From 7461eb0c217fbba5ece21e61144e868045801e21 Mon Sep 17 00:00:00 2001 From: Christoph Mallon Date: Wed, 27 Jul 2011 09:39:45 +0200 Subject: [PATCH] Extend the NOT+ADC-trick (sic) for SUB to SBB. This should fix 403.gcc. A SBB with AM could not fulfill its should_be_same contraint, so the AM gets split from the SBB. The Load of the AM gets assigned the out register of the SBB, which violates the !in_r5 constraint of the SBB. Therefore it's necessary to turn the SBB into NOT+ADC. --- ir/be/ia32/ia32_finish.c | 74 ++++++++++++++++++++++++---------------- ir/be/ia32/ia32_spec.pl | 2 +- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/ir/be/ia32/ia32_finish.c b/ir/be/ia32/ia32_finish.c index fc587a83c..54580e45b 100644 --- a/ir/be/ia32/ia32_finish.c +++ b/ir/be/ia32/ia32_finish.c @@ -117,10 +117,13 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn) } else { ir_node *res_proj = NULL; ir_node *flags_proj = NULL; + ir_node *carry; const ir_edge_t *edge; if (get_irn_mode(irn) == mode_T) { /* collect the Proj uses */ + assert(pn_ia32_Sub_res == pn_ia32_Sbb_res); + assert(pn_ia32_Sub_flags == pn_ia32_Sbb_flags); foreach_out_edge(irn, edge) { ir_node *proj = get_edge_src_irn(edge); long pn = get_Proj_proj(proj); @@ -135,27 +138,12 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn) } } - 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: @@ -165,15 +153,22 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn) * * 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); @@ -181,17 +176,36 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn) 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); + if (flags_proj != NULL) { + 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); + } - exchange(flags_proj, cmc); if (res_proj != NULL) { set_Proj_pred(res_proj, adc); set_Proj_proj(res_proj, pn_ia32_Adc_res); } 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); + + /* add to schedule */ + sched_add_before(irn, res); } } @@ -418,7 +432,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); } } diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index d67f80f0f..bc39460ea 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -555,7 +555,7 @@ SubMem8Bit => { Sbb => { state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "gp", "gp", "flags" ], - out => [ "in_r4 !in_r5", "flags", "none" ] }, + out => [ "in_r4", "flags", "none" ] }, ins => [ "base", "index", "mem", "minuend", "subtrahend", "eflags" ], outs => [ "res", "flags", "M" ], am => "source,binary", -- 2.20.1