X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fbearch_ia32.c;h=3abf57d17168497c755b0de61bdd4d5a5952c97d;hb=a1a465eb2b3f54027b29f829423fffd0396937f4;hp=711c341adc19991df70482a4a7c457cb0eff2952;hpb=6501140c2ad8e4175d1330d60574af987f1d6ded;p=libfirm diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index 711c341ad..3abf57d17 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -43,6 +43,7 @@ #include "../be_t.h" #include "../beirgmod.h" #include "../be_dbgout.h" +#include "../beblocksched.h" #include "bearch_ia32_t.h" #include "ia32_new_nodes.h" /* ia32 nodes interface */ @@ -62,9 +63,6 @@ /* TODO: ugly */ static set *cur_reg_set = NULL; -#undef is_Start -#define is_Start(irn) (get_irn_opcode(irn) == iro_Start) - /* Creates the unique per irg GP NoReg node. */ ir_node *ia32_new_NoReg_gp(ia32_code_gen_t *cg) { return be_abi_get_callee_save_irn(cg->birg->abi, &ia32_gp_regs[REG_GP_NOREG]); @@ -76,6 +74,21 @@ ir_node *ia32_new_NoReg_fp(ia32_code_gen_t *cg) { USE_SSE2(cg) ? &ia32_xmm_regs[REG_XMM_NOREG] : &ia32_vfp_regs[REG_VFP_NOREG]); } +/** + * Returns gp_noreg or fp_noreg, depending in input requirements. + */ +ir_node *ia32_get_admissible_noreg(ia32_code_gen_t *cg, ir_node *irn, int pos) { + arch_register_req_t req; + const arch_register_req_t *p_req; + + p_req = arch_get_register_req(cg->arch_env, &req, irn, pos); + assert(p_req && "Missing register requirements"); + if (p_req->cls == &ia32_reg_classes[CLASS_ia32_gp]) + return ia32_new_NoReg_gp(cg); + else + return ia32_new_NoReg_fp(cg); +} + /************************************************** * _ _ _ __ * | | | (_)/ _| @@ -87,13 +100,6 @@ ir_node *ia32_new_NoReg_fp(ia32_code_gen_t *cg) { * |___/ **************************************************/ -static ir_node *my_skip_proj(const ir_node *n) { - while (is_Proj(n)) - n = get_Proj_pred(n); - return (ir_node *)n; -} - - /** * Return register requirements for an ia32 node. * If the node returns a tuple (mode_T) then the proj's @@ -119,24 +125,22 @@ static const arch_register_req_t *ia32_get_irn_reg_req(const void *self, arch_re DBG((mod, LEVEL_1, "get requirements at pos %d for %+F ... ", pos, irn)); if (is_Proj(irn)) { - if (pos == -1) { - node_pos = ia32_translate_proj_pos(irn); - } - else { - node_pos = pos; + if(pos >= 0) { + DBG((mod, LEVEL_1, "ignoring request IN requirements for node %+F\n", irn)); + return NULL; } - irn = my_skip_proj(irn); + node_pos = (pos == -1) ? get_Proj_proj(irn) : pos; + irn = skip_Proj(irn); DB((mod, LEVEL_1, "skipping Proj, going to %+F at pos %d ... ", irn, node_pos)); } if (is_ia32_irn(irn)) { - if (pos >= 0) { - irn_req = get_ia32_in_req(irn, pos); - } - else { - irn_req = get_ia32_out_req(irn, node_pos); + irn_req = (pos >= 0) ? get_ia32_in_req(irn, pos) : get_ia32_out_req(irn, node_pos); + if (irn_req == NULL) { + /* no requirements */ + return NULL; } DB((mod, LEVEL_1, "returning reqs for %+F at pos %d\n", irn, pos)); @@ -192,8 +196,8 @@ static void ia32_set_irn_reg(const void *self, ir_node *irn, const arch_register DBG((ops->cg->mod, LEVEL_1, "ia32 assigned register %s to node %+F\n", reg->name, irn)); if (is_Proj(irn)) { - pos = ia32_translate_proj_pos(irn); - irn = my_skip_proj(irn); + pos = get_Proj_proj(irn); + irn = skip_Proj(irn); } if (is_ia32_irn(irn)) { @@ -217,8 +221,8 @@ static const arch_register_t *ia32_get_irn_reg(const void *self, const ir_node * return NULL; } - pos = ia32_translate_proj_pos(irn); - irn = my_skip_proj(irn); + pos = get_Proj_proj(irn); + irn = skip_Proj(irn); } if (is_ia32_irn(irn)) { @@ -236,7 +240,7 @@ static const arch_register_t *ia32_get_irn_reg(const void *self, const ir_node * static arch_irn_class_t ia32_classify(const void *self, const ir_node *irn) { arch_irn_class_t classification = arch_irn_class_normal; - irn = my_skip_proj(irn); + irn = skip_Proj(irn); if (is_cfop(irn)) classification |= arch_irn_class_branch; @@ -260,36 +264,33 @@ static arch_irn_class_t ia32_classify(const void *self, const ir_node *irn) { } static arch_irn_flags_t ia32_get_flags(const void *self, const ir_node *irn) { + arch_irn_flags_t flags; + ir_node *pred = is_Proj(irn) && mode_is_datab(get_irn_mode(irn)) ? get_Proj_pred(irn) : NULL; - if(is_Proj(irn)) { - ir_node *pred = get_Proj_pred(irn); - if(is_ia32_Push(pred) && get_Proj_proj(irn) == pn_ia32_Push_stack) { - /* Push modifies always ESP, this cannot be changed */ - return arch_irn_flags_modify_sp | arch_irn_flags_ignore; - } - if(is_ia32_Pop(pred) && get_Proj_proj(irn) == pn_ia32_Pop_stack) { - return arch_irn_flags_modify_sp | arch_irn_flags_ignore; - } - if(is_ia32_AddSP(pred) && get_Proj_proj(irn) == pn_ia32_AddSP_stack) { - /* AddSP modifies always ESP, this cannot be changed */ - return arch_irn_flags_modify_sp | arch_irn_flags_ignore; - } - if(is_ia32_SubSP(pred) && get_Proj_proj(irn) == pn_ia32_SubSP_stack) { - /* SubSP modifies always ESP, this cannot be changed */ - return arch_irn_flags_modify_sp | arch_irn_flags_ignore; - } - } - - irn = my_skip_proj(irn); - if (is_ia32_irn(irn)) - return get_ia32_flags(irn); + if (is_Unknown(irn)) + flags = arch_irn_flags_ignore; else { - if (is_Unknown(irn)) - return arch_irn_flags_ignore; - return 0; + /* pred is only set, if we have a Proj */ + flags = pred && is_ia32_irn(pred) ? get_ia32_out_flags(pred, get_Proj_proj(irn)) : arch_irn_flags_none; + + irn = skip_Proj(irn); + if (is_ia32_irn(irn)) + flags |= get_ia32_flags(irn); } + + return flags; } +/** + * The IA32 ABI callback object. + */ +typedef struct { + be_abi_call_flags_bits_t flags; /**< The call flags. */ + const arch_isa_t *isa; /**< The ISA handle. */ + const arch_env_t *aenv; /**< The architecture environment. */ + ir_graph *irg; /**< The associated graph. */ +} ia32_abi_env_t; + static entity *ia32_get_frame_entity(const void *self, const ir_node *irn) { return is_ia32_irn(irn) ? get_ia32_frame_ent(irn) : NULL; } @@ -305,11 +306,14 @@ static void ia32_set_frame_offset(const void *self, ir_node *irn, int bias) { if (get_ia32_frame_ent(irn)) { ia32_am_flavour_t am_flav = get_ia32_am_flavour(irn); - /* Pop nodes modify the stack pointer before calculating the destination - * address, so fix this here - */ if(is_ia32_Pop(irn)) { - bias -= 4; + int omit_fp = be_abi_omit_fp(ops->cg->birg->abi); + if (omit_fp) { + /* Pop nodes modify the stack pointer before calculating the destination + * address, so fix this here + */ + bias -= 4; + } } DBG((ops->cg->mod, LEVEL_1, "stack biased %+F with %d\n", irn, bias)); @@ -328,36 +332,18 @@ static void ia32_set_frame_offset(const void *self, ir_node *irn, int bias) { static int ia32_get_sp_bias(const void *self, const ir_node *irn) { if(is_Proj(irn)) { - int proj = get_Proj_proj(irn); + long proj = get_Proj_proj(irn); ir_node *pred = get_Proj_pred(irn); - if(is_ia32_Push(pred) && proj == 0) + if (proj == pn_ia32_Push_stack && is_ia32_Push(pred)) return 4; - if(is_ia32_Pop(pred) && proj == 1) + if (proj == pn_ia32_Pop_stack && is_ia32_Pop(pred)) return -4; } return 0; } -typedef struct { - be_abi_call_flags_bits_t flags; - const arch_isa_t *isa; - const arch_env_t *aenv; - ir_graph *irg; -} ia32_abi_env_t; - -static void *ia32_abi_init(const be_abi_call_t *call, const arch_env_t *aenv, ir_graph *irg) -{ - ia32_abi_env_t *env = xmalloc(sizeof(env[0])); - be_abi_call_flags_t fl = be_abi_call_get_flags(call); - env->flags = fl.bits; - env->irg = irg; - env->aenv = aenv; - env->isa = aenv->isa; - return env; -} - /** * Put all registers which are saved by the prologue/epilogue in a set. * @@ -390,10 +376,11 @@ static const arch_register_t *ia32_abi_prologue(void *self, ir_node **mem, pmap ir_node *bl = get_irg_start_block(env->irg); ir_node *curr_sp = be_abi_reg_map_get(reg_map, env->isa->sp); ir_node *curr_bp = be_abi_reg_map_get(reg_map, env->isa->bp); + ir_node *noreg = be_abi_reg_map_get(reg_map, &ia32_gp_regs[REG_GP_NOREG]); ir_node *push; /* push ebp */ - push = new_rd_ia32_Push(NULL, env->irg, bl, curr_sp, curr_bp, *mem); + push = new_rd_ia32_Push(NULL, env->irg, bl, noreg, noreg, curr_bp, curr_sp, *mem); curr_sp = new_r_Proj(env->irg, bl, push, get_irn_mode(curr_sp), pn_ia32_Push_stack); *mem = new_r_Proj(env->irg, bl, push, mode_M, pn_ia32_Push_M); @@ -459,13 +446,14 @@ static void ia32_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_ *mem = new_r_Proj(current_ir_graph, bl, leave, mode_M, pn_ia32_Leave_M); } else { + ir_node *noreg = be_abi_reg_map_get(reg_map, &ia32_gp_regs[REG_GP_NOREG]); ir_node *pop; /* copy ebp to esp */ curr_sp = be_new_SetSP(env->isa->sp, env->irg, bl, curr_sp, curr_bp, *mem); /* pop ebp */ - pop = new_rd_ia32_Pop(NULL, env->irg, bl, curr_sp, *mem); + pop = new_rd_ia32_Pop(NULL, env->irg, bl, noreg, noreg, curr_sp, *mem); set_ia32_flags(pop, arch_irn_flags_ignore); curr_bp = new_r_Proj(current_ir_graph, bl, pop, mode_bp, pn_ia32_Pop_res); curr_sp = new_r_Proj(current_ir_graph, bl, pop, get_irn_mode(curr_sp), pn_ia32_Pop_stack); @@ -479,6 +467,32 @@ static void ia32_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_ be_abi_reg_map_set(reg_map, env->isa->bp, curr_bp); } +/** + * Initialize the callback object. + * @param call The call object. + * @param aenv The architecture environment. + * @param irg The graph with the method. + * @return Some pointer. This pointer is passed to all other callback functions as self object. + */ +static void *ia32_abi_init(const be_abi_call_t *call, const arch_env_t *aenv, ir_graph *irg) +{ + ia32_abi_env_t *env = xmalloc(sizeof(env[0])); + be_abi_call_flags_t fl = be_abi_call_get_flags(call); + env->flags = fl.bits; + env->irg = irg; + env->aenv = aenv; + env->isa = aenv->isa; + return env; +} + +/** + * Destroy the callback object. + * @param self The callback object. + */ +static void ia32_abi_done(void *self) { + free(self); +} + /** * Produces the type which sits between the stack args and the locals on the stack. * it will contain the return address and space to store the old base pointer. @@ -723,6 +737,9 @@ static int ia32_possible_memory_operand(const void *self, const ir_node *irn, un } static void ia32_perform_memory_operand(const void *self, ir_node *irn, ir_node *spill, unsigned int i) { + const ia32_irn_ops_t *ops = self; + ia32_code_gen_t *cg = ops->cg; + assert(ia32_possible_memory_operand(self, irn, i) && "Cannot perform memory operand change"); if (i == 2) { @@ -735,8 +752,6 @@ static void ia32_perform_memory_operand(const void *self, ir_node *irn, ir_node set_ia32_op_type(irn, ia32_AddrModeS); set_ia32_am_flavour(irn, ia32_B); set_ia32_ls_mode(irn, get_irn_mode(get_irn_n(irn, i))); - //TODO this will fail, if spill is a PhiM (give PhiMs entities?) - set_ia32_frame_ent(irn, be_get_frame_entity(spill)); set_ia32_use_frame(irn); set_ia32_got_reload(irn); @@ -748,14 +763,14 @@ static void ia32_perform_memory_operand(const void *self, ir_node *irn, ir_node We would need cg object to get a real noreg, but we cannot access it from here. */ - set_irn_n(irn, 3, get_irn_n(irn, 1)); + set_irn_n(irn, 3, ia32_get_admissible_noreg(cg, irn, 3)); //FIXME DBG_OPT_AM_S(reload, irn); } static const be_abi_callbacks_t ia32_abi_callbacks = { ia32_abi_init, - free, + ia32_abi_done, ia32_abi_get_between_type, ia32_abi_dont_save_regs, ia32_abi_prologue, @@ -984,9 +999,8 @@ static void transform_to_Load(ia32_transform_env_t *env) { else new_op = new_rd_ia32_vfld(env->dbg, env->irg, env->block, ptr, noreg, mem); } - else { + else new_op = new_rd_ia32_Load(env->dbg, env->irg, env->block, ptr, noreg, mem); - } set_ia32_am_support(new_op, ia32_am_Source); set_ia32_op_type(new_op, ia32_AddrModeS); @@ -997,7 +1011,7 @@ static void transform_to_Load(ia32_transform_env_t *env) { DBG_OPT_RELOAD2LD(irn, new_op); - proj = new_rd_Proj(env->dbg, env->irg, env->block, new_op, mode, pn_Load_res); + proj = new_rd_Proj(env->dbg, env->irg, env->block, new_op, mode, pn_ia32_Load_res); if (sched_point) { sched_add_after(sched_point, new_op); @@ -1067,42 +1081,42 @@ static void transform_to_Store(ia32_transform_env_t *env) { exchange(irn, proj); } -static ir_node *create_push(ia32_transform_env_t *env, ir_node *schedpoint, ir_node *sp, ir_node *mem, entity *ent, const char *offset) { +static ir_node *create_push(ia32_transform_env_t *env, ir_node *schedpoint, ir_node *sp, ir_node *mem, entity *ent) { ir_node *noreg = ia32_new_NoReg_gp(env->cg); + ir_node *frame = get_irg_frame(env->irg); - ir_node *push = new_rd_ia32_Push(env->dbg, env->irg, env->block, sp, noreg, mem); + ir_node *push = new_rd_ia32_Push(env->dbg, env->irg, env->block, frame, noreg, noreg, sp, mem); set_ia32_frame_ent(push, ent); set_ia32_use_frame(push); set_ia32_op_type(push, ia32_AddrModeS); set_ia32_am_flavour(push, ia32_B); set_ia32_ls_mode(push, mode_Is); - if(offset != NULL) - add_ia32_am_offs(push, offset); sched_add_before(schedpoint, push); return push; } -static ir_node *create_pop(ia32_transform_env_t *env, ir_node *schedpoint, ir_node *sp, entity *ent, const char *offset) { - ir_node *pop = new_rd_ia32_Pop(env->dbg, env->irg, env->block, sp, new_NoMem()); +static ir_node *create_pop(ia32_transform_env_t *env, ir_node *schedpoint, ir_node *sp, entity *ent) { + ir_node *noreg = ia32_new_NoReg_gp(env->cg); + ir_node *frame = get_irg_frame(env->irg); + + ir_node *pop = new_rd_ia32_Pop(env->dbg, env->irg, env->block, frame, noreg, sp, new_NoMem()); set_ia32_frame_ent(pop, ent); set_ia32_use_frame(pop); set_ia32_op_type(pop, ia32_AddrModeD); set_ia32_am_flavour(pop, ia32_B); set_ia32_ls_mode(pop, mode_Is); - if(offset != NULL) - add_ia32_am_offs(pop, offset); sched_add_before(schedpoint, pop); return pop; } -static ir_node* create_spproj(ia32_transform_env_t *env, ir_node *pred, int pos, ir_node *schedpoint, const ir_node *oldsp) { - ir_mode *spmode = get_irn_mode(oldsp); - const arch_register_t *spreg = arch_get_irn_register(env->cg->arch_env, oldsp); +static ir_node* create_spproj(ia32_transform_env_t *env, ir_node *pred, int pos, ir_node *schedpoint) { + ir_mode *spmode = mode_Iu; + const arch_register_t *spreg = &ia32_gp_regs[REG_ESP]; ir_node *sp; sp = new_rd_Proj(env->dbg, env->irg, env->block, pred, spmode, pos); @@ -1112,15 +1126,15 @@ static ir_node* create_spproj(ia32_transform_env_t *env, ir_node *pred, int pos, return sp; } +/** + * Transform memperm, currently we do this the ugly way and produce + * push/pop into/from memory cascades. This is possible without using + * any registers. + */ static void transform_MemPerm(ia32_transform_env_t *env) { - /* - * Transform memperm, currently we do this the ugly way and produce - * push/pop into/from memory cascades. This is possible without using - * any registers. - */ ir_node *node = env->irn; int i, arity; - ir_node *sp = get_irn_n(node, 0); + ir_node *sp = be_abi_get_ignore_irn(env->cg->birg->abi, &ia32_gp_regs[REG_ESP]); const ir_edge_t *edge; const ir_edge_t *next; ir_node **pops; @@ -1138,12 +1152,13 @@ static void transform_MemPerm(ia32_transform_env_t *env) { assert( (entbits == 32 || entbits == 64) && "spillslot on x86 should be 32 or 64 bit"); - push = create_push(env, node, sp, mem, ent, NULL); - sp = create_spproj(env, push, 0, node, sp); + push = create_push(env, node, sp, mem, ent); + sp = create_spproj(env, push, 0, node); if(entbits == 64) { // add another push after the first one - push = create_push(env, node, sp, mem, ent, "4"); - sp = create_spproj(env, push, 0, node, sp); + push = create_push(env, node, sp, mem, ent); + add_ia32_am_offs_int(push, 4); + sp = create_spproj(env, push, 0, node); } set_irn_n(node, i, new_Bad()); @@ -1159,15 +1174,14 @@ static void transform_MemPerm(ia32_transform_env_t *env) { assert( (entbits == 32 || entbits == 64) && "spillslot on x86 should be 32 or 64 bit"); - pop = create_pop(env, node, sp, ent, NULL); + pop = create_pop(env, node, sp, ent); if(entbits == 64) { // add another pop after the first one - sp = create_spproj(env, pop, 1, node, sp); - pop = create_pop(env, node, sp, ent, "4"); + sp = create_spproj(env, pop, 1, node); + pop = create_pop(env, node, sp, ent); + add_ia32_am_offs_int(pop, 4); } - //if(i != 0) { - sp = create_spproj(env, pop, 1, node, sp); - //} + sp = create_spproj(env, pop, 1, node); pops[i] = pop; } @@ -1269,11 +1283,10 @@ static void ia32_finish(void *self) { ia32_code_gen_t *cg = self; ir_graph *irg = cg->irg; - // Matze: disabled for now, as the irextbb algo sometimes returns extbb in - // the wrong order if the graph has critical edges - be_remove_empty_blocks(irg); + //be_remove_empty_blocks(irg); + cg->blk_sched = be_create_block_schedule(irg, cg->birg->execfreqs); - cg->blk_sched = sched_create_block_schedule(cg->irg, cg->birg->execfreqs); + //cg->blk_sched = sched_create_block_schedule(cg->irg, cg->birg->execfreqs); /* if we do x87 code generation, rewrite all the virtual instructions and registers */ if (cg->used_fp == fp_x87 || cg->force_sim) { @@ -1643,7 +1656,7 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type, be_abi_cal tp = get_method_res_type(method_type, 1); mode = get_type_mode(tp); - assert(!mode_is_float(mode) && "two FP results not supported"); + assert(!mode_is_float(mode) && "mixed INT, FP results not supported"); be_abi_call_res_reg(abi, 0, &ia32_gp_regs[REG_EAX]); be_abi_call_res_reg(abi, 1, &ia32_gp_regs[REG_EDX]); @@ -1655,9 +1668,7 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type, be_abi_cal assert(is_atomic_type(tp)); mode = get_type_mode(tp); - reg = mode_is_float(mode) ? - (USE_SSE2(isa) ? &ia32_xmm_regs[REG_XMM0] : &ia32_vfp_regs[REG_VF0]) : - &ia32_gp_regs[REG_EAX]; + reg = mode_is_float(mode) ? &ia32_vfp_regs[REG_VF0] : &ia32_gp_regs[REG_EAX]; be_abi_call_res_reg(abi, 0, reg); }