X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fsparc%2Fsparc_emitter.c;h=a5b25e932c0de5d3448c89ff66dbdcfee33497ed;hb=30e0e01a7abee881b1684ee93750e886cf2d6d66;hp=42f948ca1785b42de5f0340d2f95807bb6455822;hpb=c563dd6506ad94733626b2c83fb7b017f90f37f7;p=libfirm diff --git a/ir/be/sparc/sparc_emitter.c b/ir/be/sparc/sparc_emitter.c index 42f948ca1..a5b25e932 100644 --- a/ir/be/sparc/sparc_emitter.c +++ b/ir/be/sparc/sparc_emitter.c @@ -53,8 +53,6 @@ #include "sparc_new_nodes.h" #include "gen_sparc_regalloc_if.h" - -#define SNPRINTF_BUF_LEN 128 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) /** @@ -172,6 +170,21 @@ void sparc_emit_offset(const ir_node *node) } } +void sparc_emit_float_load_store_mode(const ir_node *node) +{ + const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node); + ir_mode *mode = attr->load_store_mode; + int bits = get_mode_size_bits(mode); + + assert(mode_is_float(mode)); + + switch (bits) { + case 32: return; + case 64: be_emit_char('d'); return; + case 128: be_emit_char('q'); return; + } + panic("invalid flaot load/store mode %+F", mode); +} /** * Emit load mode char @@ -188,7 +201,7 @@ void sparc_emit_load_mode(const ir_node *node) } else if (bits == 8) { be_emit_string(is_signed ? "sb" : "ub"); } else if (bits == 64) { - be_emit_string("d"); + be_emit_char('d'); } else { assert(bits == 32); } @@ -208,7 +221,7 @@ void sparc_emit_store_mode(const ir_node *node) } else if (bits == 8) { be_emit_string("b"); } else if (bits == 64) { - be_emit_string("d"); + be_emit_char('d'); } else { assert(bits == 32); } @@ -224,44 +237,32 @@ void sparc_emit_mode_sign_prefix(const ir_node *node) be_emit_string(is_signed ? "s" : "u"); } -/** - * emit FP load mode char - */ -void sparc_emit_fp_load_mode(const ir_node *node) +static void emit_fp_suffix(const ir_mode *mode) { - const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node); - ir_mode *mode = attr->load_store_mode; - int bits = get_mode_size_bits(mode); - + unsigned bits = get_mode_size_bits(mode); assert(mode_is_float(mode)); if (bits == 32) { - be_emit_string("f"); + be_emit_char('s'); } else if (bits == 64) { - be_emit_string("df"); + be_emit_char('d'); + } else if (bits == 128) { + be_emit_char('q'); } else { - panic("FP load mode > 64bits not implemented yet"); + panic("invalid FP mode"); } } -/** - * emit FP store mode char - */ -void sparc_emit_fp_store_mode(const ir_node *node) +void sparc_emit_fp_conv_source(const ir_node *node) { - const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node); - ir_mode *mode = attr->load_store_mode; - int bits = get_mode_size_bits(mode); - - assert(mode_is_float(mode)); + const sparc_fp_conv_attr_t *attr = get_sparc_fp_conv_attr_const(node); + emit_fp_suffix(attr->src_mode); +} - if (bits == 32) { - be_emit_string("f"); - } else if (bits == 64) { - be_emit_string("df"); - } else { - panic("FP store mode > 64bits not implemented yet"); - } +void sparc_emit_fp_conv_destination(const ir_node *node) +{ + const sparc_fp_conv_attr_t *attr = get_sparc_fp_conv_attr_const(node); + emit_fp_suffix(attr->dest_mode); } /** @@ -269,18 +270,8 @@ void sparc_emit_fp_store_mode(const ir_node *node) */ void sparc_emit_fp_mode_suffix(const ir_node *node) { - ir_mode *mode = get_irn_mode(node); - int bits = get_mode_size_bits(mode); - - assert(mode_is_float(mode)); - - if (bits == 32) { - be_emit_string("s"); - } else if (bits == 64) { - be_emit_string("d"); - } else { - panic("FP mode > 64bits not implemented yet"); - } + const sparc_fp_attr_t *attr = get_sparc_fp_attr_const(node); + emit_fp_suffix(attr->fp_mode); } /** @@ -364,13 +355,13 @@ static void emit_sparc_LoImm(const ir_node *irn) } /** - * emit code for div with the correct sign prefix + * emits code for mulh */ -static void emit_sparc_Div(const ir_node *irn) +static void emit_sparc_Mulh(const ir_node *irn) { be_emit_cstring("\t"); sparc_emit_mode_sign_prefix(irn); - be_emit_cstring("div "); + be_emit_cstring("mul "); sparc_emit_source_register(irn, 0); be_emit_cstring(", "); @@ -378,49 +369,51 @@ static void emit_sparc_Div(const ir_node *irn) be_emit_cstring(", "); sparc_emit_dest_register(irn, 0); be_emit_finish_line_gas(irn); -} - -/** - * emit code for mul with the correct sign prefix - */ -static void emit_sparc_Mul(const ir_node *irn) -{ - be_emit_cstring("\t"); - sparc_emit_mode_sign_prefix(irn); - be_emit_cstring("mul "); - sparc_emit_source_register(irn, 0); - be_emit_cstring(", "); - sparc_emit_reg_or_imm(irn, 1); - be_emit_cstring(", "); + // our result is in the y register now + // we just copy it to the assigned target reg + be_emit_cstring("\tmov %y, "); sparc_emit_dest_register(irn, 0); be_emit_finish_line_gas(irn); } -/** - * emits code for mulh - */ -static void emit_sparc_Mulh(const ir_node *irn) +static void emit_sparc_Div(const ir_node *node, bool is_signed) { - be_emit_cstring("\t"); - sparc_emit_mode_sign_prefix(irn); - be_emit_cstring("mul "); + /* can we get the delay count of the wr instruction somewhere? */ + unsigned wry_delay_count = 3; + unsigned i; - sparc_emit_source_register(irn, 0); + be_emit_cstring("\twr "); + sparc_emit_source_register(node, 0); + be_emit_cstring(", 0, %y"); + be_emit_finish_line_gas(node); + + for (i = 0; i < wry_delay_count; ++i) { + be_emit_cstring("\tnop"); + be_emit_finish_line_gas(node); + } + + be_emit_irprintf("\t%s ", is_signed ? "sdiv" : "udiv"); + sparc_emit_source_register(node, 1); be_emit_cstring(", "); - sparc_emit_reg_or_imm(irn, 1); + sparc_emit_source_register(node, 2); be_emit_cstring(", "); - sparc_emit_dest_register(irn, 0); - be_emit_finish_line_gas(irn); + sparc_emit_dest_register(node, 0); + be_emit_finish_line_gas(node); +} - // our result is in the y register now - // we just copy it to the assigned target reg - be_emit_cstring("\tmov "); - be_emit_char('%'); - be_emit_string(arch_register_get_name(&sparc_flags_regs[REG_Y])); - be_emit_cstring(", "); - sparc_emit_dest_register(irn, 0); - be_emit_finish_line_gas(irn); +static void emit_sparc_SDiv(const ir_node *node) +{ + (void) node; + /* aehm we would need an aditional register for an sra instruction to + * compute the upper bits... Just panic for now */ + //emit_sparc_Div(node, true); + panic("signed div is wrong"); +} + +static void emit_sparc_UDiv(const ir_node *node) +{ + emit_sparc_Div(node, false); } /** @@ -438,24 +431,24 @@ static void emit_be_Return(const ir_node *irn) /** * Emits code for Call node */ -static void emit_be_Call(const ir_node *irn) +static void emit_sparc_Call(const ir_node *node) { - ir_entity *entity = be_Call_get_entity(irn); + const sparc_attr_t *attr = get_sparc_attr_const(node); + ir_entity *entity = attr->immediate_value_entity; + be_emit_cstring("\tcall "); if (entity != NULL) { - be_emit_cstring("\tcall "); sparc_emit_entity(entity); be_emit_cstring(", 0"); - be_emit_finish_line_gas(irn); - be_emit_cstring("\tnop"); - be_emit_pad_comment(); - be_emit_cstring("/* TODO: use delay slot */\n"); } else { - be_emit_cstring("\tnop\n"); - be_emit_pad_comment(); - be_emit_cstring("/* TODO: Entity == NULL */\n"); - be_emit_finish_line_gas(irn); + int last = get_irn_arity(node); + sparc_emit_source_register(node, last-1); } + be_emit_finish_line_gas(node); + + /* fill delay slot */ + be_emit_cstring("\tnop"); + be_emit_finish_line_gas(node); } /** @@ -496,6 +489,11 @@ static void emit_be_MemPerm(const ir_node *node) int i; int memperm_arity; int sp_change = 0; + ir_graph *irg = get_irn_irg(node); + be_stack_layout_t *layout = be_get_irg_stack_layout(irg); + + /* this implementation only works with frame pointers currently */ + assert(layout->sp_relative == false); /* TODO: this implementation is slower than necessary. The longterm goal is however to avoid the memperm node completely */ @@ -505,34 +503,40 @@ static void emit_be_MemPerm(const ir_node *node) if (memperm_arity > 8) panic("memperm with more than 8 inputs not supported yet"); + be_emit_irprintf("\tsub %%sp, %d, %%sp", memperm_arity*4); + be_emit_finish_line_gas(node); + for (i = 0; i < memperm_arity; ++i) { - int offset; ir_entity *entity = be_get_MemPerm_in_entity(node, i); + int offset = be_get_stack_entity_offset(layout, entity, 0); /* spill register */ - sp_change += 4; - be_emit_irprintf("\tst %%l%d, [%%sp-%d]", i, sp_change); + be_emit_irprintf("\tst %%l%d, [%%sp%+d]", i, sp_change + SPARC_MIN_STACKSIZE); be_emit_finish_line_gas(node); /* load from entity */ - offset = get_entity_offset(entity) + sp_change; - be_emit_irprintf("\tld [%%sp+%d], %%l%d", offset, i); + be_emit_irprintf("\tld [%%fp%+d], %%l%d", offset, i); be_emit_finish_line_gas(node); + sp_change += 4; } for (i = memperm_arity-1; i >= 0; --i) { - int offset; ir_entity *entity = be_get_MemPerm_out_entity(node, i); + int offset = be_get_stack_entity_offset(layout, entity, 0); + + sp_change -= 4; /* store to new entity */ - offset = get_entity_offset(entity) + sp_change; - be_emit_irprintf("\tst %%l%d, [%%sp+%d]", i, offset); + be_emit_irprintf("\tst %%l%d, [%%fp%+d]", i, offset); be_emit_finish_line_gas(node); /* restore register */ - be_emit_irprintf("\tld [%%sp-%d], %%l%d", sp_change, i); - sp_change -= 4; + be_emit_irprintf("\tld [%%sp%+d], %%l%d", sp_change + SPARC_MIN_STACKSIZE, i); be_emit_finish_line_gas(node); } + + be_emit_irprintf("\tadd %%sp, %d, %%sp", memperm_arity*4); + be_emit_finish_line_gas(node); + assert(sp_change == 0); } @@ -587,26 +591,77 @@ static void emit_sparc_FrameAddr(const ir_node *irn) be_emit_finish_line_gas(irn); } +static const char *get_icc_unsigned(pn_Cmp pnc) +{ + switch (pnc) { + case pn_Cmp_False: return "bn"; + case pn_Cmp_Eq: return "be"; + case pn_Cmp_Lt: return "blu"; + case pn_Cmp_Le: return "bleu"; + case pn_Cmp_Gt: return "bgu"; + case pn_Cmp_Ge: return "bgeu"; + case pn_Cmp_Lg: return "bne"; + case pn_Cmp_Leg: return "ba"; + default: panic("Cmp has unsupported pnc"); + } +} + +static const char *get_icc_signed(pn_Cmp pnc) +{ + switch (pnc) { + case pn_Cmp_False: return "bn"; + case pn_Cmp_Eq: return "be"; + case pn_Cmp_Lt: return "bl"; + case pn_Cmp_Le: return "ble"; + case pn_Cmp_Gt: return "bg"; + case pn_Cmp_Ge: return "bge"; + case pn_Cmp_Lg: return "bne"; + case pn_Cmp_Leg: return "ba"; + default: panic("Cmp has unsupported pnc"); + } +} + +static const char *get_fcc(pn_Cmp pnc) +{ + switch (pnc) { + case pn_Cmp_False: return "fbn"; + case pn_Cmp_Eq: return "fbe"; + case pn_Cmp_Lt: return "fbl"; + case pn_Cmp_Le: return "fble"; + case pn_Cmp_Gt: return "fbg"; + case pn_Cmp_Ge: return "fbge"; + case pn_Cmp_Lg: return "fblg"; + case pn_Cmp_Leg: return "fbo"; + case pn_Cmp_Uo: return "fbu"; + case pn_Cmp_Ue: return "fbue"; + case pn_Cmp_Ul: return "fbul"; + case pn_Cmp_Ule: return "fbule"; + case pn_Cmp_Ug: return "fbug"; + case pn_Cmp_Uge: return "fbuge"; + case pn_Cmp_Ne: return "fbne"; + case pn_Cmp_True: return "fba"; + case pn_Cmp_max: + break; + } + panic("invalid pnc"); +} + +typedef const char* (*get_cc_func)(pn_Cmp pnc); /** * Emits code for Branch */ -static void emit_sparc_BXX(const ir_node *irn) +static void emit_sparc_branch(const ir_node *node, get_cc_func get_cc) { + const sparc_jmp_cond_attr_t *attr = get_sparc_jmp_cond_attr_const(node); + pn_Cmp pnc = attr->pnc; + const ir_node *proj_true = NULL; + const ir_node *proj_false = NULL; const ir_edge_t *edge; - const ir_node *proj_true = NULL; - const ir_node *proj_false = NULL; - const ir_node *block; - const ir_node *next_block; - ir_node *op1 = get_irn_n(irn, 0); - const char *suffix; - int proj_num = get_sparc_jmp_cond_proj_num(irn); - const sparc_cmp_attr_t *cmp_attr = get_irn_generic_attr_const(op1); - // bool is_signed = !cmp_attr->is_unsigned; - - assert(is_sparc_Cmp(op1) || is_sparc_Tst(op1)); - - foreach_out_edge(irn, edge) { + const ir_node *block; + const ir_node *next_block; + + foreach_out_edge(node, edge) { ir_node *proj = get_edge_src_irn(edge); long nr = get_Proj_proj(proj); if (nr == pn_Cond_true) { @@ -616,42 +671,29 @@ static void emit_sparc_BXX(const ir_node *irn) } } - if (cmp_attr->ins_permuted) { - proj_num = get_mirrored_pnc(proj_num); - } - /* for now, the code works for scheduled and non-schedules blocks */ - block = get_nodes_block(irn); + block = get_nodes_block(node); /* we have a block schedule */ next_block = get_irn_link(block); - assert(proj_num != pn_Cmp_False); - assert(proj_num != pn_Cmp_True); - if (get_irn_link(proj_true) == next_block) { /* exchange both proj's so the second one can be omitted */ const ir_node *t = proj_true; proj_true = proj_false; proj_false = t; - proj_num = get_negated_pnc(proj_num, mode_Iu); - } - - - switch (proj_num) { - case pn_Cmp_Eq: suffix = "e"; break; - case pn_Cmp_Lt: suffix = "l"; break; - case pn_Cmp_Le: suffix = "le"; break; - case pn_Cmp_Gt: suffix = "g"; break; - case pn_Cmp_Ge: suffix = "ge"; break; - case pn_Cmp_Lg: suffix = "ne"; break; - case pn_Cmp_Leg: suffix = "a"; break; - default: panic("Cmp has unsupported pnc"); + if (is_sparc_fbfcc(node)) { + pnc = get_negated_pnc(pnc, mode_F); + } else { + pnc = get_negated_pnc(pnc, mode_Iu); + } } /* emit the true proj */ - be_emit_irprintf("\tb%s ", suffix); + be_emit_cstring("\t"); + be_emit_string(get_cc(pnc)); + be_emit_char(' '); sparc_emit_cfop_target(proj_true); be_emit_finish_line_gas(proj_true); @@ -660,7 +702,7 @@ static void emit_sparc_BXX(const ir_node *irn) be_emit_cstring("/* TODO: use delay slot */\n"); if (get_irn_link(proj_false) == next_block) { - be_emit_cstring("\t/* false-fallthrough to "); + be_emit_cstring("\t/* fallthrough to "); sparc_emit_cfop_target(proj_false); be_emit_cstring(" */"); be_emit_finish_line_gas(proj_false); @@ -673,6 +715,18 @@ static void emit_sparc_BXX(const ir_node *irn) } } +static void emit_sparc_Bicc(const ir_node *node) +{ + const sparc_jmp_cond_attr_t *attr = get_sparc_jmp_cond_attr_const(node); + bool is_unsigned = attr->is_unsigned; + emit_sparc_branch(node, is_unsigned ? get_icc_unsigned : get_icc_signed); +} + +static void emit_sparc_fbfcc(const ir_node *node) +{ + emit_sparc_branch(node, get_fcc); +} + /** * emit Jmp (which actually is a branch always (ba) instruction) */ @@ -698,28 +752,55 @@ static void emit_sparc_Ba(const ir_node *node) be_emit_finish_line_gas(node); } +static void emit_fmov(const ir_node *node, const arch_register_t *src_reg, + const arch_register_t *dst_reg) +{ + be_emit_cstring("\tfmov "); + be_emit_string(arch_register_get_name(src_reg)); + be_emit_cstring(", "); + be_emit_string(arch_register_get_name(dst_reg)); + be_emit_finish_line_gas(node); +} + +static const arch_register_t *get_next_fp_reg(const arch_register_t *reg) +{ + unsigned index = reg->index; + assert(reg == &sparc_fp_regs[index]); + index++; + assert(index < N_sparc_fp_REGS); + return &sparc_fp_regs[index]; +} + /** * emit copy node */ -static void emit_be_Copy(const ir_node *irn) +static void emit_be_Copy(const ir_node *node) { - ir_mode *mode = get_irn_mode(irn); + ir_mode *mode = get_irn_mode(node); + const arch_register_t *src_reg = get_in_reg(node, 0); + const arch_register_t *dst_reg = get_out_reg(node, 0); - if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) { - /* omitted Copy */ + if (src_reg == dst_reg) return; - } if (mode_is_float(mode)) { - panic("emit_be_Copy: move not supported for FP"); + unsigned bits = get_mode_size_bits(mode); + int n = bits > 32 ? bits > 64 ? 3 : 1 : 0; + int i; + emit_fmov(node, src_reg, dst_reg); + for (i = 0; i < n; ++i) { + src_reg = get_next_fp_reg(src_reg); + dst_reg = get_next_fp_reg(dst_reg); + emit_fmov(node, src_reg, dst_reg); + } } else if (mode_is_data(mode)) { be_emit_cstring("\tmov "); - sparc_emit_source_register(irn, 0); + sparc_emit_source_register(node, 0); be_emit_cstring(", "); - sparc_emit_dest_register(irn, 0); - be_emit_finish_line_gas(irn); + sparc_emit_dest_register(node, 0); + be_emit_finish_line_gas(node); } else { - panic("emit_be_Copy: move not supported for this mode"); + panic("emit_be_Copy: invalid mode"); } } @@ -732,8 +813,6 @@ static void emit_nothing(const ir_node *irn) (void) irn; } - - /** * type of emitter function */ @@ -759,23 +838,24 @@ static void sparc_register_emitters(void) sparc_register_spec_emitters(); /* custom emitter */ - set_emitter(op_be_Call, emit_be_Call); set_emitter(op_be_Copy, emit_be_Copy); set_emitter(op_be_CopyKeep, emit_be_Copy); set_emitter(op_be_IncSP, emit_be_IncSP); set_emitter(op_be_MemPerm, emit_be_MemPerm); set_emitter(op_be_Perm, emit_be_Perm); set_emitter(op_be_Return, emit_be_Return); - set_emitter(op_sparc_BXX, emit_sparc_BXX); - set_emitter(op_sparc_Div, emit_sparc_Div); + set_emitter(op_sparc_Ba, emit_sparc_Ba); + set_emitter(op_sparc_Bicc, emit_sparc_Bicc); + set_emitter(op_sparc_Call, emit_sparc_Call); + set_emitter(op_sparc_fbfcc, emit_sparc_fbfcc); set_emitter(op_sparc_FrameAddr, emit_sparc_FrameAddr); set_emitter(op_sparc_HiImm, emit_sparc_HiImm); - set_emitter(op_sparc_Ba, emit_sparc_Ba); set_emitter(op_sparc_LoImm, emit_sparc_LoImm); - set_emitter(op_sparc_Mul, emit_sparc_Mul); set_emitter(op_sparc_Mulh, emit_sparc_Mulh); set_emitter(op_sparc_Save, emit_sparc_Save); + set_emitter(op_sparc_SDiv, emit_sparc_SDiv); set_emitter(op_sparc_SymConst, emit_sparc_SymConst); + set_emitter(op_sparc_UDiv, emit_sparc_UDiv); /* no need to emit anything for the following nodes */ set_emitter(op_be_Barrier, emit_nothing); @@ -789,15 +869,15 @@ static void sparc_register_emitters(void) */ static void sparc_emit_node(const ir_node *node) { - ir_op *op = get_irn_op(node); + ir_op *op = get_irn_op(node); if (op->ops.generic) { emit_func func = (emit_func) op->ops.generic; be_dbg_set_dbg_info(get_irn_dbg_info(node)); (*func) (node); } else { - panic("Error: No emit handler for node %+F (graph %+F)\n", - node, current_ir_graph); + panic("No emit handler for node %+F (graph %+F)\n", node, + current_ir_graph); } }