From: Matthias Braun Date: Thu, 28 Jun 2007 16:25:51 +0000 (+0000) Subject: rewrite and improve Cond transformation X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=d9b6f3a9505efb7dc1f692d2f7958a575532bdbf;p=libfirm rewrite and improve Cond transformation [r14821] --- diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 47160f898..ad6a9df2d 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -836,19 +836,10 @@ void emit_ia32_CondJmp(ia32_emit_env_t *env, const ir_node *node) { */ static void TestJmp_emitter(ia32_emit_env_t *env, const ir_node *node) { - if(is_ia32_ImmSymConst(node) || is_ia32_ImmConst(node)) { - be_emit_cstring(env, "\ttest "); - ia32_emit_immediate(env, node); - be_emit_cstring(env, ", "); - ia32_emit_source_register(env, node, 0); - be_emit_finish_line_gas(env, node); - } else { - be_emit_cstring(env, "\ttest "); - ia32_emit_source_register(env, node, 1); - be_emit_cstring(env, ", "); - ia32_emit_source_register(env, node, 0); - be_emit_finish_line_gas(env, node); - } + be_emit_cstring(env, "\ttest "); + ia32_emit_binop(env, node); + be_emit_finish_line_gas(env, node); + finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node)); } diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 0c30e8bbb..5a39bdf3d 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -771,8 +771,12 @@ Not => { CondJmp => { state => "pinned", op_flags => "L|X|Y", - reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], out => [ "none", "none"] }, + reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], + out => [ "none", "none"] }, + ins => [ "base", "index", "left", "right", "mem" ], outs => [ "false", "true" ], + attr => "long pnc", + init_attr => "attr->pn_code = pnc;", latency => 3, units => [ "BRANCH" ], }, @@ -780,8 +784,12 @@ CondJmp => { TestJmp => { state => "pinned", op_flags => "L|X|Y", - reg_req => { in => [ "gp", "gp" ], out => [ "none", "none" ] }, + reg_req => { in => [ "gp", "gp", "gp", "gp", "none" ], + out => [ "none", "none" ] }, + ins => [ "base", "index", "left", "right", "mem" ], outs => [ "false", "true" ], + attr => "long pnc", + init_attr => "attr->pn_code = pnc;", latency => 3, units => [ "BRANCH" ], }, @@ -807,6 +815,7 @@ SwitchJmp => { reg_req => { in => [ "gp" ], out => [ "none" ] }, latency => 3, units => [ "BRANCH" ], + mode => "mode_T", }, Const => { diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index 1221ce74a..bdeaf8ceb 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -1753,7 +1753,97 @@ static ir_node *gen_Store(ir_node *node) { return new_op; } +static ir_node *try_create_TestJmp(ir_node *node, long pnc) +{ + ir_node *cmp_a = get_Cmp_left(node); + ir_node *new_cmp_a; + ir_node *cmp_b = get_Cmp_right(node); + ir_node *new_cmp_b; + ir_node *and_left; + ir_node *and_right; + ir_node *res; + ir_node *block; + ir_node *noreg; + ir_node *nomem; + dbg_info *dbgi; + tarval *tv; + + if (pnc != pn_Cmp_Eq && pnc != pn_Cmp_Lg) + return NULL; + + if(!is_Const(cmp_b)) + return NULL; + + tv = get_Const_tarval(cmp_b); + if(!tarval_is_null(tv)) + return NULL; + if(!is_And(cmp_a)) + return NULL; + /* only fold if we're the only user of the And (it's not 100% clear that + * this is better, as we could have a series of Conds as users...) + */ + if(get_irn_n_edges(cmp_a) > 1) + return NULL; + + and_left = get_And_left(cmp_a); + and_right = get_And_right(cmp_a); + if(!is_Const(and_right)) + return NULL; + + dbgi = get_irn_dbg_info(node); + block = be_transform_node(get_nodes_block(node)); + noreg = ia32_new_NoReg_gp(env_cg); + nomem = new_NoMem(); + new_cmp_a = be_transform_node(and_left); + new_cmp_b = try_create_Immediate(and_right, 0); + if(new_cmp_b == NULL) + panic("couldn't create immediate for TestJmp"); + + res = new_rd_ia32_TestJmp(dbgi, current_ir_graph, block, noreg, noreg, + new_cmp_a, new_cmp_b, nomem, pnc); + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); + + return res; +} +static ir_node *create_Switch(ir_node *node) +{ + ir_graph *irg = current_ir_graph; + dbg_info *dbgi = get_irn_dbg_info(node); + ir_node *block = be_transform_node(get_nodes_block(node)); + ir_node *sel = get_Cond_selector(node); + ir_node *new_sel = be_transform_node(sel); + ir_node *res; + int switch_min = INT_MAX; + const ir_edge_t *edge; + + /* determine the smallest switch case value */ + foreach_out_edge(node, edge) { + ir_node *proj = get_edge_src_irn(edge); + int pn = get_Proj_proj(proj); + if(pn < switch_min) + switch_min = pn; + } + + if (switch_min != 0) { + ir_node *noreg = ia32_new_NoReg_gp(env_cg); + + /* if smallest switch case is not 0 we need an additional sub */ + new_sel = new_rd_ia32_Lea(dbgi, irg, block, new_sel, noreg); + add_ia32_am_offs_int(new_sel, -switch_min); + set_ia32_am_flavour(new_sel, ia32_am_OB); + set_ia32_op_type(new_sel, ia32_AddrModeS); + + SET_IA32_ORIG_NODE(new_sel, ia32_get_old_node_name(env_cg, node)); + } + + res = new_rd_ia32_SwitchJmp(dbgi, irg, block, new_sel); + set_ia32_pncode(res, get_Cond_defaultProj(node)); + + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); + + return res; +} /** * Transforms a Cond -> Proj[b] -> Cmp into a CondJmp, CondJmp_i or TestJmp @@ -1768,129 +1858,71 @@ static ir_node *gen_Cond(ir_node *node) { ir_mode *sel_mode = get_irn_mode(sel); ir_node *res = NULL; ir_node *noreg = ia32_new_NoReg_gp(env_cg); - ir_node *cnst, *expr; - - if (is_Proj(sel) && sel_mode == mode_b) { - ir_node *pred = get_Proj_pred(sel); - ir_node *cmp_a = get_Cmp_left(pred); - ir_node *new_cmp_a = be_transform_node(cmp_a); - ir_node *cmp_b = get_Cmp_right(pred); - ir_node *new_cmp_b = be_transform_node(cmp_b); - ir_mode *cmp_mode = get_irn_mode(cmp_a); - ir_node *nomem = new_NoMem(); - - int pnc = get_Proj_proj(sel); - if(mode_is_float(cmp_mode) || !mode_is_signed(cmp_mode)) { - pnc |= ia32_pn_Cmp_Unsigned; - } + ir_node *cmp; + ir_node *cmp_a; + ir_node *cmp_b; + ir_node *new_cmp_a; + ir_node *new_cmp_b; + ir_mode *cmp_mode; + ir_node *nomem = new_NoMem(); + long pnc; - /* check if we can use a CondJmp with immediate */ - cnst = (env_cg->opt & IA32_OPT_IMMOPS) ? get_immediate_op(new_cmp_a, new_cmp_b) : NULL; - expr = get_expr_op(new_cmp_a, new_cmp_b); + if (sel_mode != mode_b) { + return create_Switch(node); + } - if (cnst != NULL && expr != NULL) { - /* immop has to be the right operand, we might need to flip pnc */ - if(cnst != new_cmp_b) { - pnc = get_inversed_pnc(pnc); - } + cmp = get_Proj_pred(sel); + cmp_a = get_Cmp_left(cmp); + cmp_b = get_Cmp_right(cmp); + cmp_mode = get_irn_mode(cmp_a); + pnc = get_Proj_proj(sel); + if(mode_is_float(cmp_mode) || !mode_is_signed(cmp_mode)) { + pnc |= ia32_pn_Cmp_Unsigned; + } - if ((pnc == pn_Cmp_Eq || pnc == pn_Cmp_Lg) && mode_needs_gp_reg(get_irn_mode(expr))) { - if (get_ia32_immop_type(cnst) == ia32_ImmConst && - classify_tarval(get_ia32_Immop_tarval(cnst)) == TV_CLASSIFY_NULL) - { - /* a Cmp A =/!= 0 */ - ir_node *op1 = expr; - ir_node *op2 = expr; - int is_and = 0; - - /* check, if expr is an only once used And operation */ - if (is_ia32_And(expr) && get_irn_n_edges(expr)) { - op1 = get_irn_n(expr, 2); - op2 = get_irn_n(expr, 3); - - is_and = (is_ia32_ImmConst(expr) || is_ia32_ImmSymConst(expr)); - } - res = new_rd_ia32_TestJmp(dbgi, irg, block, op1, op2); - set_ia32_pncode(res, pnc); - - if (is_and) { - copy_ia32_Immop_attr(res, expr); - } - - SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); - return res; - } - } + if(mode_needs_gp_reg(cmp_mode)) { + res = try_create_TestJmp(cmp, pnc); + if(res != NULL) + return res; - if (mode_is_float(cmp_mode)) { - FP_USED(env_cg); - if (USE_SSE2(env_cg)) { - res = new_rd_ia32_xCondJmp(dbgi, irg, block, noreg, noreg, expr, noreg, nomem); - set_ia32_ls_mode(res, cmp_mode); - } else { - assert(0); - } - } - else { - assert(get_mode_size_bits(cmp_mode) == 32); - res = new_rd_ia32_CondJmp(dbgi, irg, block, noreg, noreg, expr, noreg, nomem); - } - copy_ia32_Immop_attr(res, cnst); - } - else { - ir_mode *cmp_mode = get_irn_mode(cmp_a); - - if (mode_is_float(cmp_mode)) { - FP_USED(env_cg); - if (USE_SSE2(env_cg)) { - res = new_rd_ia32_xCondJmp(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem); - set_ia32_ls_mode(res, cmp_mode); - } else { - ir_node *proj_eax; - res = new_rd_ia32_vfCondJmp(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem); - proj_eax = new_r_Proj(irg, block, res, mode_Iu, pn_ia32_vfCondJmp_temp_reg_eax); - be_new_Keep(&ia32_reg_classes[CLASS_ia32_gp], irg, block, 1, &proj_eax); - } - } - else { - assert(get_mode_size_bits(cmp_mode) == 32); - res = new_rd_ia32_CondJmp(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem); - set_ia32_commutative(res); - } + new_cmp_b = try_create_Immediate(cmp_b, 0); + if(new_cmp_b == NULL) { + new_cmp_b = be_transform_node(cmp_b); } - - set_ia32_pncode(res, pnc); - // Matze: disabled for now, because the default collect_spills_walker - // is not able to detect the mode of the spilled value - // moreover, the lea optimize phase freely exchanges left/right - // without updating the pnc - //set_ia32_am_support(res, ia32_am_Source | ia32_am_binary); + new_cmp_a = be_transform_node(cmp_a); + } else { + new_cmp_a = be_transform_node(cmp_a); + new_cmp_b = be_transform_node(cmp_b); } - else { - /* determine the smallest switch case value */ - ir_node *new_sel = be_transform_node(sel); - int switch_min = INT_MAX; - const ir_edge_t *edge; - - foreach_out_edge(node, edge) { - int pn = get_Proj_proj(get_edge_src_irn(edge)); - switch_min = pn < switch_min ? pn : switch_min; - } - if (switch_min) { - /* if smallest switch case is not 0 we need an additional sub */ - res = new_rd_ia32_Lea(dbgi, irg, block, new_sel, noreg); - SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); - add_ia32_am_offs_int(res, -switch_min); - set_ia32_am_flavour(res, ia32_am_OB); - set_ia32_op_type(res, ia32_AddrModeS); + if (mode_is_float(cmp_mode)) { + FP_USED(env_cg); + if (USE_SSE2(env_cg)) { + res = new_rd_ia32_xCondJmp(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem); + set_ia32_pncode(res, pnc); + set_ia32_ls_mode(res, cmp_mode); + } else { + ir_node *proj_eax; + res = new_rd_ia32_vfCondJmp(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem); + set_ia32_pncode(res, pnc); + proj_eax = new_r_Proj(irg, block, res, mode_Iu, pn_ia32_vfCondJmp_temp_reg_eax); + be_new_Keep(&ia32_reg_classes[CLASS_ia32_gp], irg, block, 1, &proj_eax); } - - res = new_rd_ia32_SwitchJmp(dbgi, irg, block, switch_min ? res : new_sel, mode_T); - set_ia32_pncode(res, get_Cond_defaultProj(node)); + } else { + assert(get_mode_size_bits(cmp_mode) == 32); + res = new_rd_ia32_CondJmp(dbgi, irg, block, noreg, noreg, + new_cmp_a, new_cmp_b, nomem, pnc); + set_ia32_commutative(res); } + // Matze: disabled for now, because the default collect_spills_walker + // is not able to detect the mode of the spilled value + // moreover, the lea optimize phase freely exchanges left/right + // without updating the pnc + //set_ia32_am_support(res, ia32_am_Source | ia32_am_binary); + SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node)); + return res; }