/*
- * 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
#include "besched_t.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"));
}
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
ir_node *def = get_def_at_idom(env, block);
mark_irn_visited(block);
set_irn_link(block, def);
-
return def;
}
}
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
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);
* 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,
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,
waitq_put(env->worklist, block);
}
introduce_def_at_block(block, copy);
+ update_domzone(env, block);
}
}
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;
+
+ if(is_Phi(use)) {
+ ir_node *block = get_nodes_block(use);
+ ir_node *predblock = get_Block_cfgpred_block(block, pos);
+ at = sched_last(predblock);
+ }
- def = search_def(env, at);
+ def = search_def(env, at);
- if(def == NULL) {
- panic("no definition found for %+F at position %d\n", use, pos);
- }
+ 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);
}
+
+ BE_TIMER_POP(t_ssa_constr);
}
void be_init_ssaconstr(void)