X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fbearch_ia32.c;h=269901cf73883a5ebd98c5fcc7feda566185650e;hb=927eac90f1c28092a5406def6540bb9fae752360;hp=b463da42df585473413f7d4d46f6f204d6303fc5;hpb=20f979ab927f39d7d934100e402a74a7bb511b9e;p=libfirm diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index b463da42d..269901cf7 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -50,6 +50,7 @@ #include "ia32_x87.h" #include "ia32_dbg_stat.h" #include "ia32_finish.h" +#include "ia32_util.h" #define DEBUG_MODULE "firm.be.ia32.isa" @@ -70,21 +71,6 @@ 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 the first Proj with given mode from mode_T node */ -static ir_node *get_proj_for_mode(ir_node *node, ir_mode *mode) { - const ir_edge_t *edge; - - assert(get_irn_mode(node) == mode_T && "Need mode_T node."); - - foreach_out_edge(node, edge) { - ir_node *proj = get_edge_src_irn(edge); - if (get_irn_mode(proj) == mode) - return proj; - } - - return NULL; -} - /************************************************** * _ _ _ __ * | | | (_)/ _| @@ -341,7 +327,6 @@ static const arch_register_t *ia32_abi_prologue(void *self, ir_node **mem, pmap ia32_abi_env_t *env = self; if (!env->flags.try_omit_fp) { - int reg_size = get_mode_size_bytes(env->isa->bp->reg_class->mode); 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); @@ -400,7 +385,6 @@ static void ia32_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_ else { const ia32_isa_t *isa = (ia32_isa_t *)env->isa; ir_mode *mode_bp = env->isa->bp->reg_class->mode; - int reg_size = get_mode_size_bytes(env->isa->bp->reg_class->mode); /* gcc always emits a leave at the end of a routine */ if (1 || ARCH_AMD(isa->opt_arch)) { @@ -487,6 +471,10 @@ static ir_type *ia32_abi_get_between_type(void *self) static int ia32_get_op_estimated_cost(const void *self, const ir_node *irn) { int cost; + + if(is_Proj(irn)) + return 0; + switch (get_ia32_irn_opcode(irn)) { case iro_ia32_xDiv: case iro_ia32_DivMod: @@ -587,8 +575,8 @@ static arch_inverse_t *ia32_get_inverse(const void *self, const ir_node *irn, in } else { /* normal add: inverse == sub */ - ir_node *proj = get_irn_out_edge_first(irn)->src; - assert(proj && is_Proj(proj)); + ir_node *proj = ia32_get_res_proj(irn); + assert(proj); inverse->nodes[0] = new_rd_ia32_Sub(NULL, irg, block, noreg, noreg, proj, get_irn_n(irn, i ^ 1), nomem); pnc = pn_ia32_Sub_res; @@ -606,8 +594,8 @@ static arch_inverse_t *ia32_get_inverse(const void *self, const ir_node *irn, in } else { /* normal sub */ - ir_node *proj = get_irn_out_edge_first(irn)->src; - assert(proj && is_Proj(proj)); + ir_node *proj = ia32_get_res_proj(irn); + assert(proj); if (i == 2) { inverse->nodes[0] = new_rd_ia32_Add(NULL, irg, block, noreg, noreg, proj, get_irn_n(irn, 3), nomem); @@ -634,16 +622,24 @@ static arch_inverse_t *ia32_get_inverse(const void *self, const ir_node *irn, in inverse->costs += 1; } break; - case iro_ia32_Not: - inverse->nodes[0] = new_rd_ia32_Not(NULL, irg, block, noreg, noreg, get_irn_n(irn, i), nomem); + case iro_ia32_Not: { + ir_node *proj = ia32_get_res_proj(irn); + assert(proj); + + inverse->nodes[0] = new_rd_ia32_Not(NULL, irg, block, noreg, noreg, proj, nomem); pnc = pn_ia32_Not_res; inverse->costs += 1; break; - case iro_ia32_Minus: - inverse->nodes[0] = new_rd_ia32_Minus(NULL, irg, block, noreg, noreg, get_irn_n(irn, i), nomem); - pnc = pn_ia32_Minus_res; + } + case iro_ia32_Minus: { + ir_node *proj = ia32_get_res_proj(irn); + assert(proj); + + inverse->nodes[0] = new_rd_ia32_Minus(NULL, irg, block, noreg, noreg, proj, nomem); + pnc = pn_ia32_Minus_res; inverse->costs += 1; break; + } default: /* inverse operation not supported */ return NULL; @@ -655,6 +651,59 @@ static arch_inverse_t *ia32_get_inverse(const void *self, const ir_node *irn, in return inverse; } +/** + * Check if irn can load it's operand at position i from memory (source addressmode). + * @param self Pointer to irn ops itself + * @param irn The irn to be checked + * @param i The operands position + * @return Non-Zero if operand can be loaded + */ +static int ia32_possible_memory_operand(const void *self, const ir_node *irn, unsigned int i) { + if (! is_ia32_irn(irn) || /* must be an ia32 irn */ + get_irn_arity(irn) != 5 || /* must be a binary operation */ + get_ia32_op_type(irn) != ia32_Normal || /* must not already be a addressmode irn */ + ! (get_ia32_am_support(irn) & ia32_am_Source) || /* must be capable of source addressmode */ + (i != 2 && i != 3) || /* a "real" operand position must be requested */ + (i == 2 && ! is_ia32_commutative(irn)) || /* if first operand requested irn must be commutative */ + is_ia32_use_frame(irn)) /* must not already use frame */ + return 0; + + return 1; +} + +static void ia32_perform_memory_operand(const void *self, ir_node *irn, ir_node *reload, unsigned int i) { + assert(ia32_possible_memory_operand(self, irn, i) && "Cannot perform memory operand change"); + assert(get_nodes_block(reload) == get_nodes_block(irn) && "Reload must be in same block as irn."); + + if (get_irn_n_edges(reload) > 1) + return; + + if (i == 2) { + ir_node *tmp = get_irn_n(irn, 3); + set_irn_n(irn, 3, get_irn_n(irn, 2)); + set_irn_n(irn, 2, tmp); + } + + set_ia32_am_support(irn, ia32_am_Source); + set_ia32_op_type(irn, ia32_AddrModeS); + set_ia32_am_flavour(irn, ia32_B); + set_ia32_ls_mode(irn, get_irn_mode(reload)); + set_ia32_frame_ent(irn, be_get_frame_entity(reload)); + set_ia32_use_frame(irn); + + set_irn_n(irn, 0, be_get_Reload_frame(reload)); + set_irn_n(irn, 4, be_get_Reload_mem(reload)); + + /* + Input at position one is index register, which is NoReg. + 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)); + + DBG_OPT_AM_S(reload, irn); +} + static const be_abi_callbacks_t ia32_abi_callbacks = { ia32_abi_init, free, @@ -675,7 +724,9 @@ static const arch_irn_ops_if_t ia32_irn_ops_if = { ia32_get_frame_entity, ia32_set_stack_bias, ia32_get_inverse, - ia32_get_op_estimated_cost + ia32_get_op_estimated_cost, + ia32_possible_memory_operand, + ia32_perform_memory_operand, }; ia32_irn_ops_t ia32_irn_ops = { @@ -758,7 +809,7 @@ static void remove_unused_nodes(ir_node *irn, bitset_t *already_visited) { /* tuple node has one user which is not the mem proj-> ok */ if (mode == mode_T && get_irn_n_edges(irn) == 1) { - mem_proj = get_proj_for_mode(irn, mode_M); + mem_proj = ia32_get_proj_for_mode(irn, mode_M); if (! mem_proj) return; } @@ -960,10 +1011,11 @@ static void ia32_after_ra_walker(ir_node *block, void *env) { transform_to_Load(&tenv); } else if (be_is_Spill(node)) { + ir_node *spillval = get_irn_n(node, be_pos_Spill_val); /* we always spill the whole register */ tenv.dbg = get_irn_dbg_info(node); tenv.irn = node; - tenv.mode = fix_spill_mode(cg, get_irn_mode(be_get_Spill_context(node))); + tenv.mode = fix_spill_mode(cg, get_irn_mode(spillval)); transform_to_Store(&tenv); } } @@ -978,6 +1030,7 @@ static void ia32_after_ra_walker(ir_node *block, void *env) { */ static void ia32_after_ra(void *self) { ia32_code_gen_t *cg = self; + irg_block_walk_graph(cg->irg, NULL, ia32_after_ra_walker, self); /* if we do x87 code generation, rewrite all the virtual instructions and registers */ @@ -1246,7 +1299,6 @@ static int ia32_get_n_reg_class(const void *self) { * Return the register class for index i. */ static const arch_register_class_t *ia32_get_reg_class(const void *self, int i) { - const ia32_isa_t *isa = self; assert(i >= 0 && i < 3 && "Invalid ia32 register class requested."); if (i == 0) return &ia32_reg_classes[CLASS_ia32_gp];