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
40 #include "../besched.h"
41 #include "../benode_t.h"
42 #include "../beutil.h"
44 #include "mips_emitter.h"
45 #include "gen_mips_emitter.h"
46 #include "mips_nodes_attr.h"
47 #include "mips_new_nodes.h"
48 #include "mips_map_regs.h"
50 #define SNPRINTF_BUF_LEN 128
52 static const arch_env_t *arch_env = NULL;
55 /*************************************************************
57 * (_) | | / _| | | | |
58 * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __
59 * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__|
60 * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ |
61 * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_|
64 *************************************************************/
66 static const char *get_symconst_str(ir_node *node)
70 switch(get_SymConst_kind(node)) {
71 case symconst_addr_name:
72 id = get_SymConst_name(node);
73 return get_id_str(id);
74 case symconst_addr_ent:
75 id = get_entity_ident(get_SymConst_entity(node));
76 return get_id_str(id);
85 * Return a const or symconst as string.
87 static const char *node_const_to_str(ir_node *n)
90 const mips_attr_t *attr = get_mips_attr(n);
93 if(is_mips_load_r(n) || is_mips_store_r(n)) {
94 mips_attr_t *attr = get_mips_attr(n);
97 if(attr->tv != NULL) {
98 val = get_tarval_long(attr->tv);
99 snprintf(buf, sizeof(buf), "%ld", val);
103 if(attr->stack_entity != NULL) {
104 snprintf(buf, sizeof(buf), "%d", attr->stack_entity_offset);
108 symconst = get_irn_n(n, 1);
109 assert(get_irn_opcode(symconst) == iro_SymConst);
111 return get_symconst_str(symconst);
112 } else if(is_mips_la(n)) {
113 snprintf(buf, sizeof(buf), "%s", get_id_str(attr->symconst_id));
115 } else if(is_mips_lli(n)) {
116 assert(attr->tv != NULL);
117 if(get_mode_sign(get_tarval_mode(attr->tv))) {
118 long val = get_tarval_long(attr->tv);
119 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
121 unsigned long val = get_tarval_long(attr->tv);
122 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
126 } else if(is_mips_lui(n)) {
127 assert(attr->tv != NULL);
128 if(get_mode_sign(get_tarval_mode(attr->tv))) {
129 long val = get_tarval_long(attr->tv);
130 val = (val & 0xffff0000) >> 16;
131 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
133 unsigned long val = get_tarval_long(attr->tv);
134 val = (val & 0xffff0000) >> 16;
135 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
141 assert(attr->tv != NULL);
142 val = get_tarval_long(attr->tv);
143 snprintf(buf, sizeof(buf), "%ld", val);
149 * Returns node's offset as string.
151 static const char *node_offset_to_str(ir_node *n)
156 /* We always pass the ir_node which is a pointer. */
157 static int mips_get_arg_type(const lc_arg_occ_t *occ) {
158 return lc_arg_type_ptr;
163 * Returns the register at in position pos.
165 static const arch_register_t *get_in_reg(ir_node *irn, int pos)
168 const arch_register_t *reg = NULL;
170 assert(get_irn_arity(irn) > pos && "Invalid IN position");
172 /* The out register of the operator at position pos is the
173 in register we need. */
174 op = get_irn_n(irn, pos);
176 reg = arch_get_irn_register(arch_env, op);
178 assert(reg && "no in register found");
183 * Returns the register at out position pos.
185 static const arch_register_t *get_out_reg(ir_node *irn, int pos)
188 const arch_register_t *reg = NULL;
190 /* 1st case: irn is not of mode_T, so it has only */
191 /* one OUT register -> good */
192 /* 2nd case: irn is of mode_T -> collect all Projs and ask the */
193 /* Proj with the corresponding projnum for the register */
195 if (get_irn_mode(irn) != mode_T) {
196 reg = arch_get_irn_register(arch_env, irn);
198 else if (is_mips_irn(irn)) {
199 reg = get_mips_out_reg(irn, pos);
202 const ir_edge_t *edge;
204 foreach_out_edge(irn, edge) {
205 proj = get_edge_src_irn(edge);
206 assert(is_Proj(proj) && "non-Proj from mode_T node");
207 if (get_Proj_proj(proj) == pos) {
208 reg = arch_get_irn_register(arch_env, proj);
214 assert(reg && "no out register found");
219 * Returns the number of the in register at position pos.
221 int get_mips_reg_nr(ir_node *irn, int pos, int in_out)
223 const arch_register_t *reg;
226 reg = get_in_reg(irn, pos);
229 reg = get_out_reg(irn, pos);
232 return arch_register_get_index(reg);
236 * Returns the name of the in register at position pos.
238 const char *get_mips_reg_name(ir_node *irn, int pos, int in_out)
240 const arch_register_t *reg;
243 reg = get_in_reg(irn, pos);
246 reg = get_out_reg(irn, pos);
249 return arch_register_get_name(reg);
253 * Get the register name for a node.
255 static int mips_get_reg_name(lc_appendable_t *app,
256 const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
260 ir_node *X = arg->v_ptr;
261 int nr = occ->width - 1;
264 return lc_arg_append(app, occ, "(null)", 6);
266 if (occ->conversion == 'S') {
267 buf = get_mips_reg_name(X, nr, 1);
270 buf = get_mips_reg_name(X, nr, 0);
273 res = lc_appendable_chadd(app, '$');
274 res += lc_appendable_snadd(app, buf, strlen(buf));
279 * Returns the tarval or offset of an mips node as a string.
281 static int mips_const_to_str(lc_appendable_t *app,
282 const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
285 ir_node *X = arg->v_ptr;
288 return lc_arg_append(app, occ, "(null)", 6);
290 if (occ->conversion == 'C') {
291 buf = node_const_to_str(X);
294 buf = node_offset_to_str(X);
297 return lc_arg_append(app, occ, buf, strlen(buf));
301 * Determines the SSE suffix depending on the mode.
303 static int mips_get_mode_suffix(lc_appendable_t *app,
304 const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
306 ir_node *X = arg->v_ptr;
309 return lc_arg_append(app, occ, "(null)", 6);
311 if (get_mode_size_bits(get_irn_mode(X)) == 32)
312 return lc_appendable_chadd(app, 's');
314 return lc_appendable_chadd(app, 'd');
318 * Return the mips printf arg environment.
319 * We use the firm environment with some additional handlers.
321 const lc_arg_env_t *mips_get_arg_env(void)
323 static lc_arg_env_t *env = NULL;
325 static const lc_arg_handler_t mips_reg_handler = { mips_get_arg_type, mips_get_reg_name };
326 static const lc_arg_handler_t mips_const_handler = { mips_get_arg_type, mips_const_to_str };
327 static const lc_arg_handler_t mips_mode_handler = { mips_get_arg_type, mips_get_mode_suffix };
330 /* extend the firm printer */
331 env = firm_get_arg_env();
334 lc_arg_register(env, "mips:sreg", 'S', &mips_reg_handler);
335 lc_arg_register(env, "mips:dreg", 'D', &mips_reg_handler);
336 lc_arg_register(env, "mips:cnst", 'C', &mips_const_handler);
337 lc_arg_register(env, "mips:offs", 'O', &mips_const_handler);
338 lc_arg_register(env, "mips:mode", 'M', &mips_mode_handler);
345 * Add a number to a prefix. This number will not be used a second time.
347 static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
349 static unsigned long id = 0;
350 snprintf(buf, buflen, "%s%lu", prefix, ++id);
354 /************************************************************************/
356 /************************************************************************/
358 static void mips_emit_IncSP(const ir_node *node, mips_emit_env_t *env)
361 int offset = be_get_IncSP_offset(node);
364 fprintf(F, "\t\t\t\t # omitted IncSP with 0\n");
368 if(offset > 0xffff || offset < -0xffff) {
369 panic("stackframe > 2^16 bytes not supported yet\n");
373 fprintf(F, "\tsubu $sp, $sp, %d\n", offset);
375 fprintf(F, "\taddu $sp, $sp, %d\n", -offset);
379 static void mips_emit_Copy(const ir_node *node, mips_emit_env_t *env)
383 lc_efprintf(mips_get_arg_env(), F, "\tmove %1D, %1S\t\t\t# copy\n", node, node);
386 static void mips_emit_Return(const ir_node* node, mips_emit_env_t *env)
389 fprintf(F, "\tj $ra\t\t\t\t# return\n");
392 static void mips_emit_nops(FILE* F, int n)
396 for(i = 0; i < n; ++i) {
397 fprintf(F, "\tnop\n");
401 static void mips_emit_Perm(const ir_node *node, mips_emit_env_t *env)
405 assert(get_irn_arity(node) == 2);
407 lc_efprintf(mips_get_arg_env(), F, "\txor %1S, %1S, %2S\t\t\t# perm\n", node, node, node);
408 mips_emit_nops(F, 3);
409 lc_efprintf(mips_get_arg_env(), F, "\txor %2S, %2S, %1S\n", node, node, node);
410 mips_emit_nops(F, 3);
411 lc_efprintf(mips_get_arg_env(), F, "\txor %1S, %1S, %2S\n", node, node, node);
412 mips_emit_nops(F, 3);
415 static void mips_emit_Spill(const ir_node* node, mips_emit_env_t *env)
418 ir_entity *ent = be_get_frame_entity(node);
420 lc_efprintf(mips_get_arg_env(), F, "\tsw %1S, %d($fp)\n", node, get_entity_offset(ent));
423 static void mips_emit_Reload(const ir_node* node, mips_emit_env_t *env)
426 ir_entity *ent = be_get_frame_entity(node);
428 lc_efprintf(mips_get_arg_env(), F, "\tlw %1D, %d($fp)\n", node, get_entity_offset(ent));
431 /************************************************************************/
433 /************************************************************************/
435 static void mips_emit_Call(ir_node *node, mips_emit_env_t *env)
438 const arch_register_t *callee_reg;
440 // call to imediate value (label)
441 ir_entity *callee = be_Call_get_entity(node);
443 fprintf(F, "\tjal %s\n", get_entity_name(callee));
447 // call to function pointer
448 callee_reg = get_in_reg(node, be_pos_Call_ptr);
449 assert(callee_reg != NULL);
451 fprintf(F, "\tjal %s\n", arch_register_get_name(callee_reg));
454 /************************************************************************
456 * | |_ _ _ __ ___ _ __ ___
457 * _ | | | | | '_ ` _ \| '_ \/ __|
458 * | |_| | |_| | | | | | | |_) \__ \
459 * \___/ \__,_|_| |_| |_| .__/|___/
461 ************************************************************************/
463 const char* mips_get_block_label(const ir_node* block)
466 snprintf(buf, sizeof(buf), "BLOCK_%ld", get_irn_node_nr(block));
471 static void mips_emit_Jump(ir_node *node, mips_emit_env_t *env)
474 const ir_node *block = get_irn_link(node);
476 assert(is_Block(block));
478 fprintf(F, "\tb %s\n", mips_get_block_label(block));
481 ir_node *mips_get_jump_block(const ir_node* node, int projn)
483 const ir_edge_t *oute;
484 for(oute = get_irn_out_edge_first(node); oute != NULL;
485 oute = get_irn_out_edge_next(node, oute)) {
486 ir_node *proj = get_edge_src_irn(oute);
488 assert(is_Proj(proj));
490 n = get_Proj_proj(proj);
492 return get_irn_link(proj);
498 /************************************************************************
500 * / ___|_ _(_) |_ ___| |__ | |_ _ _ __ ___ _ __ *
501 * \___ \ \ /\ / / | __/ __| '_ \ _ | | | | | '_ ` _ \| '_ \ *
502 * ___) \ V V /| | || (__| | | | |_| | |_| | | | | | | |_) | *
503 * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/ *
506 ************************************************************************/
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) {
528 branch_t *b1 = (branch_t *)a;
529 branch_t *b2 = (branch_t *)b;
531 if (b1->value <= b2->value)
537 const char* mips_get_jumptbl_label(const ir_node* switchjmp)
540 snprintf(buf, sizeof(buf), "__JUMPTBL%ld", get_irn_node_nr(switchjmp));
546 * Emits code for a SwitchJmp (creates a jump table if
547 * possible otherwise a cmp-jmp cascade). Stolen from ia32
549 void emit_mips_jump_table(const ir_node *irn, FILE* F) {
550 int lastval, i, i2, pn;
553 const ir_edge_t *edge;
554 mips_attr_t *attr = get_mips_attr(irn);
556 /* fill the table structure */
557 tbl.label = xmalloc(SNPRINTF_BUF_LEN);
558 tbl.label = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
560 tbl.num_branches = get_irn_n_edges(irn);
561 tbl.branches = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
562 tbl.min_value = INT_MAX;
563 tbl.max_value = INT_MIN;
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");
571 pn = get_Proj_proj(proj);
573 /* create branch entry */
574 tbl.branches[i].target = get_irn_link(proj);
575 tbl.branches[i].value = pn;
577 tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value;
578 tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value;
583 /* sort the branches by their number */
584 qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), mips_cmp_branch_t);
586 fprintf(F, "%s:\n", mips_get_jumptbl_label(irn));
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;
592 for(i2 = lastval + 1; i2 < value; ++i2) {
593 fprintf(F, "\t.word %s\n", get_id_str(attr->symconst_id));
596 fprintf(F, "\t.word %s\n", mips_get_block_label(branch->target));
597 lastval = branch->value;
606 static void dump_jump_tables(ir_node* node, void *env)
608 FILE* F = (FILE*) env;
611 if(is_mips_SwitchJump(node)) {
612 fprintf(F, ".data\n");
613 emit_mips_jump_table(node, F);
614 fprintf(F, ".text\n");
618 /***********************************************************************************
621 * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __
622 * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
623 * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | <
624 * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\
626 ***********************************************************************************/
628 static void mips_emit_nothing(ir_mode *mode, mips_emit_env_t *env)
632 static void mips_emit_this_shouldnt_happen(ir_mode *mode, mips_emit_env_t *env)
638 * Register emitter functions for mips backend
640 void mips_register_emitters(void)
642 /* first clear the generic function pointer for all ops */
643 clear_irp_opcodes_generic_func();
645 /* register all emitter functions defined in spec */
646 mips_register_spec_emitters();
649 op_be_IncSP->ops.generic = (op_func) mips_emit_IncSP;
650 op_be_SetSP->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
651 op_be_AddSP->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
652 op_be_Call->ops.generic = (op_func) mips_emit_Call;
653 op_be_Keep->ops.generic = (op_func) mips_emit_nothing;
654 op_be_Copy->ops.generic = (op_func) mips_emit_Copy;
655 op_be_Return->ops.generic = (op_func) mips_emit_Return;
656 op_be_RegParams->ops.generic = (op_func) mips_emit_nothing;
657 op_be_Spill->ops.generic = (op_func) mips_emit_Spill;
658 op_be_Reload->ops.generic = (op_func) mips_emit_Reload;
659 op_be_Perm->ops.generic = (op_func) mips_emit_Perm;
661 op_Start->ops.generic = (op_func) mips_emit_nothing;
662 op_Proj->ops.generic = (op_func) mips_emit_nothing;
663 op_SymConst->ops.generic = (op_func) mips_emit_nothing;
664 op_Jmp->ops.generic = (op_func) mips_emit_Jump;
665 op_Cmp->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
666 op_Cond->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
669 typedef void (*emit_func) (const ir_node *, mips_emit_env_t *);
672 * Emits assembly for a single node
674 static void mips_emit_node(ir_node *irn, mips_emit_env_t* env)
676 mips_emit_env_t *emit_env = env;
677 FILE *F = emit_env->out;
678 ir_op *op = get_irn_op(irn);
679 DEBUG_ONLY(firm_dbg_module_t *mod = emit_env->mod;)
681 DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));
683 if (op->ops.generic) {
684 emit_func emit = (emit_func) op->ops.generic;
688 if(emit != (emit_func) mips_emit_nothing)
689 mips_emit_nops(F, 5);
692 ir_fprintf(F, "\t\t\t\t\t# %+F\n", irn);
697 * Walks over the nodes in a block connected by scheduling edges
698 * and emits code for each node.
700 void mips_gen_block(ir_node *block, void *env)
702 FILE *F = ((mips_emit_env_t *)env)->out;
705 if (! is_Block(block))
708 fprintf(F, "%s:\n", mips_get_block_label(block));
709 sched_foreach(block, irn) {
710 mips_emit_node(irn, env);
716 * Emits code for function start.
718 void mips_emit_start(FILE *F, ir_graph *irg)
720 const char *irg_name = get_entity_name(get_irg_entity(irg));
723 irg_walk_graph(irg, NULL, dump_jump_tables, F);
726 fprintf(F, "\t.balign\t4\n");
727 fprintf(F, "\t.global\t%s\n", irg_name);
728 fprintf(F, "\t.set\tnomips16\n");
729 fprintf(F, "\t.ent\t%s\n", irg_name);
730 fprintf(F, "%s:\n", irg_name);
731 fprintf(F, "\t.frame\t$fp, 24, $ra\n");
732 fprintf(F, "\t.mask\t0xc0000000, -4\n");
733 fprintf(F, "\t.fmask\t0x00000000, 0\n");
737 * Emits code for function end
739 void mips_emit_end(FILE *F, ir_graph *irg)
741 const char *irg_name = get_entity_name(get_irg_entity(irg));
742 fprintf(F, "\t.end\t%s\n", irg_name);
746 * Sets labels for control flow nodes (jump target)
747 * TODO: Jump optimization
749 void mips_gen_labels(ir_node *block, void *env)
752 int n = get_Block_n_cfgpreds(block);
754 for (n--; n >= 0; n--) {
755 pred = get_Block_cfgpred(block, n);
756 set_irn_link(pred, block);
763 void mips_gen_routine(FILE *F, ir_graph *irg, const mips_code_gen_t *cg)
765 mips_emit_env_t emit_env;
769 emit_env.arch_env = cg->arch_env;
771 FIRM_DBG_REGISTER(emit_env.mod, "firm.be.mips.emit");
773 /* set the global arch_env (needed by print hooks) */
774 arch_env = cg->arch_env;
776 irg_block_walk_graph(irg, mips_gen_labels, NULL, &emit_env);
777 mips_emit_start(F, irg);
778 // irg_walk_blkwise_graph(irg, NULL, mips_gen_block, &emit_env);
780 dump_ir_block_graph_sched(irg, "-kaputtelist");
782 for (i = 0, n = mips_get_sched_n_blocks(cg); i < n; ++i) {
783 ir_node *block = mips_get_sched_block(cg, i);
784 mips_gen_block(block, &emit_env);
787 mips_emit_end(F, irg);