X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_finish.c;h=8b932c426d23d7481ac0869b3335cbf075544389;hb=205396c4f4f5abe7abd6dc2350c8c398a7623afc;hp=04b3f10b760e94ef6ea387f85907e426c5fb4c28;hpb=48071aea23fabc99044488d12757f274bc956fae;p=libfirm diff --git a/ir/be/ia32/ia32_finish.c b/ir/be/ia32/ia32_finish.c index 04b3f10b7..8b932c426 100644 --- a/ir/be/ia32/ia32_finish.c +++ b/ir/be/ia32/ia32_finish.c @@ -1,16 +1,22 @@ /** - * This file implements functions to finalize the irg for emit. - * @author Christian Wuerdig - * $Id$ + * @file + * @brief This file implements functions to finalize the irg for emit. + * @author Christian Wuerdig + * @version $Id$ */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include "irnode.h" #include "ircons.h" #include "irgmod.h" #include "irgwalk.h" +#include "iredges.h" #include "pdeq.h" +#include "error.h" -#include "../bearch.h" +#include "../bearch_t.h" #include "../besched_t.h" #include "../benode_t.h" @@ -23,20 +29,27 @@ #include "ia32_optimize.h" #include "gen_ia32_regalloc_if.h" +DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) + /** * Transforms a Sub or xSub into Neg--Add iff OUT_REG == SRC2_REG. * THIS FUNCTIONS MUST BE CALLED AFTER REGISTER ALLOCATION. */ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) { - ia32_transform_env_t tenv; + ir_graph *irg; ir_node *in1, *in2, *noreg, *nomem, *res; + ir_node *noreg_fp, *block; + ir_mode *mode = get_irn_mode(irn); + dbg_info *dbg = get_irn_dbg_info(irn); const arch_register_t *in1_reg, *in2_reg, *out_reg, **slots; + int i, arity; /* 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); + noreg_fp = ia32_new_NoReg_fp(cg); nomem = new_rd_NoMem(cg->irg); in1 = get_irn_n(irn, 2); in2 = get_irn_n(irn, 3); @@ -44,52 +57,63 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) { in2_reg = arch_get_irn_register(cg->arch_env, in2); out_reg = get_ia32_out_reg(irn, 0); - tenv.block = get_nodes_block(irn); - tenv.dbg = get_irn_dbg_info(irn); - tenv.irg = cg->irg; - tenv.irn = irn; - tenv.mode = get_ia32_res_mode(irn); - tenv.cg = cg; - DEBUG_ONLY(tenv.mod = cg->mod;) + irg = cg->irg; + block = get_nodes_block(irn); /* in case of sub and OUT == SRC2 we can transform the sequence into neg src2 -- add */ - if (REGS_ARE_EQUAL(out_reg, in2_reg)) { - /* generate the neg src2 */ - res = gen_Minus_ex(&tenv, in2); - 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 */ - if (mode_is_float(tenv.mode)) { - res = new_rd_ia32_xAdd(tenv.dbg, tenv.irg, tenv.block, noreg, noreg, res, in1, nomem); - set_ia32_am_support(res, ia32_am_Source); - } - else { - res = new_rd_ia32_Add(tenv.dbg, tenv.irg, tenv.block, noreg, noreg, res, in1, nomem); - set_ia32_am_support(res, ia32_am_Full); - set_ia32_commutative(res); - } - set_ia32_res_mode(res, tenv.mode); + if (!REGS_ARE_EQUAL(out_reg, in2_reg)) + return; - SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(tenv.cg, irn)); - /* copy register */ - slots = get_ia32_slots(res); - slots[0] = in2_reg; + /* generate the neg src2 */ + if(mode_is_float(mode)) { + int size; + ir_entity *entity; + + res = new_rd_ia32_xXor(dbg, irg, block, noreg, noreg, in2, noreg_fp, nomem); + size = get_mode_size_bits(mode); + entity = ia32_gen_fp_known_const(size == 32 ? ia32_SSIGN : ia32_DSIGN); + set_ia32_am_sc(res, entity); + set_ia32_op_type(res, ia32_AddrModeS); + set_ia32_ls_mode(res, get_ia32_ls_mode(irn)); + } else { + res = new_rd_ia32_Neg(dbg, irg, block, noreg, noreg, in2, nomem); + } + arch_set_irn_register(cg->arch_env, res, in2_reg); - /* add to schedule */ - sched_add_before(irn, res); + /* add to schedule */ + sched_add_before(irn, res); - /* remove the old sub */ - sched_remove(irn); + /* generate the add */ + if (mode_is_float(mode)) { + res = new_rd_ia32_xAdd(dbg, irg, block, noreg, noreg, res, in1, nomem); + set_ia32_am_support(res, ia32_am_Source); + set_ia32_ls_mode(res, get_ia32_ls_mode(irn)); + } + else { + res = new_rd_ia32_Add(dbg, irg, block, noreg, noreg, res, in1, nomem); + set_ia32_am_support(res, ia32_am_Full); + set_ia32_commutative(res); + } - DBG_OPT_SUB2NEGADD(irn, res); + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, irn)); + /* copy register */ + slots = get_ia32_slots(res); + slots[0] = in2_reg; + + /* exchange the add and the sub */ + edges_reroute(irn, res, irg); + + /* add to schedule */ + sched_add_before(irn, res); - /* exchange the add and the sub */ - exchange(irn, res); + /* remove the old sub */ + sched_remove(irn); + arity = get_irn_arity(irn); + for(i = 0; i < arity; ++i) { + set_irn_n(irn, i, new_Bad()); } + + DBG_OPT_SUB2NEGADD(irn, res); } /** @@ -99,10 +123,12 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) { static void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) { ia32_am_flavour_t am_flav; int imm = 0; + dbg_info *dbg = get_irn_dbg_info(irn); + ir_graph *irg; ir_node *res = NULL; ir_node *nomem, *noreg, *base, *index, *op1, *op2; - char *offs; - ia32_transform_env_t tenv; + ir_node *block; + int offs = 0; const arch_register_t *out_reg, *base_reg, *index_reg; /* must be a LEA */ @@ -111,7 +137,8 @@ static void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) { am_flav = get_ia32_am_flavour(irn); - if (get_ia32_am_sc(irn)) + /* mustn't have a symconst */ + if (get_ia32_am_sc(irn) != NULL || get_ia32_frame_ent(irn) != NULL) return; /* only some LEAs can be transformed to an Add */ @@ -125,23 +152,16 @@ 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); - - /* offset has a explicit sign -> we need to skip + */ - if (offs && offs[0] == '+') - offs++; + if (am_flav & ia32_O) { + offs = get_ia32_am_offs_int(irn); + } out_reg = arch_get_irn_register(cg->arch_env, irn); base_reg = arch_get_irn_register(cg->arch_env, base); index_reg = arch_get_irn_register(cg->arch_env, index); - tenv.block = get_nodes_block(irn); - tenv.dbg = get_irn_dbg_info(irn); - tenv.irg = cg->irg; - tenv.irn = irn; - DEBUG_ONLY(tenv.mod = cg->mod;) - tenv.mode = get_irn_mode(irn); - tenv.cg = cg; + irg = cg->irg; + block = get_nodes_block(irn); switch(get_ia32_am_flavour(irn)) { case ia32_am_B: @@ -185,15 +205,14 @@ static void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) { break; } - res = new_rd_ia32_Add(tenv.dbg, tenv.irg, tenv.block, noreg, noreg, op1, op2, nomem); + res = new_rd_ia32_Add(dbg, irg, block, noreg, noreg, op1, op2, nomem); arch_set_irn_register(cg->arch_env, res, out_reg); set_ia32_op_type(res, ia32_Normal); set_ia32_commutative(res); - set_ia32_res_mode(res, tenv.mode); if (imm) { - set_ia32_cnst(res, offs); - set_ia32_immop_type(res, ia32_ImmConst); + tarval *tv = new_tarval_from_long(offs, mode_Iu); + set_ia32_Immop_tarval(res, tv); } SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, irn)); @@ -203,11 +222,6 @@ static void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) { DBG_OPT_LEA2ADD(irn, res); - res = new_rd_Proj(tenv.dbg, tenv.irg, tenv.block, res, tenv.mode, pn_ia32_Add_res); - - /* add result Proj to schedule */ - sched_add_before(irn, res); - /* remove the old LEA */ sched_remove(irn); @@ -221,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); } @@ -231,7 +246,7 @@ static INLINE int need_constraint_copy(ir_node *irn) { */ static void ia32_finish_node(ir_node *irn, void *env) { ia32_code_gen_t *cg = env; - const ia32_register_req_t **reqs; + const arch_register_req_t **reqs; const arch_register_t *out_reg, *in_reg, *in2_reg; int n_res, i; ir_node *copy, *in_node, *block, *in2_node; @@ -251,10 +266,12 @@ static void ia32_finish_node(ir_node *irn, void *env) { if ((op_tp == ia32_Normal || op_tp == ia32_AddrModeS) && need_constraint_copy(irn)) { for (i = 0; i < n_res; i++) { - if (arch_register_req_is(&(reqs[i]->req), should_be_same)) { + if (arch_register_req_is(reqs[i], should_be_same)) { + int same_pos = reqs[i]->other_same; + /* get in and out register */ out_reg = get_ia32_out_reg(irn, i); - in_node = get_irn_n(irn, reqs[i]->same_pos); + in_node = get_irn_n(irn, same_pos); in_reg = arch_get_irn_register(cg->arch_env, in_node); /* don't copy ignore nodes */ @@ -267,19 +284,19 @@ static void ia32_finish_node(ir_node *irn, void *env) { /* beware: the current op could be everything, so test for ia32 */ /* commutativity first before getting the second in */ if (is_ia32_commutative(irn)) { - in2_node = get_irn_n(irn, reqs[i]->same_pos ^ 1); + in2_node = get_irn_n(irn, same_pos ^ 1); in2_reg = arch_get_irn_register(cg->arch_env, in2_node); if (REGS_ARE_EQUAL(out_reg, in2_reg)) { - set_irn_n(irn, reqs[i]->same_pos, in2_node); - set_irn_n(irn, reqs[i]->same_pos ^ 1, in_node); + set_irn_n(irn, same_pos, in2_node); + set_irn_n(irn, same_pos ^ 1, in_node); } else goto insert_copy; } else { insert_copy: - DBG((cg->mod, LEVEL_1, "inserting copy for %+F in_pos %d\n", irn, reqs[i]->same_pos)); + DBG((dbg, LEVEL_1, "inserting copy for %+F in_pos %d\n", irn, same_pos)); /* create copy from in register */ copy = be_new_Copy(arch_register_get_class(in_reg), cg->irg, block, in_node); @@ -292,7 +309,7 @@ insert_copy: sched_add_before(irn, copy); /* set copy as in */ - set_irn_n(irn, reqs[i]->same_pos, copy); + set_irn_n(irn, same_pos, copy); } } } @@ -319,23 +336,9 @@ insert_copy: 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)); + set_ia32_pncode(irn, get_negated_pnc(pnc, mode_E)); } } - - /* - 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 ((is_ia32_CondJmp(irn) || is_ia32_CmpSet(irn) || is_ia32_xCmpSet(irn)) && - (is_ia32_ImmConst(irn) || is_ia32_ImmSymConst(irn)) && - op_tp == ia32_AddrModeS) - { - set_ia32_op_type(irn, ia32_AddrModeD); - set_ia32_pncode(irn, get_inversed_pnc(get_ia32_pncode(irn))); - } } end: ; } @@ -352,12 +355,15 @@ 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; + const arch_register_req_t **reqs; int n_res, i; /* 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); @@ -371,15 +377,16 @@ static void fix_am_source(ir_node *irn, void *env) { 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)) { + if (arch_register_req_is(reqs[i], should_be_same)) { /* get in and out register */ const arch_register_t *out_reg = get_ia32_out_reg(irn, i); + int same_pos = reqs[i]->other_same; /* 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 && + if (same_pos == 2 && (REGS_ARE_EQUAL(out_reg, reg_base) || REGS_ARE_EQUAL(out_reg, reg_index))) { /* turn back address mode */ @@ -399,7 +406,7 @@ static void fix_am_source(ir_node *irn, void *env) { pnres = pn_ia32_xLoad_res; } else { - assert(0 && "cannot turn back address mode for this register class"); + panic("cannot turn back address mode for this register class"); } /* copy address mode information to load */ @@ -409,7 +416,7 @@ static void fix_am_source(ir_node *irn, void *env) { 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)); + add_ia32_am_offs_int(load, get_ia32_am_offs_int(irn)); set_ia32_frame_ent(load, get_ia32_frame_ent(irn)); if (is_ia32_use_frame(irn)) @@ -418,7 +425,7 @@ static void fix_am_source(ir_node *irn, void *env) { /* 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)); + DBG((dbg, 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); @@ -451,18 +458,14 @@ static void ia32_finish_irg_walker(ir_node *block, void *env) { for (irn = sched_first(block); ! sched_is_end(irn); irn = next) { ia32_code_gen_t *cg = env; - next = sched_next(irn); - if (is_ia32_irn(irn)) { - /* check if there is a sub which need to be transformed */ - ia32_transform_sub_to_neg_add(irn, cg); + next = sched_next(irn); - /* transform a LEA into an Add if possible */ - ia32_transform_lea_to_add(irn, cg); + /* check if there is a sub which need to be transformed */ + ia32_transform_sub_to_neg_add(irn, cg); - /* check for peephole optimization */ - ia32_peephole_optimization(irn, cg); - } + /* transform a LEA into an Add if possible */ + ia32_transform_lea_to_add(irn, cg); } /* second: insert copies and finish irg */ @@ -493,3 +496,8 @@ void ia32_finish_irg(ir_graph *irg, ia32_code_gen_t *cg) { } del_waitq(wq); } + +void ia32_init_finish(void) +{ + FIRM_DBG_REGISTER(dbg, "firm.be.ia32.finish"); +}