X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fsparc%2Fsparc_emitter.c;h=5c553b4c38bc94f98e7866abdc00caf4ee20c6d1;hb=7cf3689476440ec8774dc310354c0948a6f5bfae;hp=53585b1760f187367e92d66f61a161189e71c80e;hpb=7c36344d22a7c306a4e216f135c974bdb9f6b943;p=libfirm diff --git a/ir/be/sparc/sparc_emitter.c b/ir/be/sparc/sparc_emitter.c index 53585b176..5c553b4c3 100644 --- a/ir/be/sparc/sparc_emitter.c +++ b/ir/be/sparc/sparc_emitter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved. + * Copyright (C) 1995-2010 University of Karlsruhe. All right reserved. * * This file is part of libFirm. * @@ -20,7 +20,7 @@ /** * @file * @brief emit assembler for a backend graph - * @version $Id: sparc_emitter.c 26542 2009-09-18 09:18:32Z matze $ + * @version $Id$ */ #include "config.h" @@ -51,10 +51,19 @@ #include "gen_sparc_emitter.h" #include "sparc_nodes_attr.h" #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. */ @@ -122,8 +131,8 @@ static const arch_register_t *get_out_reg(const ir_node *node, int pos) void sparc_emit_immediate(const ir_node *node) { - // TODO: make sure it's a valid simm13 ? 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); } @@ -164,10 +173,12 @@ 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("+0x%X", attr->offset); + be_emit_irprintf("+%ld", attr->offset); } + /** * Emit load mode char */ @@ -209,6 +220,75 @@ void sparc_emit_store_mode(const ir_node *node) } } +/** + * emit integer signed/unsigned prefix char + */ +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"); +} + +/** + * emit FP load mode char + */ +void sparc_emit_fp_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); + + 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"); + } +} + +/** + * emit FP store mode char + */ +void sparc_emit_fp_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)); + + if (bits == 32) { + be_emit_string("f"); + } else if (bits == 64) { + be_emit_string("df"); + } else { + panic("FP store mode > 64bits not implemented yet"); + } +} + +/** + * emits the FP mode suffix char + */ +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"); + } +} + /** * Returns the target label for a control flow node. */ @@ -223,7 +303,7 @@ static void sparc_emit_cfop_target(const ir_node *node) */ static void sparc_emit_entity(ir_entity *entity) { - be_emit_ident(get_entity_ld_ident(entity)); + be_gas_emit_entity(entity); } /*********************************************************************************** @@ -244,36 +324,120 @@ static void emit_be_IncSP(const ir_node *irn) { int offs = -be_get_IncSP_offset(irn); - if (offs != 0) { - /* SPARC stack grows downwards */ - if (offs < 0) { - be_emit_cstring("\tsub "); - offs = -offs; - } else { - be_emit_cstring("\tadd "); - } + if (offs == 0) + return; - sparc_emit_source_register(irn, 0); - be_emit_irprintf(", %d", offs); - be_emit_cstring(", "); - sparc_emit_dest_register(irn, 0); - be_emit_finish_line_gas(irn); + /* SPARC stack grows downwards */ + if (offs < 0) { + be_emit_cstring("\tsub "); + offs = -offs; } else { - // ignore IncSP(0) - //be_emit_cstring("\t/* IncSP(0) skipped */"); - -// be_emit_cstring("\t/* "); -// be_emit_cstring("sub "); -// offs = -offs; -// sparc_emit_source_register(irn, 0); -// be_emit_irprintf(", %d", offs); -// be_emit_cstring(", "); -// sparc_emit_dest_register(irn, 0); -// be_emit_cstring(" ignored */ "); -// be_emit_finish_line_gas(irn); + be_emit_cstring("\tadd "); } + sparc_emit_source_register(irn, 0); + be_emit_irprintf(", %d", offs); + be_emit_cstring(", "); + sparc_emit_dest_register(irn, 0); + be_emit_finish_line_gas(irn); +} +/** + * emits code for save instruction with min. required stack space + */ +static void emit_sparc_Save(const ir_node *irn) +{ + 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); + sparc_emit_dest_register(irn, 0); + be_emit_finish_line_gas(irn); +} + +/** + * emits code to load hi 22 bit of a constant + */ +static void emit_sparc_HiImm(const ir_node *irn) +{ + const sparc_attr_t *attr = get_sparc_attr_const(irn); + be_emit_cstring("\tsethi "); + be_emit_irprintf("%%hi(%d), ", attr->immediate_value); + sparc_emit_dest_register(irn, 0); + be_emit_finish_line_gas(irn); +} + +/** + * emits code to load lo 10bits of a constant + */ +static void emit_sparc_LoImm(const ir_node *irn) +{ + const sparc_attr_t *attr = get_sparc_attr_const(irn); + be_emit_cstring("\tor "); + sparc_emit_source_register(irn, 0); + be_emit_irprintf(", %%lo(%d), ", attr->immediate_value); + sparc_emit_dest_register(irn, 0); + 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 + */ +static void emit_sparc_Mulh(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); + + // 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); } /** @@ -282,6 +446,9 @@ static void emit_be_IncSP(const ir_node *irn) static void emit_be_Return(const ir_node *irn) { be_emit_cstring("\tret"); + //be_emit_cstring("\tjmp %i7+8"); + be_emit_finish_line_gas(irn); + be_emit_cstring("\trestore"); be_emit_finish_line_gas(irn); } @@ -295,6 +462,7 @@ static void emit_be_Call(const ir_node *irn) 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(); @@ -307,40 +475,130 @@ static void emit_be_Call(const ir_node *irn) } } +/** + * Emit code for Perm node + */ +static void emit_be_Perm(const ir_node *irn) +{ + be_emit_cstring("\txor "); + sparc_emit_source_register(irn, 1); + be_emit_cstring(", "); + sparc_emit_source_register(irn, 0); + be_emit_cstring(", "); + sparc_emit_source_register(irn, 0); + be_emit_finish_line_gas(NULL); + + be_emit_cstring("\txor "); + sparc_emit_source_register(irn, 1); + be_emit_cstring(", "); + sparc_emit_source_register(irn, 0); + be_emit_cstring(", "); + sparc_emit_source_register(irn, 1); + be_emit_finish_line_gas(NULL); + + be_emit_cstring("\txor "); + sparc_emit_source_register(irn, 1); + be_emit_cstring(", "); + sparc_emit_source_register(irn, 0); + be_emit_cstring(", "); + sparc_emit_source_register(irn, 0); + be_emit_finish_line_gas(irn); +} + +/** + * TODO: not really tested but seems to work with memperm_arity == 1 + */ +static void emit_be_MemPerm(const ir_node *node) +{ + int i; + int memperm_arity; + int sp_change = 0; + + /* TODO: this implementation is slower than necessary. + The longterm goal is however to avoid the memperm node completely */ + + memperm_arity = be_get_MemPerm_entity_arity(node); + // we use our local registers - so this is limited to 8 inputs ! + if (memperm_arity > 8) + panic("memperm with more than 8 inputs not supported yet"); + + for (i = 0; i < memperm_arity; ++i) { + int offset; + ir_entity *entity = be_get_MemPerm_in_entity(node, i); + + /* spill register */ + sp_change += 4; + be_emit_irprintf("\tst %%l%d, [%%sp-%d]", i, sp_change); + 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_finish_line_gas(node); + } + + for (i = memperm_arity-1; i >= 0; --i) { + int offset; + ir_entity *entity = be_get_MemPerm_out_entity(node, i); + + /* store to new entity */ + offset = get_entity_offset(entity) + sp_change; + be_emit_irprintf("\tst %%l%d, [%%sp+%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_finish_line_gas(node); + } + assert(sp_change == 0); +} + /** * Emit a SymConst. */ static void emit_sparc_SymConst(const ir_node *irn) { const sparc_symconst_attr_t *attr = get_sparc_symconst_attr_const(irn); - //const char *entity_name = get_entity_ld_name(attr->entity); - ident *id_symconst = get_entity_ident(attr->entity); - const char *label = get_id_str(id_symconst); //sethi %hi(const32),%reg //or %reg,%lo(const32),%reg - be_emit_irprintf("\tsethi %%hi(%s), ", label); + be_emit_cstring("\tsethi %hi("); + be_gas_emit_entity(attr->entity); + be_emit_cstring("), "); sparc_emit_dest_register(irn, 0); be_emit_cstring("\n "); + + // TODO: could be combined with the following load/store instruction be_emit_cstring("\tor "); sparc_emit_dest_register(irn, 0); - be_emit_irprintf(", %%lo(%s), ", label); + be_emit_cstring(", %lo("); + be_gas_emit_entity(attr->entity); + be_emit_cstring("), "); sparc_emit_dest_register(irn, 0); be_emit_finish_line_gas(irn); } - /** * Emits code for FrameAddr fix */ static void emit_sparc_FrameAddr(const ir_node *irn) { const sparc_symconst_attr_t *attr = get_irn_generic_attr_const(irn); - be_emit_cstring("\tadd "); - sparc_emit_source_register(irn, 0); - be_emit_cstring(", "); - be_emit_irprintf("0x%X", attr->fp_offset); + + // no need to fix offset as we are adressing via the framepointer + if (attr->fp_offset >= 0) { + be_emit_cstring("\tadd "); + sparc_emit_source_register(irn, 0); + be_emit_cstring(", "); + be_emit_irprintf("%ld", attr->fp_offset + save_attr->initial_stacksize); + } else { + be_emit_cstring("\tsub "); + sparc_emit_source_register(irn, 0); + be_emit_cstring(", "); + be_emit_irprintf("%ld", -attr->fp_offset); + } + be_emit_cstring(", "); sparc_emit_dest_register(irn, 0); be_emit_finish_line_gas(irn); @@ -397,6 +655,7 @@ 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; @@ -426,13 +685,13 @@ static void emit_sparc_Branch(const ir_node *irn) be_emit_cstring("\tba "); sparc_emit_cfop_target(proj_false); be_emit_finish_line_gas(proj_false); - be_emit_cstring("\tnop\t\t/* TODO: use delay slot */"); - be_emit_write_line(); + be_emit_cstring("\tnop\t\t/* TODO: use delay slot */\n"); + be_emit_finish_line_gas(proj_false); } } /** - * emit Jmp (which actually is a branch always) + * emit Jmp (which actually is a branch always (ba) instruction) */ static void emit_sparc_Jmp(const ir_node *node) { @@ -446,6 +705,8 @@ static void emit_sparc_Jmp(const ir_node *node) if (get_irn_link(node) != next_block) { be_emit_cstring("\tba "); sparc_emit_cfop_target(node); + be_emit_finish_line_gas(node); + be_emit_cstring("\tnop\t\t/* TODO: use delay slot */\n"); } else { be_emit_cstring("\t/* fallthrough to "); sparc_emit_cfop_target(node); @@ -454,6 +715,9 @@ static void emit_sparc_Jmp(const ir_node *node) be_emit_finish_line_gas(node); } +/** + * emit copy node + */ static void emit_be_Copy(const ir_node *irn) { ir_mode *mode = get_irn_mode(irn); @@ -514,16 +778,26 @@ static void sparc_register_emitters(void) 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_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_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); @@ -532,8 +806,7 @@ static void sparc_register_emitters(void) set_emitter(op_arm_fpaDbl2GP, emit_arm_fpaDbl2GP); set_emitter(op_arm_LdTls, emit_arm_LdTls); set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp); - set_emitter(op_be_MemPerm, emit_be_MemPerm); - set_emitter(op_be_Perm, emit_be_Perm); + */ /* no need to emit anything for the following nodes */ set_emitter(op_Phi, emit_nothing); @@ -588,12 +861,7 @@ static void sparc_gen_block(ir_node *block, void *data) static void sparc_emit_func_prolog(ir_graph *irg) { ir_entity *ent = get_irg_entity(irg); - be_gas_emit_function_prolog(ent, 4); - // TODO: fetch reg names via API func - // TODO: move value to SPARC_MIN_STACKSIZE const - be_emit_cstring("\tsave %sp, -64, %sp"); - be_emit_cstring("\t/* incr CWP and alloc min. required stack space */\n"); be_emit_write_line(); } @@ -604,9 +872,7 @@ static void sparc_emit_func_epilog(ir_graph *irg) { ir_entity *ent = get_irg_entity(irg); const char *irg_name = get_entity_ld_name(ent); - - be_emit_cstring("\trestore"); - be_emit_cstring("\t/* decr CWP */\n"); + be_emit_write_line(); be_emit_irprintf("\t.size %s, .-%s\n", irg_name, irg_name); be_emit_cstring("# -- End "); be_emit_string(irg_name); @@ -641,15 +907,17 @@ void sparc_gen_routine(const sparc_code_gen_t *cg, ir_graph *irg) ir_node *last_block = NULL; ir_entity *entity = get_irg_entity(irg); int i, n; + (void) cg; be_gas_elf_type_char = '#'; + be_gas_object_file_format = OBJECT_FILE_FORMAT_ELF_SPARC; /* register all emitter functions */ sparc_register_emitters(); - be_dbg_method_begin(entity, be_abi_get_stack_layout(cg->birg->abi)); + be_dbg_method_begin(entity); /* create the block schedule. For now, we don't need it earlier. */ - blk_sched = be_create_block_schedule(cg->irg, cg->birg->exec_freq); + blk_sched = be_create_block_schedule(irg); // emit function prolog sparc_emit_func_prolog(irg);