X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=sidebyside;f=ir%2Fbe%2Fsparc%2Fsparc_emitter.c;h=898605dd0044468db8c48959a9ebc1a449362795;hb=f89fe6bdc4d0f139557986320adfa37ea02d32b3;hp=5c553b4c38bc94f98e7866abdc00caf4ee20c6d1;hpb=af6ad57149a141f96818ec53d27f604a07dfc439;p=libfirm diff --git a/ir/be/sparc/sparc_emitter.c b/ir/be/sparc/sparc_emitter.c index 5c553b4c3..898605dd0 100644 --- a/ir/be/sparc/sparc_emitter.c +++ b/ir/be/sparc/sparc_emitter.c @@ -53,17 +53,8 @@ #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;) -/** - * attribute of SAVE node which follows immediatelly after the START node - * we need this to correct all offsets since SPARC expects - * some reserved stack space after the stackpointer - */ -const sparc_save_attr_t *save_attr; - /** * Returns the register at in position pos. */ @@ -118,22 +109,11 @@ static const arch_register_t *get_out_reg(const ir_node *node, int pos) return reg; } -/************************************************************* - * _ _ __ _ _ - * (_) | | / _| | | | | - * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __ - * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__| - * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ | - * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_| - * | | | | - * |_| |_| - *************************************************************/ - void sparc_emit_immediate(const ir_node *node) { - const sparc_attr_t *attr = get_sparc_attr_const(node); - assert(!(attr->immediate_value < -4096 || attr->immediate_value >= 4096)); - be_emit_irprintf("%d", attr->immediate_value); + int const val = get_sparc_attr_const(node)->immediate_value; + assert(-4096 <= val && val < 4096); + be_emit_irprintf("%d", val); } void sparc_emit_source_register(const ir_node *node, int pos) @@ -166,16 +146,28 @@ void sparc_emit_reg_or_imm(const ir_node *node, int pos) } } +static bool is_stack_pointer_relative(const ir_node *node) +{ + const arch_register_t *sp = &sparc_gp_regs[REG_SP]; + return (is_sparc_St(node) && get_in_reg(node, n_sparc_St_ptr) == sp) + || (is_sparc_Ld(node) && get_in_reg(node, n_sparc_Ld_ptr) == sp); +} + /** * emit SP offset */ void sparc_emit_offset(const ir_node *node) { const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node); - assert(attr->base.is_load_store); - - if (attr->offset > 0) - be_emit_irprintf("+%ld", attr->offset); + long offset = attr->offset; + + /* bad hack: the real stack stuff is behind the always-there spill + * space for the register window and stack */ + if (is_stack_pointer_relative(node)) + offset += SPARC_MIN_STACKSIZE; + if (offset != 0) { + be_emit_irprintf("%+ld", offset); + } } @@ -185,19 +177,19 @@ void sparc_emit_offset(const ir_node *node) void sparc_emit_load_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); - bool is_signed = mode_is_signed(mode); - - if (bits == 16) { - be_emit_string(is_signed ? "sh" : "uh"); - } else if (bits == 8) { - be_emit_string(is_signed ? "sb" : "ub"); - } else if (bits == 64) { - be_emit_string("d"); - } else { - assert(bits == 32); - } + ir_mode *mode = attr->load_store_mode; + int bits = get_mode_size_bits(mode); + bool is_signed = mode_is_signed(mode); + + if (bits == 16) { + be_emit_string(is_signed ? "sh" : "uh"); + } else if (bits == 8) { + be_emit_string(is_signed ? "sb" : "ub"); + } else if (bits == 64) { + be_emit_string("d"); + } else { + assert(bits == 32); + } } /** @@ -206,18 +198,18 @@ void sparc_emit_load_mode(const ir_node *node) void sparc_emit_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); - - if (bits == 16) { - be_emit_string("h"); - } else if (bits == 8) { - be_emit_string("b"); - } else if (bits == 64) { - be_emit_string("d"); - } else { - assert(bits == 32); - } + ir_mode *mode = attr->load_store_mode; + int bits = get_mode_size_bits(mode); + + if (bits == 16) { + be_emit_string("h"); + } else if (bits == 8) { + be_emit_string("b"); + } else if (bits == 64) { + be_emit_string("d"); + } else { + assert(bits == 32); + } } /** @@ -225,49 +217,37 @@ void sparc_emit_store_mode(const ir_node *node) */ void sparc_emit_mode_sign_prefix(const ir_node *node) { - ir_mode *mode = get_irn_mode(node); - bool is_signed = mode_is_signed(mode); - be_emit_string(is_signed ? "s" : "u"); + ir_mode *mode = get_irn_mode(node); + bool is_signed = mode_is_signed(mode); + 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); - - assert(mode_is_float(mode)); + unsigned bits = get_mode_size_bits(mode); + assert(mode_is_float(mode)); - if (bits == 32) { - be_emit_string("f"); - } else if (bits == 64) { - be_emit_string("df"); - } else { - panic("FP load mode > 64bits not implemented yet"); - } + if (bits == 32) { + be_emit_char('s'); + } else if (bits == 64) { + be_emit_char('d'); + } else if (bits == 128) { + be_emit_char('q'); + } else { + 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); } /** @@ -275,18 +255,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); } /** @@ -306,17 +276,6 @@ static void sparc_emit_entity(ir_entity *entity) be_gas_emit_entity(entity); } -/*********************************************************************************** - * _ __ _ - * (_) / _| | | - * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __ - * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ / - * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | < - * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\ - * - ***********************************************************************************/ - - /** * Emits code for stack space management */ @@ -347,7 +306,7 @@ static void emit_be_IncSP(const ir_node *irn) */ static void emit_sparc_Save(const ir_node *irn) { - save_attr = get_sparc_save_attr_const(irn); + const sparc_save_attr_t *save_attr = get_sparc_save_attr_const(irn); be_emit_cstring("\tsave "); sparc_emit_source_register(irn, 0); be_emit_irprintf(", %d, ", -save_attr->initial_stacksize); @@ -380,40 +339,6 @@ static void emit_sparc_LoImm(const ir_node *irn) be_emit_finish_line_gas(irn); } -/** - * emit code for div with the correct sign prefix - */ -static void emit_sparc_Div(const ir_node *irn) -{ - be_emit_cstring("\t"); - sparc_emit_mode_sign_prefix(irn); - be_emit_cstring("div "); - - sparc_emit_source_register(irn, 0); - be_emit_cstring(", "); - sparc_emit_reg_or_imm(irn, 1); - 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(", "); - sparc_emit_dest_register(irn, 0); - be_emit_finish_line_gas(irn); -} - /** * emits code for mulh */ @@ -455,24 +380,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); } /** @@ -513,6 +438,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 */ @@ -522,34 +452,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); } @@ -591,7 +527,7 @@ static void emit_sparc_FrameAddr(const ir_node *irn) be_emit_cstring("\tadd "); sparc_emit_source_register(irn, 0); be_emit_cstring(", "); - be_emit_irprintf("%ld", attr->fp_offset + save_attr->initial_stacksize); + be_emit_irprintf("%ld", attr->fp_offset); } else { be_emit_cstring("\tsub "); sparc_emit_source_register(irn, 0); @@ -608,22 +544,19 @@ static void emit_sparc_FrameAddr(const ir_node *irn) /** * Emits code for Branch */ -static void emit_sparc_Branch(const ir_node *irn) +static void emit_sparc_BXX(const ir_node *node) { + const sparc_jmp_cond_attr_t *attr = get_sparc_jmp_cond_attr_const(node); + int proj_num = attr->proj_num; + bool is_unsigned = attr->is_unsigned; + 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; + const char *suffix; + + foreach_out_edge(node, edge) { ir_node *proj = get_edge_src_irn(edge); long nr = get_Proj_proj(proj); if (nr == pn_Cond_true) { @@ -633,12 +566,8 @@ static void emit_sparc_Branch(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); @@ -655,20 +584,32 @@ static void emit_sparc_Branch(const ir_node *irn) 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_unsigned) { + switch (proj_num) { + case pn_Cmp_Eq: suffix = "e"; break; + case pn_Cmp_Lt: suffix = "lu"; break; + case pn_Cmp_Le: suffix = "leu"; break; + case pn_Cmp_Gt: suffix = "gu"; break; + case pn_Cmp_Ge: suffix = "geu"; break; + case pn_Cmp_Lg: suffix = "ne"; break; + default: panic("Cmp has unsupported pnc"); + } + } else { + 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; + default: panic("Cmp has unsupported pnc"); + } } /* emit the true proj */ - be_emit_irprintf("\tb%s ", suffix); + be_emit_cstring("\tb"); + be_emit_string(suffix); + be_emit_char(' '); sparc_emit_cfop_target(proj_true); be_emit_finish_line_gas(proj_true); @@ -693,7 +634,7 @@ static void emit_sparc_Branch(const ir_node *irn) /** * emit Jmp (which actually is a branch always (ba) instruction) */ -static void emit_sparc_Jmp(const ir_node *node) +static void emit_sparc_Ba(const ir_node *node) { ir_node *block, *next_block; @@ -770,50 +711,33 @@ static inline void set_emitter(ir_op *op, emit_func sparc_emit_node) */ static void sparc_register_emitters(void) { - /* first clear the generic function pointer for all ops */ clear_irp_opcodes_generic_func(); - /* register all emitter functions defined in spec */ sparc_register_spec_emitters(); /* custom emitter */ - set_emitter(op_be_IncSP, emit_be_IncSP); - set_emitter(op_be_Return, emit_be_Return); - set_emitter(op_be_Call, emit_be_Call); - set_emitter(op_sparc_FrameAddr, emit_sparc_FrameAddr); - set_emitter(op_sparc_Branch, emit_sparc_Branch); - set_emitter(op_sparc_SymConst, emit_sparc_SymConst); - set_emitter(op_sparc_Jmp, emit_sparc_Jmp); - set_emitter(op_sparc_Save, emit_sparc_Save); - - set_emitter(op_sparc_HiImm, emit_sparc_HiImm); - set_emitter(op_sparc_LoImm, emit_sparc_LoImm); - set_emitter(op_sparc_Div, emit_sparc_Div); - set_emitter(op_sparc_Mul, emit_sparc_Mul); - set_emitter(op_sparc_Mulh, emit_sparc_Mulh); - - set_emitter(op_be_Copy, emit_be_Copy); - set_emitter(op_be_CopyKeep, emit_be_Copy); - - set_emitter(op_be_Perm, emit_be_Perm); - set_emitter(op_be_MemPerm, emit_be_MemPerm); - -/* - set_emitter(op_arm_B, emit_arm_B); - set_emitter(op_arm_CopyB, emit_arm_CopyB); - set_emitter(op_arm_fpaConst, emit_arm_fpaConst); - set_emitter(op_arm_fpaDbl2GP, emit_arm_fpaDbl2GP); - set_emitter(op_arm_LdTls, emit_arm_LdTls); - set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp); - -*/ - /* no need to emit anything for the following nodes */ - set_emitter(op_Phi, emit_nothing); - set_emitter(op_be_Keep, emit_nothing); - set_emitter(op_be_Start, emit_nothing); - set_emitter(op_be_Barrier, emit_nothing); - + 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_Call, emit_sparc_Call); + 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_Mulh, emit_sparc_Mulh); + set_emitter(op_sparc_Save, emit_sparc_Save); + set_emitter(op_sparc_SymConst, emit_sparc_SymConst); + + /* no need to emit anything for the following nodes */ + set_emitter(op_be_Barrier, emit_nothing); + set_emitter(op_be_Keep, emit_nothing); + set_emitter(op_be_Start, emit_nothing); + set_emitter(op_Phi, emit_nothing); } /** @@ -940,9 +864,6 @@ void sparc_gen_routine(const sparc_code_gen_t *cg, ir_graph *irg) last_block = block; } - - //irg_walk_blkwise_graph(irg, NULL, sparc_gen_block, NULL); - // emit function epilog sparc_emit_func_epilog(irg); }