X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_finish.c;h=45f616b2c7e1c9f8525227da29363741bf8f45fa;hb=afa44cc5648401a50c08458622b50de4256498c2;hp=d376e4afd3d037e58f01e131b03e2aff40e064c0;hpb=7177a7f07255cc8f0cccd4d3777b19d06b18549b;p=libfirm diff --git a/ir/be/ia32/ia32_finish.c b/ir/be/ia32/ia32_finish.c index d376e4afd..45f616b2c 100644 --- a/ir/be/ia32/ia32_finish.c +++ b/ir/be/ia32/ia32_finish.c @@ -4,6 +4,10 @@ * $Id$ */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "irnode.h" #include "ircons.h" #include "irgmod.h" @@ -21,6 +25,7 @@ #include "ia32_transform.h" #include "ia32_dbg_stat.h" #include "ia32_optimize.h" +#include "gen_ia32_regalloc_if.h" /** * Transforms a Sub or xSub into Neg--Add iff OUT_REG == SRC2_REG. @@ -32,7 +37,7 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) { const arch_register_t *in1_reg, *in2_reg, *out_reg, **slots; /* Return if AM node or not a Sub or xSub */ - if (get_ia32_op_type(irn) != ia32_Normal || !(is_ia32_Sub(irn) || is_ia32_xSub(irn))) + if (!(is_ia32_Sub(irn) || is_ia32_xSub(irn)) || get_ia32_op_type(irn) != ia32_Normal) return; noreg = ia32_new_NoReg_gp(cg); @@ -58,6 +63,7 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) { arch_set_irn_register(cg->arch_env, res, in2_reg); /* add to schedule */ + sched_add_before(irn, get_Proj_pred(res)); sched_add_before(irn, res); /* generate the add */ @@ -99,9 +105,10 @@ static void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) { int imm = 0; ir_node *res = NULL; ir_node *nomem, *noreg, *base, *index, *op1, *op2; - char *offs; + const char *offs = NULL; ia32_transform_env_t tenv; const arch_register_t *out_reg, *base_reg, *index_reg; + int imm_tp = ia32_ImmConst; /* must be a LEA */ if (! is_ia32_Lea(irn)) @@ -123,11 +130,20 @@ static void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) { base = get_irn_n(irn, 0); index = get_irn_n(irn,1); - offs = get_ia32_am_offs(irn); + if (am_flav & ia32_O) { + offs = get_ia32_am_offs(irn); + + if (! offs) { + ident *id = get_ia32_am_sc(irn); - /* offset has a explicit sign -> we need to skip + */ - if (offs && offs[0] == '+') - offs++; + assert(id != NULL); + offs = get_id_str(id); + imm_tp = ia32_ImmSymConst; + } + /* offset has a explicit sign -> we need to skip + */ + else if (offs[0] == '+') + offs++; + } out_reg = arch_get_irn_register(cg->arch_env, irn); base_reg = arch_get_irn_register(cg->arch_env, base); @@ -191,7 +207,7 @@ static void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) { if (imm) { set_ia32_cnst(res, offs); - set_ia32_immop_type(res, ia32_ImmConst); + set_ia32_immop_type(res, imm_tp); } SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, irn)); @@ -219,6 +235,7 @@ static INLINE int need_constraint_copy(ir_node *irn) { ! is_ia32_Conv_I2I(irn) && \ ! is_ia32_Conv_I2I8Bit(irn) && \ ! is_ia32_CmpCMov(irn) && \ + ! is_ia32_PsiCondCMov(irn) && \ ! is_ia32_CmpSet(irn); } @@ -297,10 +314,37 @@ insert_copy: } } - /* If we have a CondJmp/CmpSet/xCmpSet with immediate, we need to */ - /* check if it's the right operand, otherwise we have */ - /* to change it, as CMP doesn't support immediate as */ - /* left operands. */ + /* check xCmp: try to avoid unordered cmp */ + if ((is_ia32_xCmp(irn) || is_ia32_xCmpCMov(irn) || is_ia32_xCmpSet(irn)) && + op_tp == ia32_Normal && + ! is_ia32_ImmConst(irn) && ! is_ia32_ImmSymConst(irn)) + { + long pnc = get_ia32_pncode(irn); + + if (pnc & pn_Cmp_Uo) { + ir_node *tmp; + int idx1 = 2, idx2 = 3; + + if (is_ia32_xCmpCMov(irn)) { + idx1 = 0; + idx2 = 1; + } + + tmp = get_irn_n(irn, idx1); + set_irn_n(irn, idx1, get_irn_n(irn, idx2)); + set_irn_n(irn, idx2, tmp); + + set_ia32_pncode(irn, get_negated_pnc(pnc, mode_D)); + } + } + + /* + If we have a CondJmp/CmpSet/xCmpSet with immediate, + we need to check if it's the right operand, otherwise + we have to change it, as CMP doesn't support immediate + as left operands. + */ +#if 0 if ((is_ia32_CondJmp(irn) || is_ia32_CmpSet(irn) || is_ia32_xCmpSet(irn)) && (is_ia32_ImmConst(irn) || is_ia32_ImmSymConst(irn)) && op_tp == ia32_AddrModeS) @@ -308,22 +352,136 @@ insert_copy: set_ia32_op_type(irn, ia32_AddrModeD); set_ia32_pncode(irn, get_inversed_pnc(get_ia32_pncode(irn))); } +#endif + } +end: ; +} - /* check if there is a sub which need to be transformed */ - ia32_transform_sub_to_neg_add(irn, cg); +/** + * Following Problem: + * We have a source address mode node with base or index register equal to + * result register. The constraint handler will insert a copy from the + * remaining input operand to the result register -> base or index is + * broken then. + * Solution: Turn back this address mode into explicit Load + Operation. + */ +static void fix_am_source(ir_node *irn, void *env) { + ia32_code_gen_t *cg = env; + ir_node *base, *index, *noreg; + const arch_register_t *reg_base, *reg_index; + const ia32_register_req_t **reqs; + int n_res, i; - /* transform a LEA into an Add if possible */ - ia32_transform_lea_to_add(irn, cg); - } -end: + /* check only ia32 nodes with source address mode */ + if (! is_ia32_irn(irn) || get_ia32_op_type(irn) != ia32_AddrModeS) + return; + /* no need to fix unary operations */ + if (get_irn_arity(irn) == 4) + return; + + base = get_irn_n(irn, 0); + index = get_irn_n(irn, 1); + + reg_base = arch_get_irn_register(cg->arch_env, base); + reg_index = arch_get_irn_register(cg->arch_env, index); + reqs = get_ia32_out_req_all(irn); + + noreg = ia32_new_NoReg_gp(cg); - /* check for peephole optimization */ - ia32_peephole_optimization(irn, cg); + n_res = get_ia32_n_res(irn); + + for (i = 0; i < n_res; i++) { + if (arch_register_req_is(&(reqs[i]->req), should_be_same)) { + /* get in and out register */ + const arch_register_t *out_reg = get_ia32_out_reg(irn, i); + + /* + there is a constraint for the remaining operand + and the result register is equal to base or index register + */ + if (reqs[i]->same_pos == 2 && + (REGS_ARE_EQUAL(out_reg, reg_base) || REGS_ARE_EQUAL(out_reg, reg_index))) + { + /* turn back address mode */ + ir_node *in_node = get_irn_n(irn, 2); + const arch_register_t *in_reg = arch_get_irn_register(cg->arch_env, in_node); + ir_node *block = get_nodes_block(irn); + ir_mode *ls_mode = get_ia32_ls_mode(irn); + ir_node *load; + int pnres; + + if (arch_register_get_class(in_reg) == &ia32_reg_classes[CLASS_ia32_gp]) { + load = new_rd_ia32_Load(NULL, cg->irg, block, base, index, get_irn_n(irn, 4)); + pnres = pn_ia32_Load_res; + } + else if (arch_register_get_class(in_reg) == &ia32_reg_classes[CLASS_ia32_xmm]) { + load = new_rd_ia32_xLoad(NULL, cg->irg, block, base, index, get_irn_n(irn, 4)); + pnres = pn_ia32_xLoad_res; + } + else { + assert(0 && "cannot turn back address mode for this register class"); + } + + /* copy address mode information to load */ + set_ia32_ls_mode(load, ls_mode); + set_ia32_am_flavour(load, get_ia32_am_flavour(irn)); + set_ia32_op_type(load, ia32_AddrModeS); + set_ia32_am_support(load, ia32_am_Source); + set_ia32_am_scale(load, get_ia32_am_scale(irn)); + set_ia32_am_sc(load, get_ia32_am_sc(irn)); + add_ia32_am_offs(load, get_ia32_am_offs(irn)); + set_ia32_frame_ent(load, get_ia32_frame_ent(irn)); + + if (is_ia32_use_frame(irn)) + set_ia32_use_frame(load); + + /* insert the load into schedule */ + sched_add_before(irn, load); + + DBG((cg->mod, LEVEL_3, "irg %+F: build back AM source for node %+F, inserted load %+F\n", cg->irg, irn, load)); + + load = new_r_Proj(cg->irg, block, load, ls_mode, pnres); + arch_set_irn_register(cg->arch_env, load, out_reg); + + /* insert the load result proj into schedule */ + sched_add_before(irn, load); + + /* set the new input operand */ + set_irn_n(irn, 3, load); + + /* this is a normal node now */ + set_irn_n(irn, 0, noreg); + set_irn_n(irn, 1, noreg); + set_ia32_op_type(irn, ia32_Normal); + + break; + } + } + } } static void ia32_finish_irg_walker(ir_node *block, void *env) { ir_node *irn, *next; + /* first: turn back AM source if necessary */ + for (irn = sched_first(block); ! sched_is_end(irn); irn = next) { + next = sched_next(irn); + fix_am_source(irn, env); + } + + for (irn = sched_first(block); ! sched_is_end(irn); irn = next) { + ia32_code_gen_t *cg = env; + + next = sched_next(irn); + + /* check if there is a sub which need to be transformed */ + ia32_transform_sub_to_neg_add(irn, cg); + + /* transform a LEA into an Add if possible */ + ia32_transform_lea_to_add(irn, cg); + } + + /* second: insert copies and finish irg */ for (irn = sched_first(block); ! sched_is_end(irn); irn = next) { next = sched_next(irn); ia32_finish_node(irn, env);