added DBG_OPT_LEA( to report Lea craetion to the firm statistic module
[libfirm] / ir / be / ia32 / ia32_optimize.c
index df7a64b..6a88bda 100644 (file)
 #include "ia32_new_nodes.h"
 #include "bearch_ia32_t.h"
 #include "gen_ia32_regalloc_if.h"     /* the generated interface (register type and class defenitions) */
+#include "ia32_transform.h"
+
+/*----*/
+
+#include "irhooks.h"
+#include "dbginfo_t.h"
+#include "firmstat.h"
+
+/**
+ * Merge the debug info due to a LEA creation.
+ *
+ * @param oldn  the node
+ * @param n     the new constant holding the value
+ */
+#define DBG_OPT_LEA(oldn, n)                                \
+  do {                                                         \
+         hook_merge_nodes(&n, 1, &oldn, 1, FS_BE_IA32_LEA);      \
+    __dbg_info_merge_pair(n, oldn, dbg_backend);                 \
+  } while(0)
+
 
 #undef is_NoMem
 #define is_NoMem(irn) (get_irn_op(irn) == op_NoMem)
@@ -119,7 +139,7 @@ static ir_type *get_prim_type(pmap *types, ir_mode *mode)
 static entity *get_entity_for_tv(ia32_code_gen_t *cg, ir_node *cnst)
 {
        tarval *tv    = get_Const_tarval(cnst);
-       pmap_entry *e = pmap_find(cg->tv_ent, tv);
+       pmap_entry *e = pmap_find(cg->isa->tv_ent, tv);
        entity *res;
        ir_graph *rem;
 
@@ -127,7 +147,7 @@ static entity *get_entity_for_tv(ia32_code_gen_t *cg, ir_node *cnst)
                ir_mode *mode = get_irn_mode(cnst);
                ir_type *tp = get_Const_type(cnst);
                if (tp == firm_unknown_type)
-                       tp = get_prim_type(cg->types, mode);
+                       tp = get_prim_type(cg->isa->types, mode);
 
                res = new_entity(get_glob_type(), unique_id("ia32FloatCnst_%u"), tp);
 
@@ -142,6 +162,8 @@ static entity *get_entity_for_tv(ia32_code_gen_t *cg, ir_node *cnst)
                current_ir_graph = get_const_code_irg();
                set_atomic_ent_value(res, new_Const_type(tv, tp));
                current_ir_graph = rem;
+
+               pmap_insert(cg->isa->tv_ent, tv, res);
        }
        else
                res = e->value;
@@ -217,7 +239,7 @@ void ia32_place_consts_set_modes(ir_node *irn, void *env) {
        tenv.block    = get_nodes_block(irn);
        tenv.cg       = cg;
        tenv.irg      = cg->irg;
-       tenv.mod      = cg->mod;
+       DEBUG_ONLY(tenv.mod      = cg->mod;)
 
        /* Loop over all predecessors and check for Sym/Const nodes */
        for (i = get_irn_arity(irn) - 1; i >= 0; --i) {
@@ -398,17 +420,48 @@ static void ia32_optimize_CondJmp(ir_node *irn, ia32_code_gen_t *cg) {
 }
 
 /**
- * Performs Peephole Optimizations
+ * Tries to optimize two following IncSP.
  */
-void ia32_peephole_optimization(ir_node *irn, void *env) {
-       if (is_ia32_TestJmp(irn)) {
-               ia32_optimize_TestJmp(irn, env);
-       }
-       else if (is_ia32_CondJmp(irn)) {
-               ia32_optimize_CondJmp(irn, env);
+static void ia32_optimize_IncSP(ir_node *irn, ia32_code_gen_t *cg) {
+       ir_node *prev = be_get_IncSP_pred(irn);
+       int real_uses = get_irn_n_edges(prev);
+
+       if (be_is_IncSP(prev) && real_uses == 1) {
+               /* first IncSP has only one IncSP user, kill the first one */
+               unsigned       prev_offs = be_get_IncSP_offset(prev);
+               be_stack_dir_t prev_dir  = be_get_IncSP_direction(prev);
+               unsigned       curr_offs = be_get_IncSP_offset(irn);
+               be_stack_dir_t curr_dir  = be_get_IncSP_direction(irn);
+
+               int new_ofs = prev_offs * (prev_dir == be_stack_dir_expand ? -1 : +1) +
+                                   curr_offs * (curr_dir == be_stack_dir_expand ? -1 : +1);
+
+               if (new_ofs < 0) {
+                       new_ofs  = -new_ofs;
+                       curr_dir = be_stack_dir_expand;
+               }
+               else
+                       curr_dir = be_stack_dir_shrink;
+               be_set_IncSP_offset(prev, 0);
+               be_set_IncSP_offset(irn, (unsigned)new_ofs);
+               be_set_IncSP_direction(irn, curr_dir);
        }
 }
 
+/**
+ * Performs Peephole Optimizations.
+ */
+void ia32_peephole_optimization(ir_node *irn, void *env) {
+       ia32_code_gen_t *cg = env;
+
+       if (is_ia32_TestJmp(irn))
+               ia32_optimize_TestJmp(irn, cg);
+       else if (is_ia32_CondJmp(irn))
+               ia32_optimize_CondJmp(irn, cg);
+       else if (be_is_IncSP(irn))
+               ia32_optimize_IncSP(irn, cg);
+}
+
 
 
 /******************************************************************
@@ -596,7 +649,7 @@ static int load_store_addr_is_equal(const ir_node *load, const ir_node *store,
 /**
  * Folds Add or Sub to LEA if possible
  */
-static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, firm_dbg_module_t *mod, ir_node *noreg) {
+static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, ir_node *noreg) {
        ir_graph   *irg        = get_irn_irg(irn);
        dbg_info   *dbg        = get_irn_dbg_info(irn);
        ir_node    *block      = get_nodes_block(irn);
@@ -613,6 +666,7 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, firm_dbg_module_t *
        ir_node    *left, *right, *temp;
        ir_node    *base, *index;
        ia32_am_flavour_t am_flav;
+       DEBUG_ONLY(firm_dbg_module_t *mod = cg->mod;)
 
        if (is_ia32_Add(irn))
                isadd = 1;
@@ -738,16 +792,23 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, firm_dbg_module_t *
 
        /* Try to assimilate a LEA as left operand */
        if (is_ia32_Lea(left) && (get_ia32_am_flavour(left) != ia32_am_O)) {
-               am_flav = get_ia32_am_flavour(left);
+               ir_node *assim_lea_idx, *assim_lea_base;
+
+               am_flav        = get_ia32_am_flavour(left);
+               assim_lea_base = get_irn_n(left, 0);
+               assim_lea_idx  = get_irn_n(left, 1);
+
 
                /* If we have an Add with a real right operand (not NoReg) and  */
                /* the LEA contains already an index calculation then we create */
                /* a new LEA.                                                   */
                /* If the LEA contains already a frame_entity then we also      */
                /* create a new one  otherwise we would loose it.               */
-               if ((isadd && !be_is_NoReg(cg, index) && (am_flav & ia32_am_I)) || /* no new LEA if index already set */
-                       get_ia32_frame_ent(left)                                    || /* no new LEA if stack access */
-                       (have_am_sc && get_ia32_am_sc(left)))                          /* no new LEA if AM symconst already present */
+               if ((isadd && ! be_is_NoReg(cg, index) && (am_flav & ia32_I)) || /* no new LEA if index already set */
+                       get_ia32_frame_ent(left)                                  || /* no new LEA if stack access */
+                       (have_am_sc && get_ia32_am_sc(left))                      || /* no new LEA if AM symconst already present */
+                       /* at least on of the LEA operands must be NOREG */
+                       (!be_is_NoReg(cg, assim_lea_base) && !be_is_NoReg(cg, assim_lea_idx)))
                {
                        DBG((mod, LEVEL_1, "\tleave old LEA, creating new one\n"));
                }
@@ -757,9 +818,18 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, firm_dbg_module_t *
                        am_sc      = have_am_sc ? am_sc : get_ia32_am_sc(left);
                        have_am_sc = am_sc ? 1 : 0;
                        am_sc_sign = is_ia32_am_sc_sign(left);
-                       base       = get_irn_n(left, 0);
-                       index      = get_irn_n(left, 1);
                        scale      = get_ia32_am_scale(left);
+
+                       if (be_is_NoReg(cg, assim_lea_base) && ! be_is_NoReg(cg, assim_lea_idx)) {
+                               /* assimilate index */
+                               assert(be_is_NoReg(cg, index) && ! be_is_NoReg(cg, base) && "operand mismatch for LEA assimilation");
+                               index = assim_lea_idx;
+                       }
+                       else if (! be_is_NoReg(cg, assim_lea_base) && be_is_NoReg(cg, assim_lea_idx)) {
+                               /* assimilate base */
+                               assert(! be_is_NoReg(cg, index) && (base == left) && "operand mismatch for LEA assimilation");
+                               base = assim_lea_base;
+                       }
                }
        }
 
@@ -830,8 +900,13 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, firm_dbg_module_t *
 
                set_ia32_op_type(res, ia32_AddrModeS);
 
+               SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, irn));
+
                DBG((mod, LEVEL_1, "\tLEA [%+F + %+F * %d + %s]\n", base, index, scale, get_ia32_am_offs(res)));
 
+               /* we will exchange it, report here before the Proj is created */
+               DBG_OPT_LEA(irn, res);
+
                /* get the result Proj of the Add/Sub */
                irn = get_res_proj(irn);
 
@@ -849,7 +924,6 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, firm_dbg_module_t *
  */
 void ia32_optimize_am(ir_node *irn, void *env) {
        ia32_code_gen_t   *cg   = env;
-       firm_dbg_module_t *mod  = cg->mod;
        ir_node           *res  = irn;
        dbg_info          *dbg;
        ir_mode           *mode;
@@ -858,6 +932,7 @@ void ia32_optimize_am(ir_node *irn, void *env) {
        ir_node           *store, *load, *mem_proj;
        ir_node           *succ, *addr_b, *addr_i;
        int                check_am_src = 0;
+       DEBUG_ONLY(firm_dbg_module_t *mod = cg->mod;)
 
        if (! is_ia32_irn(irn))
                return;
@@ -889,7 +964,7 @@ void ia32_optimize_am(ir_node *irn, void *env) {
                /* check is irn is a candidate for address calculation */
                if (is_candidate(block, irn, 1)) {
                        DBG((mod, LEVEL_1, "\tfound address calculation candidate %+F ... ", irn));
-                       res = fold_addr(cg, irn, mod, noreg_gp);
+                       res = fold_addr(cg, irn, noreg_gp);
 
                        if (res == irn)
                                DB((mod, LEVEL_1, "transformed into %+F\n", res));