2 * Copyright (C) 1995-2007 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 SNPRINTF_BUF_LEN 128
60 * Returns the register at in position pos.
62 static const arch_register_t *get_in_reg(const arch_env_t *arch_env,
63 const ir_node *node, int pos)
66 const arch_register_t *reg = NULL;
68 assert(get_irn_arity(node) > pos && "Invalid IN position");
70 /* The out register of the operator at position pos is the
71 in register we need. */
72 op = get_irn_n(node, pos);
74 reg = arch_get_irn_register(arch_env, op);
76 assert(reg && "no in register found");
81 * Returns the register at out position pos.
83 static const arch_register_t *get_out_reg(const arch_env_t *arch_env,
84 const ir_node *node, int pos)
87 const arch_register_t *reg = NULL;
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 */
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);
99 const ir_edge_t *edge;
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);
111 assert(reg && "no out register found");
115 /*************************************************************
117 * (_) | | / _| | | | |
118 * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __
119 * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__|
120 * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ |
121 * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_|
124 *************************************************************/
126 void mips_emit_source_register(mips_emit_env_t *env, const ir_node *node,
129 const arch_register_t *reg = get_in_reg(env->arch_env, node, pos);
130 be_emit_string(env->emit, arch_register_get_name(reg));
133 void mips_emit_dest_register(mips_emit_env_t *env, const ir_node *node,
136 const arch_register_t *reg = get_out_reg(env->arch_env, node, pos);
137 be_emit_string(env->emit, arch_register_get_name(reg));
141 static const char *get_symconst_str(ir_node *node)
145 switch(get_SymConst_kind(node)) {
146 case symconst_addr_name:
147 id = get_SymConst_name(node);
148 return get_id_str(id);
149 case symconst_addr_ent:
150 id = get_entity_ident(get_SymConst_entity(node));
151 return get_id_str(id);
160 * Return a const or symconst as string.
162 static const char *node_const_to_str(ir_node *n)
165 const mips_attr_t *attr = get_mips_attr(n);
168 if(is_mips_load_r(n) || is_mips_store_r(n)) {
169 mips_attr_t *attr = get_mips_attr(n);
172 if(attr->tv != NULL) {
173 val = get_tarval_long(attr->tv);
174 snprintf(buf, sizeof(buf), "%ld", val);
178 if(attr->stack_entity != NULL) {
179 snprintf(buf, sizeof(buf), "%d", attr->stack_entity_offset);
183 symconst = get_irn_n(n, 1);
184 assert(get_irn_opcode(symconst) == iro_SymConst);
186 return get_symconst_str(symconst);
187 } else if(is_mips_la(n)) {
188 snprintf(buf, sizeof(buf), "%s", get_id_str(attr->symconst_id));
190 } else if(is_mips_lli(n)) {
191 assert(attr->tv != NULL);
192 if(get_mode_sign(get_tarval_mode(attr->tv))) {
193 long val = get_tarval_long(attr->tv);
194 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
196 unsigned long val = get_tarval_long(attr->tv);
197 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
201 } else if(is_mips_lui(n)) {
202 assert(attr->tv != NULL);
203 if(get_mode_sign(get_tarval_mode(attr->tv))) {
204 long val = get_tarval_long(attr->tv);
205 val = (val & 0xffff0000) >> 16;
206 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
208 unsigned long val = get_tarval_long(attr->tv);
209 val = (val & 0xffff0000) >> 16;
210 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
216 assert(attr->tv != NULL);
217 val = get_tarval_long(attr->tv);
218 snprintf(buf, sizeof(buf), "%ld", val);
224 void mips_emit_immediate(mips_emit_env_t *env, const ir_node *node)
226 const mips_attr_t *attr = get_mips_attr(node);
228 be_emit_char(env->emit, '$');
229 tarval *tv = attr->tv;
230 be_emit_tarval(env->emit, tv);
234 * Add a number to a prefix. This number will not be used a second time.
237 char *get_unique_label(char *buf, size_t buflen, const char *prefix)
239 static unsigned long id = 0;
240 snprintf(buf, buflen, "%s%lu", prefix, ++id);
244 /************************************************************************/
246 /************************************************************************/
249 void mips_emit_IncSP(mips_emit_env_t *env, const ir_node *node)
251 int offset = be_get_IncSP_offset(node);
254 be_emit_cstring(env->emit, "\t/* omitted IncSP with 0 */");
255 be_emit_finish_line_gas(env->emit, node);
259 if(offset > 0xffff || offset < -0xffff) {
260 panic("stackframe > 2^16 bytes not supported yet\n");
264 be_emit_irprintf(env->emit, "\tsubu $sp, $sp, %d", offset);
266 be_emit_irprintf(env->emit, "\taddu $sp, $sp, %d", -offset);
268 be_emit_finish_line_gas(env->emit, node);
271 static void mips_emit_Copy(mips_emit_env_t *env, const ir_node *node)
273 be_emit_cstring(env->emit, "\tmove ");
274 mips_emit_dest_register(env, node, 0);
275 be_emit_cstring(env->emit, ", ");
276 mips_emit_source_register(env, node, 0);
277 be_emit_finish_line_gas(env->emit, node);
280 static void mips_emit_Return(mips_emit_env_t *env, const ir_node* node)
282 be_emit_cstring(env->emit, "\tj $ra");
283 be_emit_finish_line_gas(env->emit, node);
286 static __attribute__((unused))
287 void mips_emit_nops(mips_emit_env_t *env, int n)
291 for(i = 0; i < n; ++i) {
292 be_emit_cstring(env->emit, "\tnop\n");
293 be_emit_write_line(env->emit);
297 static void mips_emit_Perm(const ir_node *node, mips_emit_env_t *env)
299 assert(get_irn_arity(node) == 2);
301 be_emit_cstring(env->emit, "\txor ");
302 mips_emit_source_register(env, node, 0);
303 be_emit_cstring(env->emit, ", ");
304 mips_emit_source_register(env, node, 0);
305 be_emit_cstring(env->emit, ", ");
306 mips_emit_source_register(env, node, 1);
307 be_emit_finish_line_gas(env->emit, node);
309 /* mips_emit_nops(env, 3); */
311 be_emit_cstring(env->emit, "\txor ");
312 mips_emit_source_register(env, node, 1);
313 be_emit_cstring(env->emit, ", ");
314 mips_emit_source_register(env, node, 1);
315 be_emit_cstring(env->emit, ", ");
316 mips_emit_source_register(env, node, 0);
317 be_emit_finish_line_gas(env->emit, node);
319 /* mips_emit_nops(env, 3); */
321 be_emit_cstring(env->emit, "\txor ");
322 mips_emit_source_register(env, node, 0);
323 be_emit_cstring(env->emit, ", ");
324 mips_emit_source_register(env, node, 0);
325 be_emit_cstring(env->emit, ", ");
326 mips_emit_source_register(env, node, 1);
327 be_emit_finish_line_gas(env->emit, node);
329 /* mips_emit_nops(env, 3); */
333 static void mips_emit_Spill(mips_emit_env_t *env, const ir_node *node)
337 ir_entity *ent = be_get_frame_entity(node);
339 lc_efprintf(mips_get_arg_env(), F, "\tsw %1S, %d($fp)\n", node, get_entity_offset(ent));
341 /* TODO lower spills and don't emit them... */
344 static void mips_emit_Reload(mips_emit_env_t *env, const ir_node *node)
348 ir_entity *ent = be_get_frame_entity(node);
350 lc_efprintf(mips_get_arg_env(), F, "\tlw %1D, %d($fp)\n", node, get_entity_offset(ent));
352 /* TODO lower reloads instead of emitting them... */
355 /************************************************************************/
357 /************************************************************************/
359 static void mips_emit_Call(mips_emit_env_t *env, const ir_node *node)
361 be_emit_cstring(env->emit, "\tjal ");
363 // call to imediate value (label)
364 ir_entity *callee = be_Call_get_entity(node);
366 be_emit_ident(env->emit, get_entity_ident(callee));
368 mips_emit_source_register(env, node, be_pos_Call_ptr);
370 be_emit_finish_line_gas(env->emit, node);
373 /************************************************************************
375 * | |_ _ _ __ ___ _ __ ___
376 * _ | | | | | '_ ` _ \| '_ \/ __|
377 * | |_| | |_| | | | | | | |_) \__ \
378 * \___/ \__,_|_| |_| |_| .__/|___/
380 ************************************************************************/
382 const char* mips_get_block_label(const ir_node* block)
385 snprintf(buf, sizeof(buf), "BLOCK_%ld", get_irn_node_nr(block));
391 void mips_emit_block_label(mips_emit_env_t *env, const ir_node *block)
393 be_emit_irprintf(env->emit, "BLOCK_%ld", get_irn_node_nr(block));
396 static void mips_emit_Jump(mips_emit_env_t *env, const ir_node *node)
398 const ir_node *block = get_irn_link(node);
399 assert(is_Block(block));
401 be_emit_cstring(env->emit, "\tb ");
402 mips_emit_block_label(env, block);
403 be_emit_finish_line_gas(env->emit, node);
406 ir_node *mips_get_jump_block(const ir_node* node, int projn)
408 const ir_edge_t *oute;
409 for(oute = get_irn_out_edge_first(node); oute != NULL;
410 oute = get_irn_out_edge_next(node, oute)) {
411 ir_node *proj = get_edge_src_irn(oute);
413 assert(is_Proj(proj));
415 n = get_Proj_proj(proj);
417 return get_irn_link(proj);
423 void mips_emit_jump_target_proj(mips_emit_env_t *env, const ir_node *node, int projn)
425 ir_node *jumpblock = mips_get_jump_block(node, projn);
426 assert(jumpblock != NULL);
428 mips_emit_block_label(env, jumpblock);
431 void mips_emit_jump_target(mips_emit_env_t *env, const ir_node *node)
433 ir_node *jumpblock = get_irn_link(node);
434 assert(jumpblock != NULL);
436 mips_emit_block_label(env, jumpblock);
439 /************************************************************************
441 * / ___|_ _(_) |_ ___| |__ | |_ _ _ __ ___ _ __ *
442 * \___ \ \ /\ / / | __/ __| '_ \ _ | | | | | '_ ` _ \| '_ \ *
443 * ___) \ V V /| | || (__| | | | |_| | |_| | | | | | | |_) | *
444 * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/ *
447 ************************************************************************/
449 /* jump table entry (target and corresponding number) */
450 typedef struct _branch_t {
455 /* jump table for switch generation */
456 typedef struct _jmp_tbl_t {
457 ir_node *defBlock; /**< default target */
458 int min_value; /**< smallest switch case */
459 int max_value; /**< largest switch case */
460 int num_branches; /**< number of jumps */
461 char *label; /**< label of the jump table */
462 branch_t *branches; /**< jump array */
466 * Compare two variables of type branch_t. Used to sort all switch cases
468 static int mips_cmp_branch_t(const void *a, const void *b) {
469 branch_t *b1 = (branch_t *)a;
470 branch_t *b2 = (branch_t *)b;
472 if (b1->value <= b2->value)
478 const char* mips_get_jumptbl_label(const ir_node* switchjmp)
481 snprintf(buf, sizeof(buf), "__JUMPTBL%ld", get_irn_node_nr(switchjmp));
487 * Emits code for a SwitchJmp (creates a jump table if
488 * possible otherwise a cmp-jmp cascade). Stolen from ia32
490 void emit_mips_jump_table(mips_emit_env_t *env, const ir_node *irn) {
491 int lastval, i, i2, pn;
494 const ir_edge_t *edge;
495 mips_attr_t *attr = get_mips_attr(irn);
497 /* fill the table structure */
498 tbl.label = xmalloc(SNPRINTF_BUF_LEN);
499 tbl.label = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
501 tbl.num_branches = get_irn_n_edges(irn);
502 tbl.branches = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
503 tbl.min_value = INT_MAX;
504 tbl.max_value = INT_MIN;
507 /* go over all proj's and collect them */
508 foreach_out_edge(irn, edge) {
509 proj = get_edge_src_irn(edge);
510 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
512 pn = get_Proj_proj(proj);
514 /* create branch entry */
515 tbl.branches[i].target = get_irn_link(proj);
516 tbl.branches[i].value = pn;
518 tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value;
519 tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value;
524 /* sort the branches by their number */
525 qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), mips_cmp_branch_t);
527 be_emit_string(env->emit, mips_get_jumptbl_label(irn));
528 be_emit_cstring(env->emit, ":\n");
529 be_emit_write_line(env->emit);
530 lastval = tbl.min_value;
531 for(i = 0; i < tbl.num_branches; ++i) {
532 const branch_t *branch = &tbl.branches[i];
533 int value = branch->value;
535 for(i2 = lastval + 1; i2 < value; ++i2) {
536 be_emit_cstring(env->emit, "\t.word ");
537 be_emit_ident(env->emit, attr->symconst_id);
538 be_emit_char(env->emit, '\n');
539 be_emit_write_line(env->emit);
542 be_emit_cstring(env->emit, "\t.word ");
543 mips_emit_block_label(env, branch->target);
544 be_emit_char(env->emit, '\n');
545 be_emit_write_line(env->emit);
547 lastval = branch->value;
557 void dump_jump_tables(ir_node* node, void *data)
559 mips_emit_env_t *env = data;
562 if(is_mips_SwitchJump(node)) {
563 be_emit_cstring(env->emit, ".data\n");
564 be_emit_write_line(env->emit);
566 emit_mips_jump_table(env, node);
568 be_emit_cstring(env->emit, ".text\n");
569 be_emit_write_line(env->emit);
573 /***********************************************************************************
576 * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __
577 * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
578 * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | <
579 * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\
581 ***********************************************************************************/
583 static void mips_emit_nothing(ir_mode *mode, mips_emit_env_t *env)
587 static void mips_emit_this_shouldnt_happen(ir_mode *mode, mips_emit_env_t *env)
593 * Register emitter functions for mips backend
595 void mips_register_emitters(void)
597 /* first clear the generic function pointer for all ops */
598 clear_irp_opcodes_generic_func();
600 /* register all emitter functions defined in spec */
601 mips_register_spec_emitters();
604 op_be_IncSP->ops.generic = (op_func) mips_emit_IncSP;
605 op_be_SetSP->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
606 op_be_AddSP->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
607 op_be_Call->ops.generic = (op_func) mips_emit_Call;
608 op_be_Keep->ops.generic = (op_func) mips_emit_nothing;
609 op_be_Copy->ops.generic = (op_func) mips_emit_Copy;
610 op_be_Return->ops.generic = (op_func) mips_emit_Return;
611 op_be_RegParams->ops.generic = (op_func) mips_emit_nothing;
612 op_be_Spill->ops.generic = (op_func) mips_emit_Spill;
613 op_be_Reload->ops.generic = (op_func) mips_emit_Reload;
614 op_be_Perm->ops.generic = (op_func) mips_emit_Perm;
616 op_Start->ops.generic = (op_func) mips_emit_nothing;
617 op_Proj->ops.generic = (op_func) mips_emit_nothing;
618 op_SymConst->ops.generic = (op_func) mips_emit_nothing;
619 op_Jmp->ops.generic = (op_func) mips_emit_Jump;
620 op_Cmp->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
621 op_Cond->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
624 typedef void (*emit_func) (mips_emit_env_t *, const ir_node *);
627 * Emits assembly for a single node
629 static void mips_emit_node(mips_emit_env_t *env, const ir_node *node)
631 ir_op *op = get_irn_op(node);
633 if (op->ops.generic) {
634 emit_func emit = (emit_func) op->ops.generic;
637 be_emit_cstring(env->emit, "\t/* TODO */");
638 be_emit_finish_line_gas(env->emit, node);
643 * Walks over the nodes in a block connected by scheduling edges
644 * and emits code for each node.
646 void mips_gen_block(mips_emit_env_t *env, ir_node *block)
650 if (! is_Block(block))
653 mips_emit_block_label(env, block);
654 be_emit_cstring(env->emit, ":\n");
655 be_emit_write_line(env->emit);
657 sched_foreach(block, node) {
658 mips_emit_node(env, node);
661 be_emit_char(env->emit, '\n');
662 be_emit_write_line(env->emit);
666 * Emits code for function start.
668 void mips_emit_func_prolog(mips_emit_env_t *env, ir_graph *irg)
670 ident *irg_ident = get_entity_ident(get_irg_entity(irg));
671 be_emit_env_t *eenv = env->emit;
674 irg_walk_graph(irg, NULL, dump_jump_tables, env);
676 be_emit_write_line(eenv);
677 be_gas_emit_switch_section(eenv, GAS_SECTION_TEXT);
679 be_emit_cstring(eenv, "\t.balign\t4\n");
681 be_emit_cstring(eenv, "\t.global\t")
682 be_emit_ident(eenv, irg_ident);
683 be_emit_char(eenv, '\n');
685 be_emit_cstring(eenv, "\t.set\tnomips16\n");
687 be_emit_cstring(eenv, "\t.ent\t");
688 be_emit_ident(eenv, irg_ident);
689 be_emit_char(eenv, '\n');
691 be_emit_ident(eenv, irg_ident);
692 be_emit_cstring(eenv, ":\n");
694 be_emit_cstring(eenv, "\t.frame\t$fp, 24, $ra\n");
695 be_emit_cstring(eenv, "\t.mask\t0xc0000000, -4\n");
696 be_emit_cstring(eenv, "\t.fmask\t0x00000000, 0\n");
698 be_emit_write_line(eenv);
702 * Emits code for function end
704 void mips_emit_func_epilog(mips_emit_env_t *env, ir_graph *irg)
706 ident *irg_ident = get_entity_ident(get_irg_entity(irg));
708 be_emit_cstring(env->emit, "\t.end\t");
709 be_emit_ident(env->emit, irg_ident);
710 be_emit_char(env->emit, '\n');
711 be_emit_write_line(env->emit);
715 * Sets labels for control flow nodes (jump target)
717 void mips_gen_labels(ir_node *block, void *env)
720 int n = get_Block_n_cfgpreds(block);
722 for (n--; n >= 0; n--) {
723 pred = get_Block_cfgpred(block, n);
724 set_irn_link(pred, block);
731 void mips_gen_routine(mips_code_gen_t *cg, ir_graph *irg)
736 env.isa = (mips_isa_t*) cg->arch_env->isa;
737 env.emit = &env.isa->emit;
738 env.arch_env = cg->arch_env;
741 mips_register_emitters();
743 irg_block_walk_graph(irg, mips_gen_labels, NULL, &env);
745 mips_emit_func_prolog(&env, irg);
747 dump_ir_block_graph_sched(irg, "-kaputtelist");
749 for (i = 0, n = mips_get_sched_n_blocks(cg); i < n; ++i) {
750 ir_node *block = mips_get_sched_block(cg, i);
751 mips_gen_block(&env, block);
754 mips_emit_func_epilog(&env, irg);
757 void mips_init_emitter(void)
759 FIRM_DBG_REGISTER(dbg, "firm.be.mips.emitter");