From: Christian Würdig Date: Fri, 10 Mar 2006 15:01:48 +0000 (+0000) Subject: fixed frame entity handling in am optimizer X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=2dc3473c46d1efa35c6014599374aa8cafc2bfe2;p=libfirm fixed frame entity handling in am optimizer fixed some bugs --- diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index 8a0cab03e..87c6d43a7 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -213,7 +213,7 @@ static void ia32_set_stack_bias(const void *self, ir_node *irn, int bias) { char buf[64]; const ia32_irn_ops_t *ops = self; - if (is_ia32_use_frame(irn)) { + if (is_ia32_use_frame(irn) && bias != 0) { ia32_am_flavour_t am_flav = get_ia32_am_flavour(irn); DBG((ops->cg->mod, LEVEL_1, "stack biased %+F with %d\n", irn, bias)); @@ -265,8 +265,11 @@ static void ia32_prepare_graph(void *self) { dump_ir_block_graph_sched(cg->irg, "-transformed"); edges_deactivate(cg->irg); edges_activate(cg->irg); - irg_walk_blkwise_graph(cg->irg, NULL, ia32_optimize_am, cg); - dump_ir_block_graph_sched(cg->irg, "-am"); + + if (cg->opt.doam) { + irg_walk_blkwise_graph(cg->irg, NULL, ia32_optimize_am, cg); + dump_ir_block_graph_sched(cg->irg, "-am"); + } } @@ -528,6 +531,12 @@ static void *ia32_cg_init(FILE *F, const be_irg_t *birg) { cg->tv_ent = pmap_create(); cg->birg = birg; + /* set optimizations */ + cg->opt.incdec = 0; + cg->opt.doam = 1; + cg->opt.placecnst = 1; + cg->opt.immops = 1; + isa->num_codegens++; if (isa->num_codegens > 1) @@ -660,7 +669,7 @@ void ia32_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *ab int i, ignore; ir_mode **modes; const arch_register_t *reg; - be_abi_call_flags_t call_flags = { 0, 0, 0, 0, 1 }; + be_abi_call_flags_t call_flags = { 0, 0, 1, 0, 1 }; /* get the between type and the frame pointer save entity */ between_type = get_between_type(); diff --git a/ir/be/ia32/bearch_ia32_t.h b/ir/be/ia32/bearch_ia32_t.h index 1ff141abf..5cf21fa32 100644 --- a/ir/be/ia32/bearch_ia32_t.h +++ b/ir/be/ia32/bearch_ia32_t.h @@ -8,6 +8,13 @@ /* some typedefs */ +typedef struct _ia32_optimize_t { + unsigned incdec : 1; /**< optimize add/sub 1/-1 to inc/dec */ + unsigned doam : 1; /**< do address mode optimizations */ + unsigned placecnst : 1; /**< place constants in the blocks where they are used */ + unsigned immops : 1; /**< create operations with immediates */ +} ia32_optimize_t; + typedef struct _ia32_code_gen_t { const arch_code_generator_if_t *impl; /**< implementation */ ir_graph *irg; /**< current irg */ @@ -19,6 +26,7 @@ typedef struct _ia32_code_gen_t { pmap *types; /**< A map of modes to primitive types */ pmap *tv_ent; /**< A map of entities that store tarvals */ const be_irg_t *birg; /**< The be-irg (contains additional information about the irg) */ + ia32_optimize_t opt; /**< contains optimization information */ } ia32_code_gen_t; typedef struct _ia32_isa_t { diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index f24e922c1..13302d5ae 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -234,22 +234,6 @@ static const arch_register_t *get_out_reg(const ir_node *irn, int pos) { return reg; } -/** - * Returns the number of the in register at position pos. - */ -int get_ia32_reg_nr(ir_node *irn, int pos, int in_out) { - const arch_register_t *reg; - - if (in_out == 1) { - reg = get_in_reg(irn, pos); - } - else { - reg = get_out_reg(irn, pos); - } - - return arch_register_get_index(reg); -} - enum io_direction { IN_REG, OUT_REG @@ -266,7 +250,7 @@ static const char *get_ia32_reg_name(ir_node *irn, int pos, enum io_direction in } else { /* destination address mode nodes don't have outputs */ - if (get_ia32_op_type(irn) == ia32_AddrModeD) { + if (is_ia32_irn(irn) && get_ia32_op_type(irn) == ia32_AddrModeD) { return "MEM"; } @@ -786,6 +770,23 @@ void emit_be_IncSP(const ir_node *irn, emit_env_t *emit_env) { } } +void emit_be_SetSP(const ir_node *irn, emit_env_t *emit_env) { + FILE *F = emit_env->out; + + lc_efprintf(ia32_get_arg_env(), F, "\tmov %1D,%3S\t\t\t/* restore SP */\n", irn, irn); +} + +void emit_be_Copy(const ir_node *irn, emit_env_t *emit_env) { + FILE *F = emit_env->out; + + lc_efprintf(ia32_get_arg_env(), F, "\tmov %1D,%1S\t\t\t/* %+F */\n", irn, irn, irn); +} + +void emit_be_Perm(const ir_node *irn, emit_env_t *emit_env) { + FILE *F = emit_env->out; + + lc_efprintf(ia32_get_arg_env(), F, "\txchg %1S, %2S\t\t\t/* %+F(%1A, %2A) */\n", irn, irn, irn); +} /*********************************************************************************** * _ __ _ @@ -822,6 +823,9 @@ static void ia32_register_emitters(void) { /* benode emitter */ BE_EMIT(Call); BE_EMIT(IncSP); + BE_EMIT(SetSP); + BE_EMIT(Copy); + BE_EMIT(Perm); /* firm emitter */ EMIT(Jmp); diff --git a/ir/be/ia32/ia32_optimize.c b/ir/be/ia32/ia32_optimize.c index 376b327ee..a0a9c5cf7 100644 --- a/ir/be/ia32/ia32_optimize.c +++ b/ir/be/ia32/ia32_optimize.c @@ -193,6 +193,11 @@ void ia32_place_consts(ir_node *irn, void *env) { tenv.block = get_Block_cfgpred_block(get_nodes_block(irn), i); } + /* put the const into the block where the original const was */ + if (! cg->opt.placecnst) { + tenv.block = get_nodes_block(pred); + } + switch (opc) { case iro_Const: cnst = gen_Const(&tenv); @@ -316,6 +321,62 @@ static int pred_is_specific_nodeblock(const ir_node *bl, const ir_node *pred, return 0; } +/** + * Checks if irn is a candidate for address calculation or address mode. + * + * address calculation (AC): + * - none of the operand must be a Load within the same block OR + * - all Loads must have more than one user OR + * - the irn has a frame entity (it's a former FrameAddr) + * + * address mode (AM): + * - at least one operand has to be a Load within the same block AND + * - the load must not have other users than the irn AND + * - the irn must not have a frame entity set + * + * @param block The block the Loads must/not be in + * @param irn The irn to check + * @param check_addr 1 if to check for address calculation, 0 otherwise + * return 1 if irn is a candidate for AC or AM, 0 otherwise + */ +static int is_candidate(const ir_node *block, const ir_node *irn, int check_addr) { + ir_node *load_proj; + int n, is_cand = check_addr; + + if (pred_is_specific_nodeblock(block, get_irn_n(irn, 2), is_ia32_Load)) { + load_proj = get_irn_n(irn, 2); + n = ia32_get_irn_n_edges(load_proj); + is_cand = check_addr ? (n == 1 ? 0 : is_cand) : (n == 1 ? 1 : is_cand); + } + + if (pred_is_specific_nodeblock(block, get_irn_n(irn, 3), is_ia32_Load)) { + load_proj = get_irn_n(irn, 3); + n = ia32_get_irn_n_edges(load_proj); + is_cand = check_addr ? (n == 1 ? 0 : is_cand) : (n == 1 ? 1 : is_cand); + } + + is_cand = get_ia32_frame_ent(irn) ? (check_addr ? 1 : 0) : (check_addr ? 0 : 1); + + return is_cand; +} + +/** + * Compares the base and index addr and the load/store entities + * and returns 1 if they are equal. + */ +static int load_store_addr_is_equal(const ir_node *load, const ir_node *store, + const ir_node *addr_b, const ir_node *addr_i) +{ + int is_equal = (addr_b == get_irn_n(load, 0)) && (addr_i == get_irn_n(load, 1)); + entity *lent = get_ia32_frame_ent(load); + entity *sent = get_ia32_frame_ent(store); + + /* are both entities set and equal? */ + is_equal = (lent && sent && (lent == sent)) ? 1 : is_equal; + + return is_equal; +} + /** * Folds Add or Sub to LEA if possible */ @@ -451,7 +512,9 @@ static ir_node *fold_addr(be_abi_irg_t *babi, ir_node *irn, firm_dbg_module_t *m /* If we have an Add with a real right operand (not NoReg) and */ /* the LEA contains already an index calculation then we create */ /* a new LEA. */ - if (isadd && !be_is_NoReg(babi, index) && (am_flav & ia32_am_I)) { + /* If the LEA contains already a frame_entity then we also */ + /* create a new one otherwise we would loose it. */ + if (isadd && ((!be_is_NoReg(babi, index) && (am_flav & ia32_am_I)) || get_ia32_frame_ent(left))) { DBG((mod, LEVEL_1, "\tleave old LEA, creating new one\n")); } else { @@ -495,6 +558,13 @@ static ir_node *fold_addr(be_abi_irg_t *babi, ir_node *irn, firm_dbg_module_t *m } } + /* copy the frame entity (could be set in case of Add */ + /* which was a FrameAddr) */ + set_ia32_frame_ent(res, get_ia32_frame_ent(irn)); + + if (is_ia32_use_frame(irn)) + set_ia32_use_frame(res); + /* set scale */ set_ia32_am_scale(res, scale); @@ -574,9 +644,8 @@ void ia32_optimize_am(ir_node *irn, void *env) { right = get_irn_n(irn, 3); /* Do not try to create a LEA if one of the operands is a Load. */ - if (! pred_is_specific_nodeblock(block, left, is_ia32_Load) && - ! pred_is_specific_nodeblock(block, right, is_ia32_Load)) - { + /* check is irn is a candidate for address calculation */ + if (is_candidate(block, irn, 1)) { res = fold_addr(babi, irn, mod, noreg_gp); } } @@ -615,10 +684,8 @@ void ia32_optimize_am(ir_node *irn, void *env) { set_irn_n(irn, 1, get_irn_n(left, 1)); } } - /* check if at least one operand is a Load */ - else if (pred_is_specific_nodeblock(block, get_irn_n(irn, 2), is_ia32_Ld) || - pred_is_specific_nodeblock(block, get_irn_n(irn, 3), is_ia32_Ld)) - { + /* check if the node is an address mode candidate */ + else if (is_candidate(block, irn, 0)) { left = get_irn_n(irn, 2); if (get_irn_arity(irn) == 4) { /* it's an "unary" operation */ @@ -711,8 +778,7 @@ void ia32_optimize_am(ir_node *irn, void *env) { load = get_Proj_pred(right); /* Compare Load and Store address */ - if ((addr_b == get_irn_n(load, 0)) && (addr_i == get_irn_n(load, 1))) - { + if (load_store_addr_is_equal(load, store, addr_b, addr_i)) { /* Right Load is from same address, so we can */ /* disconnect the Load and Store here */ @@ -723,6 +789,11 @@ void ia32_optimize_am(ir_node *irn, void *env) { set_ia32_am_scale(irn, get_ia32_am_scale(load)); set_ia32_am_flavour(irn, get_ia32_am_flavour(load)); set_ia32_op_type(irn, ia32_AddrModeD); + set_ia32_frame_ent(irn, get_ia32_frame_ent(load)); + set_ia32_ls_mode(irn, get_ia32_ls_mode(load)); + + if (is_ia32_use_frame(load)) + set_ia32_use_frame(irn); /* connect to Load memory and disconnect Load */ if (get_irn_arity(irn) == 5) { @@ -786,6 +857,11 @@ void ia32_optimize_am(ir_node *irn, void *env) { set_ia32_am_scale(irn, get_ia32_am_scale(left)); set_ia32_am_flavour(irn, get_ia32_am_flavour(left)); set_ia32_op_type(irn, ia32_AddrModeS); + set_ia32_frame_ent(irn, get_ia32_frame_ent(left)); + set_ia32_ls_mode(irn, get_ia32_ls_mode(left)); + + if (is_ia32_use_frame(left)) + set_ia32_use_frame(irn); /* connect to Load memory */ if (get_irn_arity(irn) == 5) { diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index c325933c9..f79180677 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -360,7 +360,14 @@ $arch = "ia32"; "comment" => "represents an integer constant", "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "out" => [ "gp" ] }, - "emit" => '. mov %D1, %C\t\t\t/* Mov Const into register */', + "emit" => +' if (get_ia32_Immop_tarval(n) == get_tarval_null(get_irn_mode(n))) { +4. sub %D1, %D1\t\t\t/* optimized mov 0 to register */ + } + else { +4. mov %D1, %C\t\t\t/* Mov Const into register */ + } +', }, "Cdq" => { diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index a56b87926..994b02000 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -183,8 +183,13 @@ static ir_node *gen_binop(ia32_transform_env_t *env, ir_node *op1, ir_node *op2, ir_node *expr_op, *imm_op; - /* check if it's an operation with immediate */ - if (is_op_commutative(get_irn_op(env->irn))) { + /* Check if immediate optimization is on and */ + /* if it's an operation with immediate. */ + if (! env->cg->opt.immops) { + expr_op = op1; + imm_op = NULL; + } + else if (is_op_commutative(get_irn_op(env->irn))) { imm_op = get_immediate_op(op1, op2); expr_op = get_expr_op(op1, op2); } @@ -263,7 +268,9 @@ static ir_node *gen_shift_binop(ia32_transform_env_t *env, ir_node *op1, ir_node assert(! mode_is_float(mode) && "Shift/Rotate with float not supported"); - imm_op = get_immediate_op(NULL, op2); + /* Check if immediate optimization is on and */ + /* if it's an operation with immediate. */ + imm_op = env->cg->opt.immops ? get_immediate_op(NULL, op2) : NULL; expr_op = get_expr_op(op1, op2); assert((expr_op || imm_op) && "invalid operands"); @@ -357,8 +364,8 @@ static ir_node *gen_imm_Add(ia32_transform_env_t *env, ir_node *expr_op, ir_node int normal_add = 1; tarval_classification_t class_tv, class_negtv; - /* const_op: tarval or SymConst? */ - if (tv) { + /* try to optimize to inc/dec */ + if (env->cg->opt.incdec && tv) { /* optimize tarvals */ class_tv = classify_tarval(tv); class_negtv = classify_tarval(tarval_neg(tv)); @@ -403,7 +410,9 @@ static ir_node *gen_Add(ia32_transform_env_t *env, ir_node *op1, ir_node *op2) { ir_node *nomem = new_NoMem(); ir_node *expr_op, *imm_op; - imm_op = get_immediate_op(op1, op2); + /* Check if immediate optimization is on and */ + /* if it's an operation with immediate. */ + imm_op = env->cg->opt.immops ? get_immediate_op(op1, op2) : NULL; expr_op = get_expr_op(op1, op2); assert((expr_op || imm_op) && "invalid operands"); @@ -643,8 +652,8 @@ static ir_node *gen_imm_Sub(ia32_transform_env_t *env, ir_node *expr_op, ir_node int normal_sub = 1; tarval_classification_t class_tv, class_negtv; - /* const_op: tarval or SymConst? */ - if (tv) { + /* try to optimize to inc/dec */ + if (env->cg->opt.incdec && tv) { /* optimize tarvals */ class_tv = classify_tarval(tv); class_negtv = classify_tarval(tarval_neg(tv)); @@ -687,7 +696,9 @@ static ir_node *gen_Sub(ia32_transform_env_t *env, ir_node *op1, ir_node *op2) { ir_node *nomem = new_NoMem(); ir_node *expr_op, *imm_op; - imm_op = get_immediate_op(NULL, op2); + /* Check if immediate optimization is on and */ + /* if it's an operation with immediate. */ + imm_op = env->cg->opt.immops ? get_immediate_op(NULL, op2) : NULL; expr_op = get_expr_op(op1, op2); assert((expr_op || imm_op) && "invalid operands"); @@ -1201,7 +1212,7 @@ static ir_node *gen_Cond(ia32_transform_env_t *env) { cmp_b = get_Cmp_right(pred); /* check if we can use a CondJmp with immediate */ - cnst = get_immediate_op(cmp_a, cmp_b); + cnst = env->cg->opt.immops ? get_immediate_op(cmp_a, cmp_b) : NULL; expr = get_expr_op(cmp_a, cmp_b); if (cnst && expr) { @@ -1247,7 +1258,7 @@ static ir_node *gen_CopyB(ia32_transform_env_t *env) { /* If we have to copy more than 16 bytes, we use REP MOVSx and */ /* then we need the size explicitly in ECX. */ - if (size >= 16) { + if (size >= 16 * 4) { rem = size & 0x3; /* size % 4 */ size >>= 2; @@ -1275,7 +1286,7 @@ static ir_node *gen_CopyB(ia32_transform_env_t *env) { * @return The transformed node. */ static ir_node *gen_Mux(ia32_transform_env_t *env) { - ir_node *node = env->irn; + ir_node *node = env->irn; return new_rd_ia32_CMov(env->dbg, env->irg, env->block, get_Mux_sel(node), get_Mux_false(node), get_Mux_true(node), env->mode); @@ -1293,19 +1304,28 @@ static ir_node *gen_Mux(ia32_transform_env_t *env) { * ********************************************/ -static ir_node *gen_FrameAddr(ia32_transform_env_t *tenv) { +static ir_node *gen_FrameAddr(ia32_transform_env_t *env) { ir_node *new_op = NULL; + ir_node *node = env->irn; + ir_node *op = get_irn_n(node, 0); + ir_node *noreg = ia32_new_NoReg_gp(env->cg); + ir_node *nomem = new_rd_NoMem(env->irg); - return new_op; + new_op = new_rd_ia32_Add(env->dbg, env->irg, env->block, noreg, noreg, op, noreg, nomem, mode_T); + set_ia32_frame_ent(new_op, be_get_frame_entity(node)); + set_ia32_am_support(new_op, ia32_am_Full); + set_ia32_use_frame(new_op); + + return new_rd_Proj(env->dbg, env->irg, env->block, new_op, env->mode, 0); } -static ir_node *gen_FrameLoad(ia32_transform_env_t *tenv) { +static ir_node *gen_FrameLoad(ia32_transform_env_t *env) { ir_node *new_op = NULL; return new_op; } -static ir_node *gen_FrameStore(ia32_transform_env_t *tenv) { +static ir_node *gen_FrameStore(ia32_transform_env_t *env) { ir_node *new_op = NULL; return new_op;