3 * File name: ir/opt/gvn_pre.c
4 * Purpose: Global Value Numbering Partial Redundancy Elimination
5 * (VanDrunen Hosking 2004)
6 * Author: Michael Beck, Rubino Geiss
9 * Copyright: (c) 1998-2006 Universität Karlsruhe
10 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
19 #include "irgraph_t.h"
34 typedef struct block_info {
35 pset *nodes; /**< the set of nodes per block */
36 pset *avail_out; /**< the Avail_out set for a block */
37 pset *antic_in; /**< the Antic_in set for a block */
38 pset *new_set; /**< the set of all new values for a block */
39 ir_node *avail; /**< the get_map(avail, block) result */
40 int not_found; /**< non-zero, if avail was not found in this block */
41 struct block_info *next;
44 typedef struct pre_env {
45 struct obstack *obst; /**< the obstack to allocate on */
46 ir_node *start_block; /**< the start block of the current graph */
47 ir_node *end_block; /**< the end block of the current graph */
48 block_info *list; /**< links all block info entires for easier recovery */
49 int changes; /**< non-zero, if calculation of Antic_in has changed */
52 /** The debug module handle. */
53 static firm_dbg_module_t *dbg;
56 * returns non-zero if a node is movable.
58 static int is_nice_value(ir_node *n) {
59 ir_mode *mode = get_irn_mode(n);
61 if (!mode_is_data(mode))
63 if (is_irn_constlike(n))
65 return (get_irn_pinned(n) != op_pin_state_pinned);
68 #define pset_foreach(v, s) for ((v) = pset_first(s); (v); (v) = pset_next(s))
70 typedef unsigned (*HASH_FUNC)(void *);
72 /** computes dst = dst \/ src */
73 static void pset_union(pset *dst, pset *src, HASH_FUNC hash)
77 pset_foreach(entry, src) {
78 pset_insert(dst, entry, hash(entry));
82 #define pset_union(d, s) pset_union(d, s, (HASH_FUNC)ir_node_hash)
86 * Dump the Avail or Antic sets
88 static void dump_set(pset *set, char *txt, ir_node *block)
93 DB((dbg, LEVEL_2, "%s(%+F) = {\n", txt, block));
95 pset_foreach(n, set) {
97 DB((dbg, LEVEL_2, "\n"));
98 DB((dbg, LEVEL_2, " %+F,", n));
101 DB((dbg, LEVEL_2, "\n}\n"));
105 #define dump_set(set, txt, block)
106 #endif /* DEBUG_libfirm */
110 * Return the block info of a block
112 static block_info *get_block_info(ir_node *block) {
113 return get_irn_link(block);
117 * computes Avail_out(block):
119 * Avail_in(block) = Avail_out(dom(block))
120 * Avail_out(block) = Avail_in(block) \/ Nodes(block)
123 * This function must be called in the top-down dominance order:
124 * Then, it computes Leader(Nodes(block)) instead of Nodes(block) !
126 static void compute_avail_top_down(ir_node *block, void *ctx)
129 block_info *dom_info;
130 block_info *info = get_block_info(block);
133 /* we don't need the end block Avail */
134 if (block == env->end_block)
137 pset_union(info->avail_out, info->nodes);
139 /* the root has no dominator */
140 if (block != env->start_block) {
141 dom_blk = get_Block_idom(block);
142 assert(is_Block(dom_blk));
144 dom_info = get_block_info(dom_blk);
147 pset_union(info->avail_out, dom_info->avail_out);
149 dump_set(info->avail_out, "Avail_out", block);
153 * Get the leader of an expression. In Firm, only
154 * Phi nodes can be leaders, all other 'leader' are
155 * handled by the identify_remember mechanism right.
157 static ir_node *find_leader(ir_node *n)
159 ir_node *l = get_irn_link(n);
169 * Returns the Phi-leader if one exists, else NULL.
171 static ir_node *has_leader(ir_node *n)
173 ir_node *l = get_irn_link(n);
183 * Implements phi_translate
185 static ir_node *phi_translate(ir_node *node, ir_node *block, int pos, pre_env *env)
189 int i, arity = get_irn_intra_arity(node);
193 if (get_nodes_block(node) == block)
194 return get_Phi_pred(node, pos);
198 /* check if the node has at least one Phi predecessor */
199 for (i = 0; i < arity; ++i) {
200 ir_node *pred = get_irn_intra_n(node, i);
201 ir_node *leader = find_leader(pred);
202 if (is_Phi(leader) && get_nodes_block(leader) == block)
206 /* no Phi in the predecessors */
210 pred_block = get_Block_cfgpred_block(block, pos);
212 /* Create a copy of the node in the pos'th predecessor block.
213 Use our environmental obstack, as these nodes are always
215 old = current_ir_graph->obst;
216 current_ir_graph->obst = env->obst;
218 get_irn_dbg_info(node),
225 /* We need the attribute copy here, because the Hash value of a
226 node might depend on that. */
227 copy_node_attr(node, res);
228 current_ir_graph->obst = old;
230 set_irn_n(res, -1, get_irn_intra_n(node, -1));
231 for (i = 0; i < arity; ++i) {
232 ir_node *pred = get_irn_intra_n(node, i);
233 ir_node *leader = find_leader(pred);
235 if (is_Phi(leader) && get_nodes_block(leader) == block)
236 set_irn_n(res, i, get_Phi_pred(leader, pos));
238 set_irn_n(res, i, leader);
240 set_irn_link(res, NULL);
242 if (is_op_commutative(get_irn_op(res))) {
243 ir_node *l = get_binop_left(res);
244 ir_node *r = get_binop_right(res);
246 /* for commutative operators perform a OP b == b OP a */
248 set_binop_left(res, r);
249 set_binop_right(res, l);
254 } /* phi_translate */
257 * computes Antic_in(block):
259 static void compute_antic(ir_node *block, void *ctx)
262 block_info *succ_info;
263 block_info *info = get_block_info(block);
267 /* no need for computations in start block */
268 if (block == env->start_block)
271 size = pset_count(info->antic_in);
273 /* the root has no dominator */
274 if (block != env->end_block) {
275 int n_succ = get_Block_n_cfg_outs(block);
280 pset *nodes = new_pset(identities_cmp, 8);
282 pset_union(nodes, info->nodes);
284 /* find blocks position in succ's block predecessors */
285 succ = get_Block_cfg_out(block, 0);
286 for (i = get_Block_n_cfgpreds(succ) - 1; i >= 0; --i) {
287 if (get_Block_cfgpred_block(succ, i) == block) {
294 succ_info = get_block_info(succ);
295 for (node = pset_first(succ_info->antic_in);
297 node = pset_next(succ_info->antic_in)) {
298 ir_node *trans = phi_translate(node, succ, pos, env);
300 identify_remember(nodes, trans);
302 /* add all predecessors of node */
303 for (i = get_irn_arity(node) - 1; i >= 0; --i) {
304 ir_node *pred = get_irn_n(node, i);
305 ir_node *trans = phi_translate(pred, succ, pos, env);
307 if (is_nice_value(trans))
308 identify_remember(nodes, trans);
311 /* this step calculates Antic_in(b) = Antic_out(b) \/ Nodes(b) */
312 pset_union(info->antic_in, nodes);
317 block_info *succ0_info;
322 /* Select a successor to compute the disjoint of all Nodes
323 sets, it might be useful to select the block with the
324 smallest number of nodes. For simplicity we choose the
326 succ0 = get_Block_cfg_out(block, 0);
327 succ0_info = get_block_info(succ0);
328 for (n = pset_first(succ0_info->antic_in);
330 n = pset_next(succ0_info->antic_in)) {
331 /* we need the disjoint */
332 for (i = 1; i < n_succ; ++i) {
333 ir_node *succ = get_Block_cfg_out(block, i);
334 block_info *succ_info = get_block_info(succ);
335 if (pset_find(succ_info->antic_in, n, ir_node_hash(n)) == NULL)
339 /* we found a node that is common in all Antic_in(succ(b)),
340 put it in Antic_in(b) */
341 identify_remember(info->antic_in, n);
344 /* this step calculates Antic_in(b) = Antic_out(b) \/ Nodes(b) */
345 pset_union(info->antic_in, info->nodes);
349 if (size != pset_count(info->antic_in))
350 /* the Antic_in set has changed */
353 dump_set(info->antic_in, "Antic_in", block);
354 } /* compute_antic */
357 * allocate a block info
359 static void alloc_blk_info(ir_node *block, void *ctx)
363 block_info *info = obstack_alloc(env->obst, sizeof(block_info));
365 set_irn_link(block, info);
366 info->nodes = new_pset(identities_cmp, 8);
367 info->antic_in = new_pset(identities_cmp, 8);
368 info->avail_out = new_pset(identities_cmp, 8);
371 info->new_set = NULL;
372 info->next = env->list;
373 env->list = info->next;
375 /* fill the nodes set, we will need it later */
376 for (i = get_irn_n_outs(block) - 1; i >= 0; --i) {
377 ir_node *n = get_irn_out(block, i);
379 /* clear the link field here, we need it later */
380 set_irn_link(n, NULL);
382 /* we cannot optimize pinned nodes, so do not remember them */
383 if (is_nice_value(n))
384 identify_remember(info->nodes, n);
385 else if (is_Phi(n) && get_irn_mode(n) != mode_M) {
387 * Phis are "temporaries" and must be handled special:
388 * They are avail, but are not in Antic_in
390 identify_remember(info->avail_out, n);
396 * Compare two nodes for equal operands.
398 static int operands_equal(ir_node *n1, ir_node *n2)
400 int i, arity = get_irn_arity(n1);
401 assert(n1->op == n2->op && arity == get_irn_arity(n2));
402 for (i = 0; i < arity; ++i)
403 if (get_irn_n(n1, i) != get_irn_n(n2, i))
409 * Replace a value in a set by an node computing the same
410 * value in a dominator block.
412 * @return non-zero if a replacement took place
414 static int value_replace(pset *set, ir_node *e)
416 ir_node *old = identify_remember(set, e);
419 /* e must dominate old here */
420 assert(block_dominates(get_nodes_block(e), get_nodes_block(old)));
422 pset_remove(set, old, ir_node_hash(old));
423 identify_remember(set, e);
430 * Perform insertion of partially redundant values.
431 * For every Block node, do the following:
432 * 1. Propagate the NEW_SETS of the dominator into the current block.
433 * If the block has multiple predecessors,
434 * 2a. Iterate over the ANTIC expressions for the block to see if
435 * any of them are partially redundant.
436 * 2b. If so, insert them into the necessary predecessors to make
437 * the expression fully redundant.
438 * 2c. Insert a new Phi merging the values of the predecessors.
439 * 2d. Insert the new Phi, and the new expressions, into the
442 static void insert_nodes(ir_node *block, void *ctx)
445 ir_node *e, *idom, *first_s;
446 block_info *curr_info, *idom_info;
447 int pos, arity = get_irn_intra_arity(block);
448 int all_same, by_some, updated;
450 curr_info = get_block_info(block);
451 curr_info->new_set = new_pset(identities_cmp, 8);
453 if (block == env->start_block)
456 idom = get_Block_idom(block);
457 idom_info = get_block_info(idom);
459 /* update the new_sets */
461 dump_set(idom_info->new_set, "[New Set]", idom);
462 pset_foreach(e, idom_info->new_set) {
463 identify_remember(curr_info->new_set, e);
464 updated |= value_replace(curr_info->avail_out, e);
467 dump_set(curr_info->avail_out, "Updated [Avail_out]", block);
472 pset_foreach(e, curr_info->antic_in) {
474 * If we already have a leader for this node,
475 * it is totally redundant.
480 /* If the value was already computed in the dominator, then
481 it is totally redundant. Hence we have nothing to insert. */
482 if (pset_find(idom_info->avail_out, e, ir_node_hash(e))) {
483 // DB((dbg, LEVEL_2, "Found %+F from block %+F avail in dom %+F\n", v, block, idom));
491 /* for all predecessor blocks */
492 for (pos = 0; pos < arity; ++pos) {
493 block_info *pred_info;
494 ir_node *pred_blk = get_Block_cfgpred_block(block, pos);
495 ir_node *e_prime, *v_prime, *e_dprime;
497 /* ignore bad blocks. */
498 if (is_Bad(pred_blk))
501 e_prime = phi_translate(e, block, pos, env);
504 pred_info = get_block_info(pred_blk);
505 e_dprime = pset_find(pred_info->avail_out, v_prime, ir_node_hash(v_prime));
507 if (e_dprime == NULL) {
509 pred_info->avail = e_prime;
510 pred_info->not_found = 1;
513 e_dprime = find_leader(e_dprime);
514 pred_info->avail = e_dprime;
515 pred_info->not_found = 0;
519 else if (first_s != e_dprime)
522 DB((dbg, LEVEL_2, "Found %+F from block %+F as %+F in pred %+F\n", e, block, e_dprime, pred_blk));
526 /* If it's not the same value already existing along every predecessor, and
527 it's defined by some predecessor, it is partially redundant. */
528 if (! all_same && by_some) {
530 ir_mode *mode = NULL;
531 DB((dbg, LEVEL_1, "Partial redundant %+F from block %+F found\n", e, block));
533 in = xmalloc(arity * sizeof(*in));
534 /* for all predecessor blocks */
535 for (pos = 0; pos < arity; ++pos) {
536 ir_node *pred_blk = get_Block_cfgpred_block(block, pos);
537 block_info *pred_info = get_block_info(pred_blk);
539 /* ignore bad blocks. */
540 if (is_Bad(pred_blk)) {
545 /* ignore blocks that already have the expression */
546 if (pred_info->not_found) {
547 ir_node *e_prime = pred_info->avail;
549 assert(! is_Phi(e_prime));
551 mode = get_irn_mode(e_prime);
553 get_irn_dbg_info(e_prime),
554 current_ir_graph, pred_blk,
557 get_irn_arity(e_prime),
558 get_irn_in(e_prime) + 1);
560 pred_info->avail = identify_remember(pred_info->avail_out, nn);
562 in[pos] = pred_info->avail;
564 phi = new_r_Phi(current_ir_graph, block, arity, in, mode);
566 identify_remember(curr_info->avail_out, phi);
567 identify_remember(curr_info->new_set, phi);
568 /* e might be translated, so add it here */
569 identify_remember(curr_info->avail_out, e);
570 identify_remember(curr_info->new_set, e);
571 set_irn_link(e, phi);
572 DB((dbg, LEVEL_2, "New %+F for redundant %+F created\n", phi, e));
579 * Do the elimination step
581 static void eliminate_nodes(ir_node *block, void *ctx)
583 block_info *curr_info = get_block_info(block);
586 pset_foreach(v, curr_info->nodes) {
587 ir_node *l = identify_remember(curr_info->avail_out, v);
591 DB((dbg, LEVEL_2, "Replacing %+F by %+F\n", v, l));
597 void do_gvn_pre(ir_graph *irg)
601 optimization_state_t state;
605 /* register a debug mask */
606 dbg = firm_dbg_register("firm.opt.gvn_pre");
607 firm_dbg_set_mask(dbg, SET_LEVEL_2);
612 a_env.start_block = get_irg_start_block(irg);
613 a_env.end_block = get_irg_end_block(irg);
615 /* Move Proj's into the same block as their args,
616 else we would assign the result to wrong blocks */
617 normalize_proj_nodes(irg);
619 /* critical edges MUST be removed */
620 remove_critical_cf_edges(irg);
622 /* we need dominator AND post dominator information */
623 if (get_irg_dom_state(irg) != dom_consistent)
625 if (get_irg_postdom_state(irg) != dom_consistent)
626 compute_postdoms(irg);
627 if (get_irg_outs_state(irg) != outs_consistent)
628 compute_irg_outs(irg);
631 * Switch on GCSE. We need it to correctly compute
632 * the leader of a node by hashing.
634 save_optimization_state(&state);
635 set_opt_global_cse(1);
637 /* allocate block info for all blocks */
638 irg_block_walk_graph(irg, NULL, alloc_blk_info, &a_env);
640 /* compute the available value sets for all blocks */
641 dom_tree_walk_irg(irg, compute_avail_top_down, NULL, &a_env);
643 /* compute the anticipated value sets for all blocks */
645 DB((dbg, LEVEL_1, "Antic_in Iteration %d starts ...\n", ++iter));
647 irg_block_walk_graph(irg, compute_antic, NULL, &a_env);
648 // postdom_tree_walk_irg(irg, compute_antic, NULL, &a_env);
649 DB((dbg, LEVEL_1, "------------------------\n"));
650 } while (a_env.changes != 0);
652 /* compute redundant expressions */
655 DB((dbg, LEVEL_1, "Insert Iteration %d starts ...\n", ++iter));
657 dom_tree_walk_irg(irg, insert_nodes, NULL, &a_env);
658 DB((dbg, LEVEL_1, "------------------------\n"));
659 } while (a_env.changes != 0);
661 /* last step: eliminate nodes */
662 dom_tree_walk_irg(irg, eliminate_nodes, NULL, &a_env);
664 restore_optimization_state(&state);
666 /* clean up: delete all sets */
667 for (p = a_env.list; p != NULL; p = p->next) {
669 del_pset(p->antic_in);
671 del_pset(p->avail_out);
675 obstack_free(&obst, NULL);