From: Matthias Braun Date: Wed, 2 Sep 2009 16:57:04 +0000 (+0000) Subject: merge preferences along congruence classes X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=de8f567353c055dad17398c38f6467f9d6020b52;p=libfirm merge preferences along congruence classes [r26470] --- diff --git a/include/libfirm/adt/unionfind.h b/include/libfirm/adt/unionfind.h index 205881e4e..2c2316d80 100644 --- a/include/libfirm/adt/unionfind.h +++ b/include/libfirm/adt/unionfind.h @@ -55,8 +55,7 @@ static inline void uf_init(int* data, size_t n_elems) * @param data The union find data * @param set1 Representative of set1 * @param set2 Representative of set2 - * @return 0 if the new union set is represented by set1, 1 if it is - * represented by set2 + * @return the new representative of the set (which is set1 or set2) */ static inline int uf_union(int* data, int set1, int set2) { @@ -65,7 +64,7 @@ static inline int uf_union(int* data, int set1, int set2) int newcount; if(set1 == set2) - return 0; + return set1; /* need 2 set representatives */ d1 = data[set1]; @@ -76,11 +75,11 @@ static inline int uf_union(int* data, int set1, int set2) if(d1 > d2) { data[set1] = set2; data[set2] = newcount; - return 1; + return set2; } else { data[set2] = set1; data[set1] = newcount; - return 0; + return set1; } } diff --git a/ir/be/benewalloc.c b/ir/be/benewalloc.c index e6546540d..f9e769c2b 100644 --- a/ir/be/benewalloc.c +++ b/ir/be/benewalloc.c @@ -60,6 +60,7 @@ #include "irnode_t.h" #include "obst.h" #include "raw_bitset.h" +#include "unionfind.h" #include "beabi.h" #include "bechordal_t.h" @@ -94,6 +95,7 @@ static be_lv_t *lv; static const ir_exec_freq *execfreqs; static unsigned n_regs; static unsigned *normal_regs; +static int *congruence_classes; /** currently active assignments (while processing a basic block) * maps registers to values(their current copies) */ @@ -131,14 +133,12 @@ typedef struct block_info_t block_info_t; */ static allocation_info_t *get_allocation_info(ir_node *node) { - allocation_info_t *info; - if (!irn_visited_else_mark(node)) { + allocation_info_t *info = get_irn_link(node); + if (info == NULL) { info = OALLOCFZ(&obst, allocation_info_t, prefs, n_regs); info->current_value = node; info->original_value = node; set_irn_link(node, info); - } else { - info = get_irn_link(node); } return info; @@ -149,14 +149,12 @@ static allocation_info_t *get_allocation_info(ir_node *node) */ static block_info_t *get_block_info(ir_node *block) { - block_info_t *info; + block_info_t *info = get_irn_link(block); assert(is_Block(block)); - if (!irn_visited_else_mark(block)) { + if (info == NULL) { info = OALLOCFZ(&obst, block_info_t, assignments, n_regs); set_irn_link(block, info); - } else { - info = get_irn_link(block); } return info; @@ -393,6 +391,113 @@ static void analyze_block(ir_node *block, void *data) ir_nodeset_destroy(&live_nodes); } +static void create_congurence_class(ir_node *node, void *data) +{ + (void) data; + if (is_Phi(node)) { + int i; + int arity = get_irn_arity(node); + unsigned phi_idx = get_irn_idx(node); + phi_idx = uf_find(congruence_classes, phi_idx); + for (i = 0; i < arity; ++i) { + ir_node *op = get_Phi_pred(node, i); + int op_idx = get_irn_idx(op); + op_idx = uf_find(congruence_classes, op_idx); + phi_idx = uf_union(congruence_classes, phi_idx, op_idx); + } + return; + } + /* should be same constraint? */ + if (is_Proj(node)) { + const arch_register_req_t *req = arch_get_register_req_out(node); + if (req->type & arch_register_req_type_should_be_same) { + ir_node *pred = get_Proj_pred(node); + int arity = get_irn_arity(pred); + int i; + unsigned node_idx = get_irn_idx(node); + node_idx = uf_find(congruence_classes, node_idx); + + for (i = 0; i < arity; ++i) { + ir_node *op; + unsigned op_idx; + + if (!rbitset_is_set(&req->other_same, i)) + continue; + + op = get_irn_n(pred, i); + op_idx = get_irn_idx(op); + op_idx = uf_find(congruence_classes, op_idx); + node_idx = uf_union(congruence_classes, node_idx, op_idx); + } + } + return; + } +} + +static void merge_congruence_prefs(ir_node *node, void *data) +{ + allocation_info_t *info; + allocation_info_t *head_info; + unsigned node_idx = get_irn_idx(node); + unsigned node_set = uf_find(congruence_classes, node_idx); + unsigned r; + + (void) data; + + /* head of congruence class or not in any class */ + if (node_set == node_idx) + return; + + if (!arch_irn_consider_in_reg_alloc(cls, node)) + return; + + head_info = get_allocation_info(get_idx_irn(irg, node_set)); + info = get_allocation_info(node); + + for (r = 0; r < n_regs; ++r) { + head_info->prefs[r] += info->prefs[r]; + } +} + +static void set_congruence_prefs(ir_node *node, void *data) +{ + allocation_info_t *info; + allocation_info_t *head_info; + unsigned node_idx = get_irn_idx(node); + unsigned node_set = uf_find(congruence_classes, node_idx); + + (void) data; + + /* head of congruence class or not in any class */ + if (node_set == node_idx) + return; + + if (!arch_irn_consider_in_reg_alloc(cls, node)) + return; + + head_info = get_allocation_info(get_idx_irn(irg, node_set)); + info = get_allocation_info(node); + + memcpy(info->prefs, head_info->prefs, n_regs * sizeof(info->prefs[0])); +} + +static void combine_congruence_classes(void) +{ + size_t n = get_irg_last_idx(irg); + congruence_classes = XMALLOCN(int, n); + uf_init(congruence_classes, n); + + /* create congruence classes */ + irg_walk_graph(irg, create_congurence_class, NULL, NULL); + /* merge preferences */ + irg_walk_graph(irg, merge_congruence_prefs, NULL, NULL); + irg_walk_graph(irg, set_congruence_prefs, NULL, NULL); +} + + + + + /** * Assign register reg to the given node. * @@ -1161,7 +1266,6 @@ static void adapt_phi_prefs(ir_node *phi) for (i = 0; i < arity; ++i) { ir_node *op = get_irn_n(phi, i); const arch_register_t *reg = arch_get_irn_register(op); - ir_node *pred; ir_node *pred_block; block_info_t *pred_block_info; float weight; @@ -1169,7 +1273,7 @@ static void adapt_phi_prefs(ir_node *phi) if (reg == NULL) continue; - /* we only give the bonus if the predecessor already has register + /* we only give the bonus if the predecessor already has registers * assigned, otherwise we only see a dummy value * and any conclusions about its register are useless */ pred_block = get_Block_cfgpred_block(block, i); @@ -1178,8 +1282,7 @@ static void adapt_phi_prefs(ir_node *phi) continue; /* give bonus for already assigned register */ - pred = get_Block_cfgpred_block(block, i); - weight = get_block_execfreq(execfreqs, pred); + weight = get_block_execfreq(execfreqs, pred_block); r = arch_register_get_index(reg); info->prefs[r] += weight * AFF_PHI; } @@ -1437,17 +1540,18 @@ static void be_straight_alloc_cls(void) be_liveness_assure_sets(lv); be_liveness_assure_chk(lv); - ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_IRN_VISITED); - inc_irg_visited(irg); + ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK); DB((dbg, LEVEL_2, "=== Allocating registers of %s ===\n", cls->name)); + be_clear_links(irg); irg_block_walk_graph(irg, NULL, analyze_block, NULL); + combine_congruence_classes(); /* we need some dominance pre-order walk to ensure we see all * definitions/create copies before we encounter their users */ dom_tree_walk_irg(irg, allocate_coalesce_block, NULL, NULL); - ir_free_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_IRN_VISITED); + ir_free_resources(irg, IR_RESOURCE_IRN_LINK); } static void dump(int mask, ir_graph *irg, const char *suffix, diff --git a/ir/be/bespillslots.c b/ir/be/bespillslots.c index d65e61cc2..303d0b0ae 100644 --- a/ir/be/bespillslots.c +++ b/ir/be/bespillslots.c @@ -222,7 +222,7 @@ static int merge_interferences(be_fec_env_t *env, bitset_t** interferences, /* merge spillslots and interferences */ res = uf_union(spillslot_unionfind, s1, s2); /* we assume that we always merge s2 to s1 so swap s1, s2 if necessary */ - if(res != 0) { + if(res != s1) { int t = s1; s1 = s2; s2 = t; diff --git a/ir/be/beutil.c b/ir/be/beutil.c index 4129bde74..07fd04a38 100644 --- a/ir/be/beutil.c +++ b/ir/be/beutil.c @@ -117,9 +117,7 @@ void be_dump(ir_graph *irg, const char *suffix, void (*dumper)(ir_graph *, const void be_clear_links(ir_graph *irg) { - ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK); irg_walk_graph(irg, firm_clear_link, NULL, NULL); - ir_free_resources(irg, IR_RESOURCE_IRN_LINK); } static void count_num_reachable_nodes(ir_node *irn, void *env)