X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_finish.c;h=1e62ce5caa6d811a42cf7e49a553cc5fa6aac9bb;hb=bd734c8925a048face4e8420228eb2deb3fc2154;hp=b7f24039315248ea6d47f9988735fa4d46e1c5a1;hpb=fc81b817119d8635eaeb345c8623255fc51bdb22;p=libfirm diff --git a/ir/be/ia32/ia32_finish.c b/ir/be/ia32/ia32_finish.c index b7f240393..1e62ce5ca 100644 --- a/ir/be/ia32/ia32_finish.c +++ b/ir/be/ia32/ia32_finish.c @@ -21,7 +21,6 @@ * @file * @brief This file implements functions to finalize the irg for emit. * @author Christian Wuerdig - * @version $Id$ */ #include "config.h" @@ -34,9 +33,9 @@ #include "pdeq.h" #include "error.h" -#include "../bearch.h" -#include "../besched.h" -#include "../benode.h" +#include "bearch.h" +#include "besched.h" +#include "benode.h" #include "bearch_ia32_t.h" #include "ia32_finish.h" @@ -73,7 +72,7 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn) in2 = get_irn_n(irn, n_ia32_binary_right); in1_reg = arch_get_irn_register(in1); in2_reg = arch_get_irn_register(in2); - out_reg = arch_irn_get_register(irn, 0); + out_reg = arch_get_irn_register_out(irn, 0); if (out_reg == in1_reg) return; @@ -108,54 +107,29 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn) /* generate the add */ res = new_bd_ia32_xAdd(dbgi, block, noreg, noreg, nomem, res, in1); set_ia32_ls_mode(res, get_ia32_ls_mode(irn)); - - /* exchange the add and the sub */ - edges_reroute(irn, res); - - /* add to schedule */ - sched_add_before(irn, res); } else { - ir_node *res_proj = NULL; - ir_node *flags_proj = NULL; - const ir_edge_t *edge; + ir_node *flags_proj = NULL; + ir_node *carry; if (get_irn_mode(irn) == mode_T) { /* collect the Proj uses */ foreach_out_edge(irn, edge) { ir_node *proj = get_edge_src_irn(edge); long pn = get_Proj_proj(proj); - if (pn == pn_ia32_Sub_res) { - assert(res_proj == NULL); - res_proj = proj; - } else { - assert(pn == pn_ia32_Sub_flags); + if (pn == pn_ia32_flags) { assert(flags_proj == NULL); flags_proj = proj; + break; } } } - if (flags_proj == NULL) { - res = new_bd_ia32_Neg(dbgi, block, in2); - arch_set_irn_register(res, in2_reg); - - /* add to schedule */ - sched_add_before(irn, res); - - /* generate the add */ - res = new_bd_ia32_Add(dbgi, block, noreg, noreg, nomem, res, in1); - arch_set_irn_register(res, out_reg); - set_ia32_commutative(res); - - /* exchange the add and the sub */ - edges_reroute(irn, res); - - /* add to schedule */ - sched_add_before(irn, res); - } else { - ir_node *stc, *cmc, *nnot, *adc; - ir_node *adc_flags; - + if (is_ia32_Sbb(irn)) { + /* Feed borrow (in CF) as carry (via CMC) into NOT+ADC. */ + carry = get_irn_n(irn, n_ia32_Sbb_eflags); + carry = new_bd_ia32_Cmc(dbgi, block, carry); + goto carry; + } else if (flags_proj != 0) { /* * ARG, the above technique does NOT set the flags right. * So, we must produce the following code: @@ -163,38 +137,57 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn) * t2 = a + ~b + Carry * Complement Carry * - * a + -b = a + (~b + 1) would set the carry flag IF a == b ... + * a + -b = a + (~b + 1) would set the carry flag wrong IFF both a and b are zero. */ + ir_node *cmc; + ir_node *nnot; + ir_node *adc; + ir_node *adc_flags; + + carry = new_bd_ia32_Stc(dbgi, block); + +carry: nnot = new_bd_ia32_Not(dbgi, block, in2); arch_set_irn_register(nnot, in2_reg); sched_add_before(irn, nnot); - stc = new_bd_ia32_Stc(dbgi, block); - arch_set_irn_register(stc, &ia32_registers[REG_EFLAGS]); - sched_add_before(irn, stc); + arch_set_irn_register(carry, &ia32_registers[REG_EFLAGS]); + sched_add_before(irn, carry); - adc = new_bd_ia32_Adc(dbgi, block, noreg, noreg, nomem, nnot, in1, stc); + adc = new_bd_ia32_Adc(dbgi, block, noreg, noreg, nomem, nnot, in1, carry); arch_set_irn_register(adc, out_reg); - sched_add_before(irn, adc); + set_ia32_commutative(adc); - set_irn_mode(adc, mode_T); - adc_flags = new_r_Proj(adc, mode_Iu, pn_ia32_Adc_flags); - arch_set_irn_register(adc_flags, &ia32_registers[REG_EFLAGS]); + if (flags_proj != NULL) { + set_irn_mode(adc, mode_T); + adc_flags = new_r_Proj(adc, mode_Iu, pn_ia32_Adc_flags); + arch_set_irn_register(adc_flags, &ia32_registers[REG_EFLAGS]); - cmc = new_bd_ia32_Cmc(dbgi, block, adc_flags); - arch_set_irn_register(cmc, &ia32_registers[REG_EFLAGS]); - sched_add_before(irn, cmc); - - exchange(flags_proj, cmc); - if (res_proj != NULL) { - set_Proj_pred(res_proj, adc); - set_Proj_proj(res_proj, pn_ia32_Adc_res); + cmc = new_bd_ia32_Cmc(dbgi, block, adc_flags); + arch_set_irn_register(cmc, &ia32_registers[REG_EFLAGS]); + sched_add_after(irn, cmc); + exchange(flags_proj, cmc); } res = adc; + } else { + res = new_bd_ia32_Neg(dbgi, block, in2); + arch_set_irn_register(res, in2_reg); + + /* add to schedule */ + sched_add_before(irn, res); + + /* generate the add */ + res = new_bd_ia32_Add(dbgi, block, noreg, noreg, nomem, res, in1); + arch_set_irn_register(res, out_reg); + set_ia32_commutative(res); } } + /* exchange the add and the sub */ + edges_reroute(irn, res); + sched_add_before(irn, res); + set_irn_mode(res, get_irn_mode(irn)); SET_IA32_ORIG_NODE(res, irn); @@ -220,6 +213,7 @@ static inline int need_constraint_copy(ir_node *irn) case iro_ia32_Conv_I2I: case iro_ia32_Conv_I2I8Bit: case iro_ia32_CMovcc: + case iro_ia32_Minus64Bit: return 0; default: @@ -253,7 +247,7 @@ static void assure_should_be_same_requirements(ir_node *node) int n_res, i; ir_node *in_node, *block; - n_res = arch_irn_get_n_outs(node); + n_res = arch_get_irn_n_outs(node); block = get_nodes_block(node); /* check all OUT requirements, if there is a should_be_same */ @@ -261,8 +255,7 @@ static void assure_should_be_same_requirements(ir_node *node) int i2, arity; int same_pos; ir_node *uses_out_reg; - const arch_register_req_t *req = arch_get_out_register_req(node, i); - const arch_register_class_t *cls; + const arch_register_req_t *req = arch_get_irn_register_req_out(node, i); int uses_out_reg_pos; if (!arch_register_req_is(req, should_be_same)) @@ -271,15 +264,14 @@ static void assure_should_be_same_requirements(ir_node *node) same_pos = get_first_same(req); /* get in and out register */ - out_reg = arch_irn_get_register(node, i); + out_reg = arch_get_irn_register_out(node, i); in_node = get_irn_n(node, same_pos); in_reg = arch_get_irn_register(in_node); /* requirement already fulfilled? */ if (in_reg == out_reg) continue; - cls = arch_register_get_class(in_reg); - assert(cls == arch_register_get_class(out_reg)); + assert(in_reg->reg_class == out_reg->reg_class); /* check if any other input operands uses the out register */ arity = get_irn_arity(node); @@ -311,7 +303,7 @@ static void assure_should_be_same_requirements(ir_node *node) * (the register can't be live since the operation will override it * anyway) */ if (uses_out_reg == NULL) { - ir_node *copy = be_new_Copy(cls, block, in_node); + ir_node *copy = be_new_Copy(block, in_node); DBG_OPT_2ADDRCPY(copy); /* destination is the out register */ @@ -361,10 +353,10 @@ static void fix_am_source(ir_node *irn) if (get_ia32_am_support(irn) != ia32_am_binary) return; - n_res = arch_irn_get_n_outs(irn); + n_res = arch_get_irn_n_outs(irn); for (i = 0; i < n_res; i++) { - const arch_register_req_t *req = arch_get_out_register_req(irn, i); + const arch_register_req_t *req = arch_get_irn_register_req_out(irn, i); const arch_register_t *out_reg; int same_pos; ir_node *same_node; @@ -375,7 +367,7 @@ static void fix_am_source(ir_node *irn) continue; /* get in and out register */ - out_reg = arch_irn_get_register(irn, i); + out_reg = arch_get_irn_register_out(irn, i); same_pos = get_first_same(req); same_node = get_irn_n(irn, same_pos); same_reg = arch_get_irn_register(same_node); @@ -418,7 +410,7 @@ static void ia32_finish_irg_walker(ir_node *block, void *env) next = sched_next(irn); /* check if there is a sub which need to be transformed */ - if (is_ia32_Sub(irn) || is_ia32_xSub(irn)) { + if (is_ia32_Sub(irn) || is_ia32_Sbb(irn) || is_ia32_xSub(irn)) { ia32_transform_sub_to_neg_add(irn); } }