Extend the NOT+ADC-trick (sic) for SUB to SBB.
authorChristoph Mallon <christoph.mallon@gmx.de>
Wed, 27 Jul 2011 07:39:45 +0000 (09:39 +0200)
committerChristoph Mallon <christoph.mallon@gmx.de>
Wed, 27 Jul 2011 07:39:45 +0000 (09:39 +0200)
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
ir/be/ia32/ia32_spec.pl

index fc587a8..54580e4 100644 (file)
@@ -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);
                }
        }
index d67f80f..bc39460 100644 (file)
@@ -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",