X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fbessaconstr.c;h=07d56cae7b9d9e7d35da110456619df0f7bffd11;hb=5bb8cd35a8074112fa2da8b8f68d7c77918119e5;hp=1b028650c7094fb4ad713ab64634d5de78b52507;hpb=4d5c3365a58cba59993045a9e08e686d8ae079a7;p=libfirm diff --git a/ir/be/bessaconstr.c b/ir/be/bessaconstr.c index 1b028650c..07d56cae7 100644 --- a/ir/be/bessaconstr.c +++ b/ir/be/bessaconstr.c @@ -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. * @@ -19,33 +19,45 @@ /** * @file - * @brief SSA construction for a set of nodes + * @brief SSA construction for a set of nodes * @author Sebastian Hack, Daniel Grund, Matthias Braun, Christian Wuerdig * @date 04.05.2005 * @version $Id$ - * Copyright: (c) Universitaet Karlsruhe - * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE. * * The problem: Given a value and a set of "copies" that are known to * represent the same abstract value, rewire all usages of the original value * 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 + * represent the same concrete value. This is the case if you + * - copy + * - spill and reload + * - re-materialize + * a value. + * + * This function reroutes all uses of the original value to the copies in the + * corresponding dominance subtrees and creates Phi functions where necessary. */ -#ifdef HAVE_CONFIG_H #include "config.h" -#endif + +/* statev in this file is extensive, so only enable if needed */ +#define DISABLE_STATEV #include "bessaconstr.h" #include "bemodule.h" -#include "besched_t.h" -#include "bera.h" -#include "beirg_t.h" +#include "besched.h" +#include "beintlive_t.h" +#include "beirg.h" +#include "be_t.h" +#include "benode.h" #include "debug.h" #include "error.h" @@ -63,57 +75,60 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) * 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) +static 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; - 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")); } -static -ir_node *search_def_end_of_block(be_ssa_construction_env_t *env, - ir_node *block); +static ir_node *search_def_end_of_block(be_ssa_construction_env_t *env, + ir_node *block); -static -ir_node *create_phi(be_ssa_construction_env_t *env, ir_node *block, - ir_node *link_with) +static ir_node *create_phi(be_ssa_construction_env_t *env, ir_node *block, + ir_node *link_with) { int i, n_preds = get_Block_n_cfgpreds(block); - ir_graph *irg = get_irn_irg(block); - ir_node *phi; - ir_node **ins = alloca(n_preds * sizeof(ins[0])); + ir_graph *irg = get_Block_irg(block); + ir_node **ins = ALLOCAN(ir_node*, n_preds); + ir_node *phi; assert(n_preds > 1); - for(i = 0; i < n_preds; ++i) { + for (i = 0; i < n_preds; ++i) { ins[i] = new_r_Unknown(irg, env->mode); } - phi = new_r_Phi(irg, block, n_preds, ins, env->mode); - if(env->new_phis != NULL) { + phi = be_new_Phi(block, n_preds, ins, env->mode, env->phi_cls); + if (env->new_phis != NULL) { ARR_APP1(ir_node*, env->new_phis, phi); } - if(env->mode != mode_M) { + if (env->mode != mode_M) { sched_add_after(block, phi); } @@ -121,7 +136,7 @@ ir_node *create_phi(be_ssa_construction_env_t *env, ir_node *block, set_irn_link(link_with, phi); mark_irn_visited(block); - for(i = 0; i < n_preds; ++i) { + for (i = 0; i < n_preds; ++i) { ir_node *pred_block = get_Block_cfgpred_block(block, i); ir_node *pred_def = search_def_end_of_block(env, pred_block); @@ -131,34 +146,30 @@ ir_node *create_phi(be_ssa_construction_env_t *env, ir_node *block, return phi; } -static -ir_node *get_def_at_idom(be_ssa_construction_env_t *env, ir_node *block) +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 -ir_node *search_def_end_of_block(be_ssa_construction_env_t *env, ir_node *block) +static ir_node *search_def_end_of_block(be_ssa_construction_env_t *env, + ir_node *block) { - if(irn_visited(block)) { + if (irn_visited(block)) { assert(get_irn_link(block) != NULL); return get_irn_link(block); - } else if(Block_block_visited(block)) { + } else if (Block_block_visited(block)) { return create_phi(env, block, block); } else { ir_node *def = get_def_at_idom(env, block); mark_irn_visited(block); set_irn_link(block, def); - return def; } } -static -ir_node *search_def(be_ssa_construction_env_t *env, ir_node *at) +static ir_node *search_def(be_ssa_construction_env_t *env, ir_node *at) { ir_node *block = get_nodes_block(at); ir_node *node; @@ -167,7 +178,7 @@ ir_node *search_def(be_ssa_construction_env_t *env, ir_node *at) DBG((dbg, LEVEL_3, "\t...searching def at %+F\n", at)); /* no defs in the current block we can do the normal searching */ - if(!irn_visited(block) && !Block_block_visited(block)) { + if (!irn_visited(block) && !Block_block_visited(block)) { DBG((dbg, LEVEL_3, "\t...continue at idom\n")); return get_def_at_idom(env, block); } @@ -177,8 +188,8 @@ ir_node *search_def(be_ssa_construction_env_t *env, ir_node *at) */ node = block; def = get_irn_link(node); - while(def != NULL) { - if(!value_dominates(at, def)) { + while (def != NULL) { + if (!value_dominates(at, def)) { DBG((dbg, LEVEL_3, "\t...found dominating def %+F\n", def)); return def; } @@ -188,13 +199,12 @@ ir_node *search_def(be_ssa_construction_env_t *env, ir_node *at) } /* block in dominance frontier? create a phi then */ - if(Block_block_visited(block)) { + if (Block_block_visited(block)) { DBG((dbg, LEVEL_3, "\t...create phi at block %+F\n", block)); assert(!is_Phi(node)); 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); } @@ -204,22 +214,21 @@ ir_node *search_def(be_ssa_construction_env_t *env, ir_node *at) * sorted by dominance. A non-visited block means no definition has been * inserted yet. */ -static -void introduce_def_at_block(ir_node *block, ir_node *def) +static void introduce_def_at_block(ir_node *block, ir_node *def) { - if(irn_visited(block)) { + if (irn_visited_else_mark(block)) { ir_node *node = block; ir_node *current_def; - while(1) { + for (;;) { current_def = get_irn_link(node); - if(current_def == def) { + if (current_def == def) { /* already in block */ return; } - if(current_def == NULL) + if (current_def == NULL) break; - if(value_dominates(current_def, def)) + if (value_dominates(current_def, def)) break; node = current_def; } @@ -229,15 +238,22 @@ void introduce_def_at_block(ir_node *block, ir_node *def) } else { set_irn_link(block, def); set_irn_link(def, NULL); - mark_irn_visited(block); } } 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; @@ -245,26 +261,28 @@ void be_ssa_construction_init(be_ssa_construction_env_t *env, be_irg_t *birg) env->new_phis = NEW_ARR_F(ir_node*, 0); env->worklist = new_waitq(); - set_using_visited(irg); - set_using_block_visited(irg); - set_using_irn_link(irg); + ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED + | IR_RESOURCE_BLOCK_VISITED | IR_RESOURCE_IRN_LINK); /* 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) */ + * 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_block_visited(env->irg); - clear_using_irn_link(env->irg); + ir_free_resources(env->irg, IR_RESOURCE_IRN_VISITED + | IR_RESOURCE_BLOCK_VISITED | IR_RESOURCE_IRN_LINK); + + stat_ev_tim_pop("bessaconstr_total_time"); + stat_ev_ctx_pop("bessaconstr"); } void be_ssa_construction_add_copy(be_ssa_construction_env_t *env, @@ -274,15 +292,16 @@ void be_ssa_construction_add_copy(be_ssa_construction_env_t *env, assert(env->iterated_domfront_calculated == 0); - if(env->mode == NULL) { - env->mode = get_irn_mode(copy); + if (env->mode == NULL) { + env->mode = get_irn_mode(copy); + env->phi_cls = arch_get_irn_reg_class_out(copy); } else { assert(env->mode == get_irn_mode(copy)); } block = get_nodes_block(copy); - if(!irn_visited(block)) { + if (!irn_visited(block)) { waitq_put(env->worklist, block); } introduce_def_at_block(block, copy); @@ -295,16 +314,17 @@ void be_ssa_construction_add_copies(be_ssa_construction_env_t *env, assert(env->iterated_domfront_calculated == 0); - if(env->mode == NULL) { - env->mode = get_irn_mode(copies[0]); + if (env->mode == NULL) { + env->mode = get_irn_mode(copies[0]); + env->phi_cls = arch_get_irn_reg_class_out(copies[0]); } - for(i = 0; i < copies_len; ++i) { - ir_node *copy = copies[i]; + for (i = 0; i < copies_len; ++i) { + ir_node *copy = copies[i]; ir_node *block = get_nodes_block(copy); assert(env->mode == get_irn_mode(copy)); - if(!irn_visited(block)) { + if (!irn_visited(block)) { waitq_put(env->worklist, block); } introduce_def_at_block(block, copy); @@ -322,190 +342,86 @@ 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) { const ir_edge_t *edge, *next; + size_t i; + stat_ev_cnt_decl(uses); + + be_timer_push(T_SSA_CONSTR); - if(!env->iterated_domfront_calculated) { - mark_iterated_dominance_frontiers(env->domfronts, env->worklist); + if (!env->iterated_domfront_calculated) { + 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_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) || is_End(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", 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) { + 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 +BE_REGISTER_MODULE_CONSTRUCTOR(be_init_ssaconstr); void be_init_ssaconstr(void) { FIRM_DBG_REGISTER(dbg, "firm.be.ssaconstr"); } - -BE_REGISTER_MODULE_CONSTRUCTOR(be_init_ssaconstr);