- refactor emitter next/prev block handling a bit
[libfirm] / ir / be / bessaconstr.c
index ae2d194..257ea72 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
  *
  * This file is part of libFirm.
  *
  * to their closest copy while introducing phis as necessary.
  *
  * Algorithm: Mark all blocks in the iterated dominance frontiers of the value
- * and it's copies. Link the copies ordered by dominance to the blocks.  The
- * we search for each use all all definitions in the current block, if none is
+ * and it's copies. Link the copies ordered by dominance to the blocks.  Then
+ * we search for each use all definitions in the current block, if none is
  * found, then we search one in the immediate dominator. If we are in a block
- * of the dominance frontier, create a phi and search do the same search for
- * the phi arguments.
+ * of the dominance frontier, create a phi and do the same search for all
+ * phi arguments.
  *
  * A copy in this context means, that you want to introduce several new
  * abstract values (in Firm: nodes) for which you know, that they
@@ -53,8 +53,9 @@
 #include "bessaconstr.h"
 #include "bemodule.h"
 #include "besched_t.h"
-#include "bera.h"
+#include "beintlive_t.h"
 #include "beirg_t.h"
+#include "be_t.h"
 
 #include "debug.h"
 #include "error.h"
 
 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 
+/**
+ * Checks that low <= what < hi.
+ */
+static INLINE int is_inside(unsigned what, unsigned low, unsigned hi)
+{
+       return what - low < hi;
+}
+
 /**
  * Calculates the iterated dominance frontier of a set of blocks. Marks the
  * blocks as visited. Sets the link fields of the blocks in the dominance
  * frontier to the block itself.
  */
 static
-void mark_iterated_dominance_frontiers(const be_dom_front_info_t *domfronts,
-                                       waitq *worklist)
+void mark_iterated_dominance_frontiers(const be_ssa_construction_env_t *env)
 {
+       stat_ev_cnt_decl(blocks);
        DBG((dbg, LEVEL_3, "Dominance Frontier:"));
-       while(!pdeq_empty(worklist)) {
+       stat_ev_tim_push();
+       while (!waitq_empty(env->worklist)) {
                int i;
-               ir_node *block = waitq_get(worklist);
-               ir_node **domfront = be_get_dominance_frontier(domfronts, block);
+               ir_node *block = waitq_get(env->worklist);
+               ir_node **domfront = be_get_dominance_frontier(env->domfronts, block);
                int domfront_len = ARR_LEN(domfront);
 
                for (i = 0; i < domfront_len; ++i) {
                        ir_node *y = domfront[i];
-                       if(Block_block_visited(y))
+                       if (Block_block_visited(y))
+                               continue;
+
+                       /*
+                        * It makes no sense to add phi-functions to blocks
+                        * that are not dominated by any definition;
+                        * all uses are dominated, hence the paths reaching the uses
+                        * have to stay in the dominance subtrees of the given definitions.
+                        */
+
+                       if (!is_inside(get_Block_dom_tree_pre_num(y), env->min_dom, env->max_dom))
                                continue;
 
-                       if(!irn_visited(y)) {
+                       if (!irn_visited(y)) {
                                set_irn_link(y, NULL);
-                               waitq_put(worklist, y);
+                               waitq_put(env->worklist, y);
                        }
+
                        DBG((dbg, LEVEL_3, " %+F", y));
                        mark_Block_block_visited(y);
+                       stat_ev_cnt_inc(blocks);
                }
        }
+       stat_ev_tim_pop("bessaconstr_idf_time");
+       stat_ev_cnt_done(blocks, "bessaconstr_idf_blocks");
        DBG((dbg, LEVEL_3, "\n"));
 }
 
@@ -144,9 +168,8 @@ static
 ir_node *get_def_at_idom(be_ssa_construction_env_t *env, ir_node *block)
 {
        ir_node *dom = get_Block_idom(block);
-       ir_node *def = search_def_end_of_block(env, dom);
-
-       return def;
+       assert(dom != NULL);
+       return search_def_end_of_block(env, dom);
 }
 
 static
@@ -161,7 +184,6 @@ ir_node *search_def_end_of_block(be_ssa_construction_env_t *env, ir_node *block)
                ir_node *def = get_def_at_idom(env, block);
                mark_irn_visited(block);
                set_irn_link(block, def);
-
                return def;
        }
 }
@@ -203,11 +225,20 @@ ir_node *search_def(be_ssa_construction_env_t *env, ir_node *at)
                return create_phi(env, block, node);
        }
 
-
        DBG((dbg, LEVEL_3, "\t...continue at idom (after checking block)\n"));
        return get_def_at_idom(env, block);
 }
 
+static
+void update_domzone(be_ssa_construction_env_t *env, const ir_node *bl)
+{
+       int start = get_Block_dom_tree_pre_num(bl);
+       int end   = get_Block_dom_max_subtree_pre_num(bl) + 1;
+
+       env->min_dom = MIN(env->min_dom, start);
+       env->max_dom = MAX(env->max_dom, end);
+}
+
 /**
  * Adds a definition into the link field of the block. The definitions are
  * sorted by dominance. A non-visited block means no definition has been
@@ -245,16 +276,26 @@ void introduce_def_at_block(ir_node *block, ir_node *def)
 void be_ssa_construction_init(be_ssa_construction_env_t *env, be_irg_t *birg)
 {
        ir_graph *irg = be_get_birg_irg(birg);
-       memset(env, 0, sizeof(env[0]));
+       ir_node *sb   = get_irg_start_block(irg);
+       int n_blocks  = get_Block_dom_max_subtree_pre_num(sb);
 
+       stat_ev_ctx_push_fobj("bessaconstr", irg);
+       stat_ev_tim_push();
+
+       (void) n_blocks;
+       stat_ev_dbl("bessaconstr_n_blocks", n_blocks);
+
+       memset(env, 0, sizeof(env[0]));
        be_assure_dom_front(birg);
 
        env->irg       = irg;
        env->domfronts = be_get_birg_dom_front(birg);
        env->new_phis  = NEW_ARR_F(ir_node*, 0);
        env->worklist  = new_waitq();
+       env->min_dom   = INT_MAX;
+       env->max_dom   = 0;
 
-       set_using_visited(irg);
+       set_using_irn_visited(irg);
        set_using_block_visited(irg);
        set_using_irn_link(irg);
 
@@ -262,18 +303,22 @@ void be_ssa_construction_init(be_ssa_construction_env_t *env, be_irg_t *birg)
         * and blocks that already have the relevant value at the end calculated */
        inc_irg_visited(irg);
        /* We use the block visited flag to indicate blocks in the dominance
-        * froniter of some values (and this potentially needing phis) */
+        * frontier of some values (and this potentially needing phis) */
        inc_irg_block_visited(irg);
 }
 
 void be_ssa_construction_destroy(be_ssa_construction_env_t *env)
 {
+       stat_ev_int("bessaconstr_phis", ARR_LEN(env->new_phis));
        del_waitq(env->worklist);
        DEL_ARR_F(env->new_phis);
 
-       clear_using_visited(env->irg);
+       clear_using_irn_visited(env->irg);
        clear_using_block_visited(env->irg);
        clear_using_irn_link(env->irg);
+
+       stat_ev_tim_pop("bessaconstr_total_time");
+       stat_ev_ctx_pop("bessaconstr");
 }
 
 void be_ssa_construction_add_copy(be_ssa_construction_env_t *env,
@@ -295,6 +340,7 @@ void be_ssa_construction_add_copy(be_ssa_construction_env_t *env,
                waitq_put(env->worklist, block);
        }
        introduce_def_at_block(block, copy);
+       update_domzone(env, block);
 }
 
 void be_ssa_construction_add_copies(be_ssa_construction_env_t *env,
@@ -317,6 +363,7 @@ void be_ssa_construction_add_copies(be_ssa_construction_env_t *env,
                        waitq_put(env->worklist, block);
                }
                introduce_def_at_block(block, copy);
+               update_domzone(env, block);
        }
 }
 
@@ -331,186 +378,84 @@ ir_node **be_ssa_construction_get_new_phis(be_ssa_construction_env_t *env)
        return env->new_phis;
 }
 
-void be_ssa_construction_fix_users(be_ssa_construction_env_t *env,
-                                   ir_node *value)
+void be_ssa_construction_fix_users_array(be_ssa_construction_env_t *env,
+                                         ir_node **nodes, size_t nodes_len)
 {
+       stat_ev_cnt_decl(uses);
        const ir_edge_t *edge, *next;
+       size_t i;
+
+       BE_TIMER_PUSH(t_ssa_constr);
 
        if(!env->iterated_domfront_calculated) {
-               mark_iterated_dominance_frontiers(env->domfronts, env->worklist);
+               mark_iterated_dominance_frontiers(env);
                env->iterated_domfront_calculated = 1;
        }
 
-       /*
-        * Search the valid def for each use and set it.
-        */
-       foreach_out_edge_safe(value, edge, next) {
-               ir_node *use = get_edge_src_irn(edge);
-               ir_node *at  = use;
-               int pos      = get_edge_src_pos(edge);
-               ir_node *def;
-
-               if(env->ignore_uses != NULL     &&
-                  ir_nodeset_contains(env->ignore_uses, use))
-                       continue;
-
-               if(is_Phi(use)) {
-                       ir_node *block = get_nodes_block(use);
-                       ir_node *predblock = get_Block_cfgpred_block(block, pos);
-                       at = sched_last(predblock);
-               }
+       stat_ev_int("bessaconstr_domzone", env->max_dom - env->min_dom);
+       stat_ev_tim_push();
+       for(i = 0; i < nodes_len; ++i) {
+               ir_node *value = nodes[i];
+
+               /*
+                * Search the valid def for each use and set it.
+                */
+               foreach_out_edge_safe(value, edge, next) {
+                       ir_node *use = get_edge_src_irn(edge);
+                       ir_node *at  = use;
+                       int pos      = get_edge_src_pos(edge);
+                       ir_node *def;
+
+                       if(env->ignore_uses != NULL     &&
+                          ir_nodeset_contains(env->ignore_uses, use))
+                               continue;
+                       if(is_Anchor(use))
+                               continue;
 
-               def = search_def(env, at);
+                       if(is_Phi(use)) {
+                               ir_node *block = get_nodes_block(use);
+                               ir_node *predblock = get_Block_cfgpred_block(block, pos);
+                               at = sched_last(predblock);
+                       }
 
-               if(def == NULL) {
-                       panic("no definition found for %+F at position %d\n", use, pos);
-               }
+                       def = search_def(env, at);
+
+                       if(def == NULL) {
+                               panic("no definition found for %+F at position %d\n", use, pos);
+                       }
 
-               DBG((dbg, LEVEL_2, "\t%+F(%d) -> %+F\n", use, pos, def));
-               set_irn_n(use, pos, def);
+                       DBG((dbg, LEVEL_2, "\t%+F(%d) -> %+F\n", use, pos, def));
+                       set_irn_n(use, pos, def);
+                       stat_ev_cnt_inc(uses);
+               }
        }
+       BE_TIMER_POP(t_ssa_constr);
+
+       stat_ev_tim_pop("bessaconstr_fix_time");
+       stat_ev_cnt_done(uses, "bessaconstr_uses");
 }
 
-void be_ssa_construction_fix_users_array(be_ssa_construction_env_t *env,
-                                         ir_node **nodes, size_t nodes_len)
+void be_ssa_construction_fix_users(be_ssa_construction_env_t *env, ir_node *value)
 {
-       size_t i;
-
-       for(i = 0; i < nodes_len; ++i) {
-               ir_node *node = nodes[i];
-               be_ssa_construction_fix_users(env, node);
-       }
+       be_ssa_construction_fix_users_array(env, &value, 1);
 }
 
+
 void be_ssa_construction_update_liveness_phis(be_ssa_construction_env_t *env,
                                               be_lv_t *lv)
 {
        int i, n;
 
+       BE_TIMER_PUSH(t_ssa_constr);
+
        n = ARR_LEN(env->new_phis);
        for(i = 0; i < n; ++i) {
                ir_node *phi = env->new_phis[i];
                be_liveness_introduce(lv, phi);
        }
-}
-
-#if 0
-ir_node **be_ssa_construction(const be_dom_front_info_t *domfronts, be_lv_t *lv,
-                              ir_node *value, int copies_len, ir_node **copies,
-                              const ir_nodeset_t *ignore_uses, int need_new_phis)
-{
-       ir_graph *irg = get_irn_irg(value);
-       const ir_edge_t *edge, *next;
-       int i;
-       ir_node *block;
-       waitq *worklist;
-       be_ssa_construction_env_t env;
-
-       /* We need to collect the phi functions to compute their liveness. */
-       if(lv != NULL || need_new_phis) {
-               env.new_phis = NEW_ARR_F(ir_node*, 0);
-       } else {
-               env.new_phis = NULL;
-       }
-       env.mode = get_irn_mode(value);
-
-       set_using_visited(irg);
-       set_using_block_visited(irg);
-       set_using_irn_link(irg);
 
-       /* we use the visited flag to indicate blocks in the dominance frontier
-        * and blocks that already have the relevant value at the end calculated */
-       inc_irg_visited(irg);
-       /* We use the block visited flag to indicate blocks in the dominance
-        * froniter of some values (and this potentially needing phis) */
-       inc_irg_block_visited(irg);
-
-       DBG((dbg, LEVEL_1, "Introducing following copies for: %+F\n", value));
-       /* compute iterated dominance frontiers and create lists in the block link
-        * fields that sort usages by dominance. Blocks in the dominance frontier
-        * are marked by links back to the block. */
-       worklist = new_waitq();
-
-       block = get_nodes_block(value);
-       /* we sometimes replace virtual values by real ones, in this case we do
-          not want to insert them into the def list (they're not scheduled
-          and can't be used anyway) */
-       if(sched_is_scheduled(value)) {
-               introduce_def_at_block(block, value);
-       }
-       waitq_put(worklist, block);
-
-       for(i = 0; i < copies_len; ++i) {
-               ir_node *copy = copies[i];
-               block = get_nodes_block(copy);
-
-               if(!irn_visited(block)) {
-                       waitq_put(worklist, block);
-               }
-               introduce_def_at_block(block, copy);
-               DBG((dbg, LEVEL_1, "\t%+F in %+F\n", copy, block));
-       }
-
-       mark_iterated_dominance_frontiers(domfronts, worklist);
-       del_waitq(worklist);
-
-       DBG((dbg, LEVEL_2, "New Definitions:\n"));
-       /*
-        * Search the valid def for each use and set it.
-        */
-       foreach_out_edge_safe(value, edge, next) {
-               ir_node *use = get_edge_src_irn(edge);
-               ir_node *at  = use;
-               int pos      = get_edge_src_pos(edge);
-
-               if(ignore_uses != NULL && ir_nodeset_contains(ignore_uses, use))
-                       continue;
-
-               if(is_Phi(use)) {
-                       ir_node *block = get_nodes_block(use);
-                       ir_node *predblock = get_Block_cfgpred_block(block, pos);
-                       at = sched_last(predblock);
-               }
-
-               ir_node *def = search_def(&env, at);
-
-               if(def == NULL) {
-                       panic("no definition found for %+F at position %d\n", use, pos);
-               }
-
-               DBG((dbg, LEVEL_2, "\t%+F(%d) -> %+F\n", use, pos, def));
-               set_irn_n(use, pos, def);
-       }
-
-       /* Recompute the liveness of the original nodes, the copies and the
-        * inserted phis. */
-       if(lv != NULL) {
-               int n;
-
-               be_liveness_update(lv, value);
-               for(i = 0; i < copies_len; ++i) {
-                       ir_node *copy = copies[i];
-                       be_liveness_update(lv, copy);
-               }
-
-               n = ARR_LEN(env.new_phis);
-               for(i = 0; i < n; ++i) {
-                       ir_node *phi = env.new_phis[i];
-                       be_liveness_introduce(lv, phi);
-               }
-       }
-
-       clear_using_visited(irg);
-       clear_using_block_visited(irg);
-       clear_using_irn_link(irg);
-
-       if(!need_new_phis && env.new_phis != NULL) {
-               DEL_ARR_F(env.new_phis);
-               return NULL;
-       }
-       return env.new_phis;
+       BE_TIMER_POP(t_ssa_constr);
 }
-#endif
 
 void be_init_ssaconstr(void)
 {