From: Michael Beck Date: Sat, 9 Aug 2008 02:18:20 +0000 (+0000) Subject: - finally understand HOW n-input nodes made the Follower -> Leader transition X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=a9eee95c42def4095dad5214b493aa0e3ab5a1f7;p=libfirm - finally understand HOW n-input nodes made the Follower -> Leader transition (read the text until end :-), this removes half of the fixes from r21061; this simplifies segregate_def_use_chains() - add a partition checker - opcode contains the arity now (not clear if this is really needed) - a lot of more assertions() - do not kill Confirms yet Still buggy yet :-( [r21069] --- diff --git a/ir/opt/combo.c b/ir/opt/combo.c index 03243911f..376beabd4 100644 --- a/ir/opt/combo.c +++ b/ir/opt/combo.c @@ -59,6 +59,10 @@ /* define this to check that all type translations are monotone */ #define VERIFY_MONOTONE +/* define this to check the consistency of partitions */ +#define CHECK_PARTITIONS + +/* define this to disable followers (may be buggy) */ #undef NO_FOLLOWER typedef struct node_t node_t; @@ -75,6 +79,7 @@ typedef void (*compute_func)(node_t *node); struct opcode_key_t { ir_opcode code; /**< The Firm opcode. */ ir_mode *mode; /**< The mode of all nodes in the partition. */ + int arity; /**< The arity of this opcode (needed for Phi etc. */ union { long proj; /**< For Proj nodes, its proj number */ ir_entity *ent; /**< For Sel Nodes, its entity */ @@ -185,6 +190,33 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg;) /** Next partition number. */ DEBUG_ONLY(static unsigned part_nr = 0); +/* forward */ +static node_t *identity(node_t *node); + +#ifdef CHECK_PARTITIONS +/** + * Check a partition. + */ +static void check_partition(const partition_t *T) { + node_t *node; + unsigned n = 0; + + list_for_each_entry(node_t, node, &T->Leader, node_list) { + assert(node->is_follower == 0); + assert(node->part == T); + ++n; + } + assert(n == T->n_leader); + + list_for_each_entry(node_t, node, &T->Follower, node_list) { + assert(node->is_follower == 1); + assert(node->part == T); + } +} /* check_partition */ +#else +#define check_partition(T) +#endif /* CHECK_PARTITIONS */ + #ifdef DEBUG_libfirm static INLINE lattice_elem_t get_partition_type(const partition_t *X); @@ -365,6 +397,7 @@ static int cmp_opcode(const void *elt, const void *key, size_t size) { (void) size; return o1->code != o2->code || o1->mode != o2->mode || + o1->arity != o2->arity || o1->u.proj != o2->u.proj || o1->u.ent != o2->u.ent; } /* cmp_opcode */ @@ -467,7 +500,7 @@ static INLINE partition_t *new_partition(environment_t *env) { */ static INLINE node_t *get_first_node(const partition_t *X) { return list_entry(X->Leader.next, node_t, node_list); -} +} /* get_first_node */ /** * Return the type of a partition (assuming partition is non-empty and @@ -529,7 +562,7 @@ static void init_block_phis(ir_node *irn, void *env) { if (is_Block(irn)) { set_Block_phis(irn, NULL); } -} +} /* init_block_phis */ /** * Post-Walker, initialize all Nodes' type to U or top and place @@ -635,6 +668,47 @@ static void update_worklist(partition_t *Z, partition_t *Z_prime, environment_t } } /* update_worklist */ +/** + * Make all inputs to x no longer be F.def_use edges. + * + * @param x the node + */ +static void move_edges_to_leader(node_t *x) { + ir_node *irn = x->node; + int i, j, k; + + for (i = get_irn_arity(irn) - 1; i >= 0; --i) { + node_t *pred = get_irn_node(get_irn_n(irn, i)); + ir_node *p; + int n; + + p = pred->node; + n = get_irn_n_outs(p); + for (j = 1; j <= pred->n_followers; ++j) { + if (p->out[j].pos == i && p->out[j].use == irn) { + /* found a follower edge to x, move it to the Leader */ + ir_def_use_edge edge = p->out[j]; + + /* remove this edge from the Follower set */ + p->out[j] = p->out[pred->n_followers]; + --pred->n_followers; + + /* sort it into the leader set */ + for (k = pred->n_followers + 2; k <= n; ++k) { + if (p->out[k].pos >= edge.pos) + break; + p->out[k - 1] = p->out[k]; + } + /* place the new edge here */ + p->out[k - 1] = edge; + + /* edge found and moved */ + break; + } + } + } +} /* move_edges_to_leader */ + /** * Split a partition that has NO followers by a local list. * @@ -664,7 +738,7 @@ static partition_t *split_no_followers(partition_t *Z, node_t *g, environment_t assert(n < Z->n_leader); Z->n_leader -= n; - /* Move g to a new partition, Z’. */ + /* Move g to a new partition, Z'. */ Z_prime = new_partition(env); max_input = 0; for (node = g; node != NULL; node = node->next) { @@ -676,6 +750,9 @@ static partition_t *split_no_followers(partition_t *Z, node_t *g, environment_t Z_prime->max_user_inputs = max_input; Z_prime->n_leader = n; + check_partition(Z); + check_partition(Z_prime); + /* for now, copy the type info tag, it will be adjusted in split_by(). */ Z_prime->type_is_T_or_C = Z->type_is_T_or_C; @@ -696,11 +773,11 @@ static partition_t *split_no_followers(partition_t *Z, node_t *g, environment_t * The environment for one race step. */ typedef struct step_env { - node_t *initial; /**< The initial node list. */ - node_t *unwalked; /**< The unwalked node list. */ - node_t *walked; /**< The walked node list. */ - int index; /**< Next index of Follower use_def edge. */ - int n_leader; /**< number of Leader in initial. */ + node_t *initial; /**< The initial node list. */ + node_t *unwalked; /**< The unwalked node list. */ + node_t *walked; /**< The walked node list. */ + int index; /**< Next index of Follower use_def edge. */ + unsigned n_leader; /**< number of Leader in initial. */ } step_env; /** @@ -734,7 +811,7 @@ static int step(step_env *env) { if (m->part != n->part) continue; - if (! m->is_flagged) { + if (!m->is_flagged) { m->is_flagged = 1; /* add m to unwalked not as first node (we might still need to @@ -779,9 +856,12 @@ static partition_t *split(partition_t **pX, node_t *gg, environment_t *env) { partition_t *X_prime; list_head tmp; step_env env1, env2, *winner; - node_t *g, *h, *node; - int max_input, n, m; + node_t *g, *h, *node, *t; + int max_input; + unsigned n, m; + DEBUG_ONLY(static int run = 0;) + DB((dbg, LEVEL_2, "Run %d ", run++)); if (list_empty(&X->Follower)) { /* if the partition has NO follower, we can use the fast splitting algorithm. */ @@ -789,15 +869,6 @@ static partition_t *split(partition_t **pX, node_t *gg, environment_t *env) { } /* else do the race */ - /* Note: there might be n-Input followers in this partition. When we split it - there inputs might end up in different partitions and these nodes must - do the Follower->Leader transition. Put them on the cprop list to let - this happen. */ - list_for_each_entry(node_t, node, &X->Follower, node_list) { - assert(node->is_follower); - add_to_cprop(node, env); - } - dump_partition("Splitting ", X); dump_list("by list ", gg); @@ -865,22 +936,38 @@ static partition_t *split(partition_t **pX, node_t *gg, environment_t *env) { max_input = 0; for (node = winner->walked; node != NULL; node = node->race_next) { list_del(&node->node_list); + node->part = X_prime; if (node->is_follower) { list_add(&node->node_list, &X_prime->Follower); } else { list_add(&node->node_list, &X_prime->Leader); ++X_prime->n_leader; } - node->part = X_prime; if (node->max_user_input > max_input) max_input = node->max_user_input; } X_prime->max_user_inputs = max_input; - X->n_leader -= winner->n_leader; + X->n_leader -= X_prime->n_leader; /* for now, copy the type info tag, it will be adjusted in split_by(). */ X_prime->type_is_T_or_C = X->type_is_T_or_C; + /* do the Follower -> Leader transition for nodes that loose congruent inputs */ + list_for_each_entry_safe(node_t, node, t, &X_prime->Follower, node_list) { + if (identity(node) == node) { + /* we reach a follower from both sides, this will split congruent + * inputs and make it a leader. */ + DB((dbg, LEVEL_2, "%+F make the follower -> leader transition\n", node->node)); + node->is_follower = 0; + move_edges_to_leader(node); + list_del(&node->node_list); + list_add(&node->node_list, &X_prime->Leader); + ++X_prime->n_leader; + } + } + check_partition(X); + check_partition(X_prime); + /* X' is the smaller part */ add_to_worklist(X_prime, env); @@ -984,6 +1071,11 @@ static void collect_touched(list_head *list, int idx, environment_t *env) { continue; y = get_irn_node(succ); + + /* ignore block edges touching followers */ + if (idx == -1 && y->is_follower) + continue; + if (is_constant_type(y->type)) { ir_opcode code = get_irn_opcode(succ); if (code == iro_Sub || code == iro_Cmp) @@ -1025,8 +1117,8 @@ static void cause_splits(environment_t *env) { collect_touched(&X->Follower, idx, env); for (Z = env->touched; Z != NULL; Z = N) { - node_t **pe, *e; - node_t *touched; + node_t *e; + node_t *touched = Z->touched; unsigned n_touched = Z->n_touched; assert(Z->touched != NULL); @@ -1037,17 +1129,11 @@ static void cause_splits(environment_t *env) { /* remove it from the touched set */ Z->on_touched = 0; - /* Empty local Z.touched AND filter out followers. */ - for (pe = &Z->touched; (*pe) != NULL; pe = &e->next) { - e = *pe; + /* Empty local Z.touched. */ + for (e = touched; e != NULL; e = e->next) { + assert(e->is_follower == 0); e->on_touched = 0; - if (e->is_follower) { - DB((dbg, LEVEL_2, "Removed follower %+F from touched\n", e->node)); - --n_touched; - *(pe) = e->next; - } } - touched = Z->touched; Z->touched = NULL; Z->n_touched = 0; @@ -1129,6 +1215,7 @@ static void *lambda_opcode(const node_t *node, environment_t *env) { key.code = get_irn_opcode(irn); key.mode = get_irn_mode(irn); + key.arity = get_irn_arity(irn); key.u.proj = 0; key.u.ent = NULL; @@ -2110,83 +2197,19 @@ static void segregate_def_use_chain_1(const ir_node *follower, node_t *leader) { * Node follower is a (new) follower of leader, segregate Leader * out edges. If follower is a n-congruent Input identity, all follower * inputs congruent to follower are also leader. + * + * @param follower the follower IR node */ -static void segregate_def_use_chain(const ir_node *follower, node_t *leader) { - ir_op *op = get_irn_op(follower); - - if (op == op_Phi) { - /* n-Congruent Input Identity for Phi's */ - int i; - ir_node *block = get_nodes_block(follower); - - DB((dbg, LEVEL_2, "n-Congruent follower %+F\n", follower)); - for (i = get_irn_arity(follower) - 1; i >= 0; --i) { - node_t *pred_X = get_irn_node(get_Block_cfgpred(block, i)); - - /* beware: we are NOT followers of dead inputs */ - if (pred_X->type.tv == tarval_reachable) { - node_t *pred = get_irn_node(get_irn_n(follower, i)); - - if (pred->part == leader->part) - segregate_def_use_chain_1(follower, pred); - } - } - } else if (op == op_Mux || op == op_Max || op == op_Min) { - /* n-Congruent Input Identity */ - int i; +static void segregate_def_use_chain(const ir_node *follower) { + int i; - DB((dbg, LEVEL_2, "n-Congruent follower %+F\n", follower)); - for (i = get_irn_arity(follower) - 1; i >= 0; --i) { - node_t *pred = get_irn_node(get_irn_n(follower, i)); + for (i = get_irn_arity(follower) - 1; i >= 0; --i) { + node_t *pred = get_irn_node(get_irn_n(follower, i)); - if (pred->part == leader->part) - segregate_def_use_chain_1(follower, pred); - } - } else { - /* 1-Congruent Input Identity */ - segregate_def_use_chain_1(follower, leader); + segregate_def_use_chain_1(follower, pred); } } /* segregate_def_use_chain */ -/** - * Make all inputs to x from inside X no longer be F.def_use edges. - */ -static void move_edges_to_leader(node_t *x) { - ir_node *irn = x->node; - int i, j, k; - - for (i = get_irn_arity(irn) - 1; i >= 0; --i) { - node_t *pred = get_irn_node(get_irn_n(irn, i)); - ir_node *p; - int n; - - p = pred->node; - n = get_irn_n_outs(p); - for (j = 1; j <= pred->n_followers; ++j) { - if (p->out[j].pos == i && p->out[j].use == irn) { - /* found a follower edge to x, move it to the Leader */ - ir_def_use_edge edge = p->out[j]; - - /* remove this edge from the Follower set */ - p->out[j] = p->out[pred->n_followers]; - --pred->n_followers; - - /* sort it into the leader set */ - for (k = pred->n_followers + 2; k <= n; ++k) { - if (p->out[k].pos >= edge.pos) - break; - p->out[k - 1] = p->out[k]; - } - /* place the new edge here */ - p->out[k - 1] = edge; - - /* edge found and moved */ - break; - } - } - } -} - /** * Propagate constant evaluation. * @@ -2216,6 +2239,7 @@ static void propagate(environment_t *env) { while (! list_empty(&X->cprop)) { /* remove the first Node x from X.cprop */ x = list_entry(X->cprop.next, node_t, cprop_list); + assert(x->part == X); list_del(&x->cprop_list); x->on_cprop = 0; @@ -2304,7 +2328,7 @@ static void propagate(environment_t *env) { list_add_tail(&y->node_list, &Y->Follower); --Y->n_leader; - segregate_def_use_chain(y->node, eq_node); + segregate_def_use_chain(y->node); } } } @@ -2323,7 +2347,10 @@ static ir_node *get_leader(node_t *node) { partition_t *part = node->part; if (part->n_leader > 1 || node->is_follower) { - DB((dbg, LEVEL_2, "Found congruence class for %+F\n", node->node)); + if (node->is_follower) + DB((dbg, LEVEL_2, "Replacing follower %+F\n", node->node)); + else + DB((dbg, LEVEL_2, "Found congruence class for %+F\n", node->node)); return get_first_node(part)->node; } @@ -2549,6 +2576,8 @@ static void apply_result(ir_node *irn, void *ctx) { exchange(irn, symc); env->modified = 1; } + } else if (is_Confirm(irn)) { + /* Confirms are always follower, but do not kill them here */ } else { ir_node *leader = get_leader(node); @@ -2577,7 +2606,9 @@ static void apply_end(ir_node *end, environment_t *env) { ir_node *ka = get_End_keepalive(end, i); node_t *node = get_irn_node(ka); - if (! node->is_flagged) { + /* Use the is_flagged bit to mark already visited nodes. + * This should not be ready but better safe than sorry. */ + if (node->is_flagged == 0) { node->is_flagged = 1; if (! is_Block(ka)) @@ -2646,7 +2677,7 @@ void combo(ir_graph *irg) { /* register a debug mask */ FIRM_DBG_REGISTER(dbg, "firm.opt.combo"); - firm_dbg_set_mask(dbg, SET_LEVEL_3); + //firm_dbg_set_mask(dbg, SET_LEVEL_3); DB((dbg, LEVEL_1, "Doing COMBO for %+F\n", irg));