21 #include "../besched.h"
22 #include "../benode_t.h"
23 #include "../beutil.h"
25 #include "mips_emitter.h"
26 #include "gen_mips_emitter.h"
27 #include "mips_nodes_attr.h"
28 #include "mips_new_nodes.h"
29 #include "mips_map_regs.h"
31 #define SNPRINTF_BUF_LEN 128
33 static const arch_env_t *arch_env = NULL;
36 /*************************************************************
38 * (_) | | / _| | | | |
39 * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __
40 * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__|
41 * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ |
42 * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_|
45 *************************************************************/
47 static const char *get_symconst_str(ir_node *node)
51 switch(get_SymConst_kind(node)) {
52 case symconst_addr_name:
53 id = get_SymConst_name(node);
54 return get_id_str(id);
55 case symconst_addr_ent:
56 id = get_entity_ident(get_SymConst_entity(node));
57 return get_id_str(id);
66 * Return a const or symconst as string.
68 static const char *node_const_to_str(ir_node *n)
71 const mips_attr_t *attr = get_mips_attr(n);
74 if(is_mips_load_r(n) || is_mips_store_r(n)) {
75 mips_attr_t *attr = get_mips_attr(n);
78 if(attr->tv != NULL) {
79 val = get_tarval_long(attr->tv);
80 snprintf(buf, sizeof(buf), "%ld", val);
84 if(attr->stack_entity != NULL) {
85 snprintf(buf, sizeof(buf), "%d", attr->stack_entity_offset);
89 symconst = get_irn_n(n, 1);
90 assert(get_irn_opcode(symconst) == iro_SymConst);
92 return get_symconst_str(symconst);
93 } else if(is_mips_la(n)) {
94 snprintf(buf, sizeof(buf), "%s", get_id_str(attr->symconst_id));
96 } else if(is_mips_lli(n)) {
97 assert(attr->tv != NULL);
98 if(get_mode_sign(get_tarval_mode(attr->tv))) {
99 long val = get_tarval_long(attr->tv);
100 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
102 unsigned long val = get_tarval_long(attr->tv);
103 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
107 } else if(is_mips_lui(n)) {
108 assert(attr->tv != NULL);
109 if(get_mode_sign(get_tarval_mode(attr->tv))) {
110 long val = get_tarval_long(attr->tv);
111 val = (val & 0xffff0000) >> 16;
112 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
114 unsigned long val = get_tarval_long(attr->tv);
115 val = (val & 0xffff0000) >> 16;
116 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
122 assert(attr->tv != NULL);
123 val = get_tarval_long(attr->tv);
124 snprintf(buf, sizeof(buf), "%ld", val);
130 * Returns node's offset as string.
132 static const char *node_offset_to_str(ir_node *n)
137 /* We always pass the ir_node which is a pointer. */
138 static int mips_get_arg_type(const lc_arg_occ_t *occ) {
139 return lc_arg_type_ptr;
144 * Returns the register at in position pos.
146 static const arch_register_t *get_in_reg(ir_node *irn, int pos)
149 const arch_register_t *reg = NULL;
151 assert(get_irn_arity(irn) > pos && "Invalid IN position");
153 /* The out register of the operator at position pos is the
154 in register we need. */
155 op = get_irn_n(irn, pos);
157 reg = arch_get_irn_register(arch_env, op);
159 assert(reg && "no in register found");
164 * Returns the register at out position pos.
166 static const arch_register_t *get_out_reg(ir_node *irn, int pos)
169 const arch_register_t *reg = NULL;
171 /* 1st case: irn is not of mode_T, so it has only */
172 /* one OUT register -> good */
173 /* 2nd case: irn is of mode_T -> collect all Projs and ask the */
174 /* Proj with the corresponding projnum for the register */
176 if (get_irn_mode(irn) != mode_T) {
177 reg = arch_get_irn_register(arch_env, irn);
179 else if (is_mips_irn(irn)) {
180 reg = get_mips_out_reg(irn, pos);
183 const ir_edge_t *edge;
185 foreach_out_edge(irn, edge) {
186 proj = get_edge_src_irn(edge);
187 assert(is_Proj(proj) && "non-Proj from mode_T node");
188 if (get_Proj_proj(proj) == pos) {
189 reg = arch_get_irn_register(arch_env, proj);
195 assert(reg && "no out register found");
200 * Returns the number of the in register at position pos.
202 int get_mips_reg_nr(ir_node *irn, int pos, int in_out)
204 const arch_register_t *reg;
207 reg = get_in_reg(irn, pos);
210 reg = get_out_reg(irn, pos);
213 return arch_register_get_index(reg);
217 * Returns the name of the in register at position pos.
219 const char *get_mips_reg_name(ir_node *irn, int pos, int in_out)
221 const arch_register_t *reg;
224 reg = get_in_reg(irn, pos);
227 reg = get_out_reg(irn, pos);
230 return arch_register_get_name(reg);
234 * Get the register name for a node.
236 static int mips_get_reg_name(lc_appendable_t *app,
237 const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
241 ir_node *X = arg->v_ptr;
242 int nr = occ->width - 1;
245 return lc_arg_append(app, occ, "(null)", 6);
247 if (occ->conversion == 'S') {
248 buf = get_mips_reg_name(X, nr, 1);
251 buf = get_mips_reg_name(X, nr, 0);
254 res = lc_appendable_chadd(app, '$');
255 res += lc_appendable_snadd(app, buf, strlen(buf));
260 * Returns the tarval or offset of an mips node as a string.
262 static int mips_const_to_str(lc_appendable_t *app,
263 const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
266 ir_node *X = arg->v_ptr;
269 return lc_arg_append(app, occ, "(null)", 6);
271 if (occ->conversion == 'C') {
272 buf = node_const_to_str(X);
275 buf = node_offset_to_str(X);
278 return lc_arg_append(app, occ, buf, strlen(buf));
282 * Determines the SSE suffix depending on the mode.
284 static int mips_get_mode_suffix(lc_appendable_t *app,
285 const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
287 ir_node *X = arg->v_ptr;
290 return lc_arg_append(app, occ, "(null)", 6);
292 if (get_mode_size_bits(get_irn_mode(X)) == 32)
293 return lc_appendable_chadd(app, 's');
295 return lc_appendable_chadd(app, 'd');
299 * Return the mips printf arg environment.
300 * We use the firm environment with some additional handlers.
302 const lc_arg_env_t *mips_get_arg_env(void)
304 static lc_arg_env_t *env = NULL;
306 static const lc_arg_handler_t mips_reg_handler = { mips_get_arg_type, mips_get_reg_name };
307 static const lc_arg_handler_t mips_const_handler = { mips_get_arg_type, mips_const_to_str };
308 static const lc_arg_handler_t mips_mode_handler = { mips_get_arg_type, mips_get_mode_suffix };
311 /* extend the firm printer */
312 env = firm_get_arg_env();
315 lc_arg_register(env, "mips:sreg", 'S', &mips_reg_handler);
316 lc_arg_register(env, "mips:dreg", 'D', &mips_reg_handler);
317 lc_arg_register(env, "mips:cnst", 'C', &mips_const_handler);
318 lc_arg_register(env, "mips:offs", 'O', &mips_const_handler);
319 lc_arg_register(env, "mips:mode", 'M', &mips_mode_handler);
326 * Add a number to a prefix. This number will not be used a second time.
328 static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
330 static unsigned long id = 0;
331 snprintf(buf, buflen, "%s%lu", prefix, ++id);
337 * Returns the target label for a control flow node.
339 static char *get_cfop_target(const ir_node *irn, char *buf)
341 ir_node *bl = get_irn_link(irn);
343 snprintf(buf, SNPRINTF_BUF_LEN, "BLOCK_%ld", get_irn_node_nr(bl));
347 /************************************************************************/
349 /************************************************************************/
351 static void mips_emit_IncSP(const ir_node *node, mips_emit_env_t *env)
354 int offset = be_get_IncSP_offset(node);
359 if(be_get_IncSP_direction(node) != be_stack_dir_expand)
362 fprintf(F, "\taddi $sp, $sp, %d\n", -offset);
365 static void mips_emit_Copy(const ir_node *node, mips_emit_env_t *env)
369 lc_efprintf(mips_get_arg_env(), F, "\tor %1D, $zero, %1S\t\t\t# copy\n", node, node);
372 static void mips_emit_Return(const ir_node* node, mips_emit_env_t *env)
375 fprintf(F, "\tj $ra\t\t\t\t# return\n");
378 static void mips_emit_nops(FILE* F, int n)
382 for(i = 0; i < n; ++i) {
383 fprintf(F, "\tnop\n");
387 static void mips_emit_Perm(const ir_node *node, mips_emit_env_t *env)
391 assert(/*get_irn_n_outs(node) == 2 &&*/ get_irn_arity(node) == 2);
393 lc_efprintf(mips_get_arg_env(), F, "\txor %1S, %1S, %2S\t\t\t# perm\n", node, node, node);
394 mips_emit_nops(F, 3);
395 lc_efprintf(mips_get_arg_env(), F, "\txor %2S, %2S, %1S\n", node, node, node);
396 mips_emit_nops(F, 3);
397 lc_efprintf(mips_get_arg_env(), F, "\txor %1S, %1S, %2S\n", node, node, node);
398 mips_emit_nops(F, 3);
401 static void mips_emit_Spill(const ir_node* node, mips_emit_env_t *env)
404 entity *ent = be_get_spill_entity(node);
406 lc_efprintf(mips_get_arg_env(), F, "\tsw %1S, %d($fp)\n", node, get_entity_offset_bytes(ent));
409 static void mips_emit_Reload(const ir_node* node, mips_emit_env_t *env)
412 entity *ent = be_get_spill_entity(node);
414 lc_efprintf(mips_get_arg_env(), F, "\tlw %1D, %d($fp)\n", node, get_entity_offset_bytes(ent));
417 /************************************************************************/
419 /************************************************************************/
421 static void mips_emit_Call(ir_node *node, mips_emit_env_t *env)
424 const arch_register_t *callee_reg;
426 // call to imediate value (label)
427 entity *callee = be_Call_get_entity(node);
429 fprintf(F, "\tjal %s\n", get_entity_name(callee));
433 // call to function pointer
434 callee_reg = get_in_reg(node, be_pos_Call_ptr);
435 assert(callee_reg != NULL);
437 fprintf(F, "\tjal %s\n", arch_register_get_name(callee_reg));
440 /************************************************************************
442 * | |_ _ _ __ ___ _ __ ___
443 * _ | | | | | '_ ` _ \| '_ \/ __|
444 * | |_| | |_| | | | | | | |_) \__ \
445 * \___/ \__,_|_| |_| |_| .__/|___/
447 ************************************************************************/
449 const char* mips_get_block_label(const ir_node* block)
452 snprintf(buf, sizeof(buf), "BLOCK_%ld", get_irn_node_nr(block));
457 static void mips_emit_Jump(ir_node *node, mips_emit_env_t *env)
460 const ir_node *block = get_irn_link(node);
462 assert(is_Block(block));
464 fprintf(F, "\tb %s\n", mips_get_block_label(block));
467 ir_node *mips_get_jump_block(const ir_node* node, int projn)
469 const ir_edge_t *oute;
470 for(oute = get_irn_out_edge_first(node); oute != NULL;
471 oute = get_irn_out_edge_next(node, oute)) {
472 ir_node *proj = get_edge_src_irn(oute);
474 assert(is_Proj(proj));
476 n = get_Proj_proj(proj);
478 return get_irn_link(proj);
484 /************************************************************************
486 * / ___|_ _(_) |_ ___| |__ | |_ _ _ __ ___ _ __ *
487 * \___ \ \ /\ / / | __/ __| '_ \ _ | | | | | '_ ` _ \| '_ \ *
488 * ___) \ V V /| | || (__| | | | |_| | |_| | | | | | | |_) | *
489 * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/ *
492 ************************************************************************/
494 /* jump table entry (target and corresponding number) */
495 typedef struct _branch_t {
500 /* jump table for switch generation */
501 typedef struct _jmp_tbl_t {
502 ir_node *defBlock; /**< default target */
503 int min_value; /**< smallest switch case */
504 int max_value; /**< largest switch case */
505 int num_branches; /**< number of jumps */
506 char *label; /**< label of the jump table */
507 branch_t *branches; /**< jump array */
511 * Compare two variables of type branch_t. Used to sort all switch cases
513 static int mips_cmp_branch_t(const void *a, const void *b) {
514 branch_t *b1 = (branch_t *)a;
515 branch_t *b2 = (branch_t *)b;
517 if (b1->value <= b2->value)
523 const char* mips_get_jumptbl_label(const ir_node* switchjmp)
526 snprintf(buf, sizeof(buf), "__JUMPTBL%ld", get_irn_node_nr(switchjmp));
532 * Emits code for a SwitchJmp (creates a jump table if
533 * possible otherwise a cmp-jmp cascade). Stolen from ia32
535 void emit_mips_jump_table(const ir_node *irn, FILE* F) {
536 int lastval, i, i2, pn;
539 const ir_edge_t *edge;
540 mips_attr_t *attr = get_mips_attr(irn);
542 /* fill the table structure */
543 tbl.label = xmalloc(SNPRINTF_BUF_LEN);
544 tbl.label = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
546 tbl.num_branches = get_irn_n_edges(irn);
547 tbl.branches = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
548 tbl.min_value = INT_MAX;
549 tbl.max_value = INT_MIN;
552 /* go over all proj's and collect them */
553 foreach_out_edge(irn, edge) {
554 proj = get_edge_src_irn(edge);
555 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
557 pn = get_Proj_proj(proj);
559 /* create branch entry */
560 tbl.branches[i].target = get_irn_link(proj);
561 tbl.branches[i].value = pn;
563 tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value;
564 tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value;
569 /* sort the branches by their number */
570 qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), mips_cmp_branch_t);
572 fprintf(F, "%s:\n", mips_get_jumptbl_label(irn));
573 lastval = tbl.min_value;
574 for(i = 0; i < tbl.num_branches; ++i) {
575 const branch_t *branch = &tbl.branches[i];
576 int value = branch->value;
578 for(i2 = lastval + 1; i2 < value; ++i2) {
579 fprintf(F, "\t.word %s\n", get_id_str(attr->symconst_id));
582 fprintf(F, "\t.word %s\n", mips_get_block_label(branch->target));
583 lastval = branch->value;
592 static void dump_jump_tables(ir_node* node, void *env)
594 FILE* F = (FILE*) env;
597 if(is_mips_SwitchJump(node)) {
598 fprintf(F, ".data\n");
599 emit_mips_jump_table(node, F);
600 fprintf(F, ".text\n");
604 /***********************************************************************************
607 * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __
608 * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
609 * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | <
610 * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\
612 ***********************************************************************************/
614 static void mips_emit_nothing(ir_mode *mode, mips_emit_env_t *env)
618 static void mips_emit_this_shouldnt_happen(ir_mode *mode, mips_emit_env_t *env)
624 * Register emitter functions for mips backend
626 void mips_register_emitters(void)
628 /* first clear the generic function pointer for all ops */
629 clear_irp_opcodes_generic_func();
631 /* register all emitter functions defined in spec */
632 mips_register_spec_emitters();
635 op_be_IncSP->ops.generic = (op_func) mips_emit_IncSP;
636 op_be_SetSP->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
637 op_be_AddSP->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
638 op_be_Call->ops.generic = (op_func) mips_emit_Call;
639 op_be_Keep->ops.generic = (op_func) mips_emit_nothing;
640 op_be_Copy->ops.generic = (op_func) mips_emit_Copy;
641 op_be_Return->ops.generic = (op_func) mips_emit_Return;
642 op_be_RegParams->ops.generic = (op_func) mips_emit_nothing;
643 op_be_Spill->ops.generic = (op_func) mips_emit_Spill;
644 op_be_Reload->ops.generic = (op_func) mips_emit_Reload;
646 op_Start->ops.generic = (op_func) mips_emit_nothing;
647 op_Proj->ops.generic = (op_func) mips_emit_nothing;
648 op_SymConst->ops.generic = (op_func) mips_emit_nothing;
649 op_Jmp->ops.generic = (op_func) mips_emit_Jump;
650 op_Cmp->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
651 op_Cond->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
654 typedef void (*emit_func) (const ir_node *, mips_emit_env_t *);
657 * Emits assembly for a single node
659 static void mips_emit_node(ir_node *irn, mips_emit_env_t* env)
661 mips_emit_env_t *emit_env = env;
662 firm_dbg_module_t *mod = emit_env->mod;
663 FILE *F = emit_env->out;
664 ir_op *op = get_irn_op(irn);
666 DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));
668 if (op->ops.generic) {
669 emit_func emit = (emit_func) op->ops.generic;
673 if(emit != (emit_func) mips_emit_nothing)
674 mips_emit_nops(F, 5);
677 ir_fprintf(F, "\t\t\t\t\t# %+F\n", irn);
682 * Walks over the nodes in a block connected by scheduling edges
683 * and emits code for each node.
685 void mips_gen_block(ir_node *block, void *env)
687 FILE *F = ((mips_emit_env_t *)env)->out;
690 if (! is_Block(block))
693 fprintf(F, "%s:\n", mips_get_block_label(block));
694 sched_foreach(block, irn) {
695 mips_emit_node(irn, env);
701 * Emits code for function start.
703 void mips_emit_start(FILE *F, ir_graph *irg)
705 const char *irg_name = get_entity_name(get_irg_entity(irg));
708 irg_walk_graph(irg, NULL, dump_jump_tables, F);
711 fprintf(F, "# Function Start of %s\n", irg_name);
712 fprintf(F, "%s:\n", irg_name);
716 * Emits code for function end
718 void mips_emit_end(FILE *F, ir_graph *irg)
720 const char *irg_name = get_entity_name(get_irg_entity(irg));
722 fprintf(F, "# End of function %s we should never get here...\n", irg_name);
723 fprintf(F, "\tjal exit\n");
727 * Sets labels for control flow nodes (jump target)
728 * TODO: Jump optimization
730 void mips_gen_labels(ir_node *block, void *env)
733 int n = get_Block_n_cfgpreds(block);
735 for (n--; n >= 0; n--) {
736 pred = get_Block_cfgpred(block, n);
737 set_irn_link(pred, block);
744 void mips_gen_routine(FILE *F, ir_graph *irg, const mips_code_gen_t *cg)
746 mips_emit_env_t emit_env;
750 emit_env.arch_env = cg->arch_env;
752 FIRM_DBG_REGISTER(emit_env.mod, "firm.be.mips.emit");
754 /* set the global arch_env (needed by print hooks) */
755 arch_env = cg->arch_env;
757 irg_block_walk_graph(irg, mips_gen_labels, NULL, &emit_env);
758 mips_emit_start(F, irg);
759 // irg_walk_blkwise_graph(irg, NULL, mips_gen_block, &emit_env);
761 dump_ir_block_graph_sched(irg, "-kaputtelist");
763 for (i = 0, n = mips_get_sched_n_blocks(cg); i < n; ++i) {
764 ir_node *block = mips_get_sched_block(cg, i);
765 mips_gen_block(block, &emit_env);
768 mips_emit_end(F, irg);