Correct a subtle bug in the ia32 backend: Sub(x, x) triggered that the Neg+Add trick...
[libfirm] / ir / be / ia32 / ia32_finish.c
index a7eaf75..3a47783 100644 (file)
@@ -23,9 +23,7 @@
  * @author  Christian Wuerdig
  * @version $Id$
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include "irnode.h"
 #include "ircons.h"
@@ -36,9 +34,9 @@
 #include "pdeq.h"
 #include "error.h"
 
-#include "../bearch_t.h"
-#include "../besched_t.h"
-#include "../benode_t.h"
+#include "../bearch.h"
+#include "../besched.h"
+#include "../benode.h"
 
 #include "bearch_ia32_t.h"
 #include "ia32_finish.h"
@@ -53,7 +51,7 @@
 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 
 /**
- * Transforms a Sub or xSub into Neg--Add iff OUT_REG == SRC2_REG.
+ * Transforms a Sub or xSub into Neg--Add iff OUT_REG != SRC1_REG && OUT_REG == SRC2_REG.
  * THIS FUNCTIONS MUST BE CALLED AFTER REGISTER ALLOCATION.
  */
 static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg)
@@ -70,16 +68,19 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg)
 
        noreg    = ia32_new_NoReg_gp(cg);
        noreg_fp = ia32_new_NoReg_xmm(cg);
-       nomem    = new_rd_NoMem(cg->irg);
+       nomem    = new_NoMem();
        in1      = get_irn_n(irn, n_ia32_binary_left);
        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  = get_ia32_out_reg(irn, 0);
+       out_reg  = arch_irn_get_register(irn, 0);
 
        irg     = cg->irg;
        block   = get_nodes_block(irn);
 
+       if (out_reg == in1_reg)
+               return;
+
        /* in case of sub and OUT == SRC2 we can transform the sequence into neg src2 -- add */
        if (out_reg != in2_reg)
                return;
@@ -94,7 +95,7 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg)
 
                assert(get_irn_mode(irn) != mode_T);
 
-               res = new_rd_ia32_xXor(dbg, irg, block, noreg, noreg, nomem, in2, noreg_fp);
+               res = new_bd_ia32_xXor(dbg, block, noreg, noreg, nomem, in2, noreg_fp);
                size = get_mode_size_bits(op_mode);
                entity = ia32_gen_fp_known_const(size == 32 ? ia32_SSIGN : ia32_DSIGN);
                set_ia32_am_sc(res, entity);
@@ -107,7 +108,7 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg)
                sched_add_before(irn, res);
 
                /* generate the add */
-               res = new_rd_ia32_xAdd(dbg, irg, block, noreg, noreg, nomem, res, in1);
+               res = new_bd_ia32_xAdd(dbg, block, noreg, noreg, nomem, res, in1);
                set_ia32_ls_mode(res, get_ia32_ls_mode(irn));
 
                /* exchange the add and the sub */
@@ -137,14 +138,14 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg)
                }
 
                if (flags_proj == NULL) {
-                       res = new_rd_ia32_Neg(dbg, irg, block, in2);
+                       res = new_bd_ia32_Neg(dbg, block, in2);
                        arch_set_irn_register(res, in2_reg);
 
                        /* add to schedule */
                        sched_add_before(irn, res);
 
                        /* generate the add */
-                       res = new_rd_ia32_Add(dbg, irg, block, noreg, noreg, nomem, res, in1);
+                       res = new_bd_ia32_Add(dbg, block, noreg, noreg, nomem, res, in1);
                        arch_set_irn_register(res, out_reg);
                        set_ia32_commutative(res);
 
@@ -166,24 +167,23 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg)
                         *
                         * a + -b = a + (~b + 1)  would set the carry flag IF a == b ...
                         */
-                       not = new_rd_ia32_Not(dbg, irg, block, in2);
+                       not = new_bd_ia32_Not(dbg, block, in2);
                        arch_set_irn_register(not, in2_reg);
                        sched_add_before(irn, not);
 
-                       stc = new_rd_ia32_Stc(dbg, irg, block);
+                       stc = new_bd_ia32_Stc(dbg, block);
                        arch_set_irn_register(stc, &ia32_flags_regs[REG_EFLAGS]);
                        sched_add_before(irn, stc);
 
-                       adc = new_rd_ia32_Adc(dbg, irg, block, noreg, noreg, nomem, not,
-                                             in1, stc);
+                       adc = new_bd_ia32_Adc(dbg, block, noreg, noreg, nomem, not, in1, stc);
                        arch_set_irn_register(adc, out_reg);
                        sched_add_before(irn, adc);
 
                        set_irn_mode(adc, mode_T);
-                       adc_flags = new_r_Proj(irg, block, adc, mode_Iu, pn_ia32_Adc_flags);
+                       adc_flags = new_r_Proj(adc, mode_Iu, pn_ia32_Adc_flags);
                        arch_set_irn_register(adc_flags, &ia32_flags_regs[REG_EFLAGS]);
 
-                       cmc = new_rd_ia32_Cmc(dbg, irg, block, adc_flags);
+                       cmc = new_bd_ia32_Cmc(dbg, block, adc_flags);
                        arch_set_irn_register(cmc, &ia32_flags_regs[REG_EFLAGS]);
                        sched_add_before(irn, cmc);
 
@@ -197,7 +197,9 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg)
                }
        }
 
-       SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, irn));
+       set_irn_mode(res, get_irn_mode(irn));
+
+       SET_IA32_ORIG_NODE(res, irn);
 
        /* remove the old sub */
        sched_remove(irn);
@@ -206,7 +208,7 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg)
        DBG_OPT_SUB2NEGADD(irn, res);
 }
 
-static INLINE int need_constraint_copy(ir_node *irn)
+static inline int need_constraint_copy(ir_node *irn)
 {
        /* TODO this should be determined from the node specification */
        switch (get_ia32_irn_opcode(irn)) {
@@ -219,7 +221,7 @@ static INLINE int need_constraint_copy(ir_node *irn)
                case iro_ia32_Lea:
                case iro_ia32_Conv_I2I:
                case iro_ia32_Conv_I2I8Bit:
-               case iro_ia32_CMov:
+               case iro_ia32_CMovcc:
                        return 0;
 
                default:
@@ -243,22 +245,28 @@ static int get_first_same(const arch_register_req_t* req)
        return 32;
 }
 
+static inline bool is_unknown_reg(const arch_register_t *reg)
+{
+       if (reg == &ia32_gp_regs[REG_GP_UKNWN]
+                       || reg == &ia32_xmm_regs[REG_XMM_UKNWN]
+                       || reg == &ia32_vfp_regs[REG_VFP_UKNWN])
+               return true;
+
+       return false;
+}
+
 /**
  * Insert copies for all ia32 nodes where the should_be_same requirement
  * is not fulfilled.
  * Transform Sub into Neg -- Add if IN2 == OUT
  */
-static void assure_should_be_same_requirements(ia32_code_gen_t *cg,
-                                               ir_node *node)
+static void assure_should_be_same_requirements(ir_node *node)
 {
-       ir_graph                   *irg      = cg->irg;
-       const arch_register_req_t **reqs;
        const arch_register_t      *out_reg, *in_reg;
        int                         n_res, i;
        ir_node                    *in_node, *block;
 
-       reqs  = get_ia32_out_req_all(node);
-       n_res = get_ia32_n_res(node);
+       n_res = arch_irn_get_n_outs(node);
        block = get_nodes_block(node);
 
        /* check all OUT requirements, if there is a should_be_same */
@@ -270,7 +278,7 @@ static void assure_should_be_same_requirements(ia32_code_gen_t *cg,
                ir_node                     *perm_proj0;
                ir_node                     *perm_proj1;
                ir_node                     *uses_out_reg;
-               const arch_register_req_t   *req = reqs[i];
+               const arch_register_req_t   *req = arch_get_out_register_req(node, i);
                const arch_register_class_t *cls;
                int                         uses_out_reg_pos;
 
@@ -280,9 +288,9 @@ static void assure_should_be_same_requirements(ia32_code_gen_t *cg,
                same_pos = get_first_same(req);
 
                /* get in and out register */
-               out_reg  = get_ia32_out_reg(node, i);
-               in_node  = get_irn_n(node, same_pos);
-               in_reg   = arch_get_irn_register(in_node);
+               out_reg = arch_irn_get_register(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)
@@ -323,7 +331,7 @@ static void assure_should_be_same_requirements(ia32_code_gen_t *cg,
                 * (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, irg, block, in_node);
+                       ir_node *copy = be_new_Copy(cls, block, in_node);
                        DBG_OPT_2ADDRCPY(copy);
 
                        /* destination is the out register */
@@ -358,10 +366,10 @@ static void assure_should_be_same_requirements(ia32_code_gen_t *cg,
                 * after! the operation as we will override the register. */
                in[0] = in_node;
                in[1] = uses_out_reg;
-               perm  = be_new_Perm(cls, irg, block, 2, in);
+               perm  = be_new_Perm(cls, block, 2, in);
 
-               perm_proj0 = new_r_Proj(irg, block, perm, get_irn_mode(in[0]), 0);
-               perm_proj1 = new_r_Proj(irg, block, perm, get_irn_mode(in[1]), 1);
+               perm_proj0 = new_r_Proj(perm, get_irn_mode(in[0]), 0);
+               perm_proj1 = new_r_Proj(perm, get_irn_mode(in[1]), 1);
 
                arch_set_irn_register(perm_proj0, out_reg);
                arch_set_irn_register(perm_proj1, in_reg);
@@ -395,7 +403,6 @@ static void assure_should_be_same_requirements(ia32_code_gen_t *cg,
  */
 static void fix_am_source(ir_node *irn)
 {
-       const arch_register_req_t **reqs;
        int                         n_res, i;
 
        /* check only ia32 nodes with source address mode */
@@ -405,22 +412,22 @@ static void fix_am_source(ir_node *irn)
        if (get_ia32_am_support(irn) != ia32_am_binary)
                return;
 
-       reqs  = get_ia32_out_req_all(irn);
-       n_res = get_ia32_n_res(irn);
+       n_res = arch_irn_get_n_outs(irn);
 
        for (i = 0; i < n_res; i++) {
-               const arch_register_t *out_reg;
-               int                    same_pos;
-               ir_node               *same_node;
-               const arch_register_t *same_reg;
-               ir_node               *load_res;
+               const arch_register_req_t *req = arch_get_out_register_req(irn, i);
+               const arch_register_t     *out_reg;
+               int                        same_pos;
+               ir_node                   *same_node;
+               const arch_register_t     *same_reg;
+               ir_node                   *load_res;
 
-               if (!arch_register_req_is(reqs[i], should_be_same))
+               if (!arch_register_req_is(req, should_be_same))
                        continue;
 
                /* get in and out register */
-               out_reg   = get_ia32_out_reg(irn, i);
-               same_pos  = get_first_same(reqs[i]);
+               out_reg   = arch_irn_get_register(irn, i);
+               same_pos  = get_first_same(req);
                same_node = get_irn_n(irn, same_pos);
                same_reg  = arch_get_irn_register(same_node);
 
@@ -459,8 +466,6 @@ static void ia32_finish_irg_walker(ir_node *block, void *env)
        }
 
        for (irn = sched_first(block); ! sched_is_end(irn); irn = next) {
-               ia32_code_gen_t *cg = env;
-
                next = sched_next(irn);
 
                /* check if there is a sub which need to be transformed */
@@ -476,7 +481,7 @@ static void ia32_finish_irg_walker(ir_node *block, void *env)
                        /* some nodes are just a bit less efficient, but need no fixing if the
                         * should be same requirement is not fulfilled */
                        if (need_constraint_copy(irn))
-                               assure_should_be_same_requirements(cg, irn);
+                               assure_should_be_same_requirements(irn);
                }
        }
 }