bde998bbc1b8dacd5842fa00d41e82cab8cf8fa2
[libfirm] / ir / opt / gvn_pre.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   Global Value Numbering Partial Redundancy Elimination
23  *          (VanDrunen Hosking 2004)
24  * @author  Michael Beck
25  * @version $Id$
26  * @summary
27  */
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include "irflag.h"
33 #include "irdom.h"
34 #include "irouts.h"
35 #include "irgopt.h"
36 #include "irgwalk.h"
37 #include "ircons.h"
38 #include "irgmod.h"
39 #include "valueset.h"
40 #include "irnodemap.h"
41 #include "irnodeset.h"
42 #include "debug.h"
43
44 #include "irgraph_t.h"
45 #include "irnode_t.h"
46 #include "iropt_t.h"
47
48 /** Additional info we need for every block. */
49 typedef struct block_info {
50         ir_valueset_t     *exp_gen;   /**< The set of expression per block. */
51         ir_valueset_t     *avail_out; /**< The Avail_out set for a block. */
52         ir_valueset_t     *antic_in;  /**< The Antic_in set for a block. */
53         ir_valueset_t     *new_set;   /**< The set of all new values for a block. */
54         ir_node           *avail;     /**< The get_map(avail, block) result. */
55         int               not_found;  /**< Non-zero, if avail was not found in this block. */
56         struct block_info *next;      /**< Links all entries, so we can recover the sets easily. */
57 } block_info;
58
59 /**
60  * A pair of nodes that must be exchanged.
61  * We must defer the exchange because our hash-sets cannot
62  * find an already replace node else.
63  */
64 typedef struct elim_pair {
65         ir_node *old_node;      /**< The old node that will be replaced. */
66         ir_node *new_node;      /**< The new node. */
67         struct elim_pair *next; /**< Links all entries in a list. */
68 } elim_pair;
69
70 /** The environment for the GVN-PRE algorithm */
71 typedef struct pre_env {
72         struct obstack *obst;   /**< The obstack to allocate on. */
73         ir_node *start_block;   /**< The start block of the current graph. */
74         ir_node *end_block;     /**< The end block of the current graph */
75         block_info *list;       /**< Links all block info entires for easier recovery. */
76         elim_pair *pairs;       /**< A list of node pairs that must be eliminated. */
77         char changes;           /**< Non-zero, if calculation of Antic_in has changed. */
78         char first_iter;        /**< non-zero for first iteration */
79 } pre_env;
80
81 static pset         *value_table;
82 static ir_nodemap_t value_map;
83
84 /** The debug module handle. */
85 DEBUG_ONLY(static firm_dbg_module_t *dbg;)
86
87 /* ----------  Functions for Value sets ---------- */
88
89 /** computes dst = dst \/ src for value sets */
90 static void value_union(ir_valueset_t *dst, ir_valueset_t *src)
91 {
92         ir_valueset_iterator_t iter;
93         ir_node *value, *expr;
94
95         foreach_valueset(src, value, expr, iter) {
96                 ir_valueset_insert(dst, value, expr);
97         }
98 }
99
100
101 /* ----------  Functions for Values ---------- */
102
103 /**
104  * Add a node node representing the value value to the set.
105  */
106 static ir_node *add(ir_node *e, ir_node *v)
107 {
108         v = identify_remember(value_table, v);
109         ir_nodemap_insert(&value_map, e, v);
110         return v;
111 }
112
113 /**
114  * Lookup a value in a value set.
115  */
116 static ir_node *lookup(ir_node *e)
117 {
118         ir_node *value = ir_nodemap_get(&value_map, e);
119         if (value != NULL)
120                 return identify_remember(value_table, value);
121         return NULL;
122 }
123
124 /**
125  * Add or replace a value in a set by an node computing the same
126  * value in a dominator block.
127  */
128 static ir_node *lookup_or_add(ir_node *e)
129 {
130         ir_node *x = lookup(e);
131
132         if (x == NULL) {
133                 x = add(e, e);
134         }
135         return x;
136 }
137
138
139 /**
140  * Return the block info of a block
141  */
142 static block_info *get_block_info(ir_node *block) {
143         return get_irn_link(block);
144 }
145
146 /**
147  * allocate a block info
148  */
149 static void alloc_blk_info(ir_node *block, pre_env *env) {
150         block_info *info = obstack_alloc(env->obst, sizeof(*info));
151
152         set_irn_link(block, info);
153         info->exp_gen   = ir_valueset_new(16);
154         info->avail_out = ir_valueset_new(16);
155         info->antic_in  = ir_valueset_new(16);
156         info->new_set   = NULL;
157         info->avail     = NULL;
158         info->not_found = 0;
159         info->next      = env->list;
160         env->list       = info;
161 }
162
163 /**
164  * Returns non-zero if a node is movable and a possible candidate for PRE.
165  */
166 static int is_nice_value(ir_node *n) {
167         ir_mode *mode;
168
169         while (is_Proj(n))
170                 n = get_Proj_pred(n);
171         mode = get_irn_mode(n);
172         /*
173          * FIXME: For now, we cannot handle Div/even if it's movable.
174          * That should be fixed.
175          */
176         if (!mode_is_data(mode))
177                 return 0;
178         return (get_irn_pinned(n) != op_pin_state_pinned);
179 }  /* is_nice_value */
180
181 #ifdef DEBUG_libfirm
182 /**
183  * Dump a ir_nodeset_t set.
184  */
185 static void dump_node_set(ir_nodeset_t *set, char *txt, ir_node *block)
186 {
187         ir_nodeset_iterator_t iter;
188         ir_node *n;
189         int i;
190
191         DB((dbg, LEVEL_2, "%s(%+F) = {\n", txt, block));
192         i = 0;
193         foreach_ir_nodeset(set, n, iter) {
194                 if ((i & 3) == 3)
195                         DB((dbg, LEVEL_2, "\n"));
196                 DB((dbg, LEVEL_2, " %+F,", n));
197                 ++i;
198         }
199         DB((dbg, LEVEL_2, "\n}\n"));
200 }  /* dump_node_set */
201
202 /**
203  * Dump a value set.
204  */
205 static void dump_value_set(ir_valueset_t *set, char *txt, ir_node *block) {
206         ir_valueset_iterator_t iter;
207         ir_node *value, *expr;
208         int i;
209
210         DB((dbg, LEVEL_2, "%s(%+F) = {\n", txt, block));
211         i = 0;
212         foreach_valueset(set, value, expr, iter) {
213                 if ((i & 3) == 3)
214                         DB((dbg, LEVEL_2, "\n"));
215                 if (value != expr)
216                         DB((dbg, LEVEL_2, " %+F(%+F),", expr, value));
217                 else
218                         DB((dbg, LEVEL_2, " %+F,", expr));
219                 ++i;
220         }
221         DB((dbg, LEVEL_2, "\n}\n"));
222 }  /* dump_value_set */
223
224
225 #else
226 #define dump_node_set(set, txt, block)
227 #define dump_value_set(set, txt, block)
228 #endif /* DEBUG_libfirm */
229
230 /**
231  * Topological walker. Allocates block info for every block and place nodes in topological
232  * order into the nodes set.
233  */
234 static void topo_walker(ir_node *irn, void *ctx) {
235         pre_env    *env = ctx;
236         ir_node    *block;
237         block_info *info;
238         ir_node    *value;
239
240         if (is_Block(irn)) {
241                 /* the topological walker ensures that blocks are visited before anything else */
242                 alloc_blk_info(irn, env);
243                 return;
244         }
245         /* GVN step: remember the value */
246         value = add(irn, irn);
247
248         /* no need to put constants into the sets: they are always redundant */
249         if (! is_nice_value(irn) || is_irn_constlike(irn))
250                 return;
251
252         /* place this node into the set of possible nodes of its block */
253         block = get_nodes_block(irn);
254         info  = get_block_info(block);
255
256         ir_valueset_insert(info->exp_gen, value, irn);
257 }  /* topo_walker */
258
259 /**
260  * Computes Avail_out(block):
261  *
262  * Avail_in(block)  = Avail_out(dom(block))
263  * Avail_out(block) = Avail_in(block) \/ Nodes(block)
264  *
265  * Precondition:
266  *  This function must be called in the top-down dominance order:
267  *  Then, it computes Leader(Nodes(block)) instead of Nodes(block) !
268  */
269 static void compute_avail_top_down(ir_node *block, void *ctx)
270 {
271         pre_env    *env = ctx;
272         block_info *dom_info;
273         block_info *info = get_block_info(block);
274         ir_node    *dom_blk;
275
276         /* we don't need the end block Avail */
277         if (block == env->end_block)
278                 return;
279
280         /*
281          * First add all nodes from the dominator.
282          * This must be done to ensure that Antic_out contains the leader
283          * for every node. The root has no dominator.
284          */
285         if (block != env->start_block) {
286                 dom_blk = get_Block_idom(block);
287                 assert(is_Block(dom_blk));
288
289                 dom_info = get_block_info(dom_blk);
290                 assert(dom_info);
291
292                 value_union(info->avail_out, dom_info->avail_out);
293         }
294         value_union(info->avail_out, info->exp_gen);
295
296         dump_value_set(info->avail_out, "Avail_out", block);
297 }
298
299 /**
300  * check if a node n is clean in block block.
301  */
302 static int _is_clean(ir_node *n, ir_node *block)
303 {
304         int i;
305
306         if (get_nodes_block(n) != block)
307                 return 1;
308         if (is_Phi(n))
309                 return 1;
310
311         if (irn_visited(n))
312                 return 0;
313
314         if (! is_nice_value(n))
315                 goto bad;
316         for (i = get_irn_arity(n) - 1; i >= 0; --i) {
317                 ir_node *pred = get_irn_n(n, i);
318                 if (! _is_clean(pred, block))
319                         goto bad;
320         }
321         return 1;
322 bad:
323         mark_irn_visited(n);
324         return 0;
325 }
326
327 /**
328  * check if a node n is clean.
329  */
330 static int is_clean(ir_node *n) {
331         int res = _is_clean(n, get_nodes_block(n));
332         return res;
333 }
334
335 /**
336  * Implements phi_translate.
337  */
338 static ir_node *phi_translate(ir_node *node, ir_node *block, int pos, pre_env *env)
339 {
340         ir_node *nn, *res;
341         int i, arity;
342         struct obstack *old;
343
344         if (is_Phi(node)) {
345                 if (get_nodes_block(node) == block) {
346                         /* a Phi inside our block */
347                         return get_Phi_pred(node, pos);
348                 }
349                 /* already outside */
350                 return node;
351         }
352
353         arity = get_irn_intra_arity(node);
354
355         /* check if the node has at least one Phi predecessor */
356         for (i = 0; i < arity; ++i) {
357                 ir_node *pred    = get_irn_intra_n(node, i);
358                 ir_node *pred_bl = get_nodes_block(pred);
359                 ir_node *leader  = lookup(pred);
360
361                 leader = leader != NULL ? leader : pred;
362                 if (is_Phi(leader) && get_nodes_block(pred) == block)
363                         break;
364         }
365         if (i >= arity) {
366                 /* no Phi in the predecessors */
367                 return node;
368         }
369
370         /* Create a copy of the node in the pos'th predecessor block.
371            Use our environmental obstack, as these nodes are always
372            temporary. */
373         old = current_ir_graph->obst;
374         current_ir_graph->obst = env->obst;
375         nn = new_ir_node(
376                 get_irn_dbg_info(node),
377                 current_ir_graph,
378                 NULL,
379                 get_irn_op(node),
380                 get_irn_mode(node),
381                 arity,
382                 get_irn_in(node));
383         /* We need the attribute copy here, because the Hash value of a
384            node might depend on that. */
385         copy_node_attr(node, nn);
386
387         set_nodes_block(nn, get_nodes_block(node));
388         for (i = 0; i < arity; ++i) {
389                 ir_node *pred    = get_irn_intra_n(node, i);
390                 ir_node *pred_bl = get_irn_intra_n(pred, -1);
391                 ir_node *leader  = lookup(pred);
392
393                 leader = leader != NULL ? leader : pred;
394                 if (is_Phi(leader) && get_irn_intra_n(pred, -1) == block)
395                         set_irn_n(nn, i, get_Phi_pred(leader, pos));
396                 else
397                         set_irn_n(nn, i, leader);
398         }
399         current_ir_graph->obst = old;
400         return nn;
401 }  /* phi_translate */
402
403 /**
404  * computes Antic_in(block):
405  */
406 static void compute_antic(ir_node *block, void *ctx) {
407         pre_env    *env = ctx;
408         block_info *succ_info;
409         block_info *info = get_block_info(block);
410         ir_node    *succ, *value, *expr;
411         size_t     size;
412         ir_valueset_iterator_t  iter;
413
414         /* no need for computations in start block */
415         if (block == env->start_block)
416                 return;
417
418         size = ir_valueset_size(info->antic_in);
419
420         /* the end block has no successor */
421         if (block != env->end_block) {
422                 int n_succ = get_Block_n_cfg_outs(block);
423
424                 if (n_succ == 1) {
425                         int i, pos = -1;
426
427                         /* find blocks position in succ's block predecessors */
428                         succ = get_Block_cfg_out(block, 0);
429                         for (i = get_Block_n_cfgpreds(succ) - 1; i >= 0; --i) {
430                                 if (get_Block_cfgpred_block(succ, i) == block) {
431                                         pos = i;
432                                         break;
433                                 }
434                         }
435                         assert(pos >= 0);
436
437                         succ_info = get_block_info(succ);
438                         /* translate into list: we cannot insert into a set we iterate
439                          * and succ might be equal to block for endless loops */
440                         foreach_valueset(succ_info->antic_in, value, expr, iter) {
441                                 ir_node *trans = phi_translate(expr, succ, pos, env);
442
443                                 if (is_clean(trans))
444                                         ir_valueset_insert(info->antic_in, value, trans);
445                         }
446                 } else { /* n_succ > 1 */
447                         ir_node    *succ0;
448                         block_info *succ0_info;
449                         int        i;
450
451                         assert(n_succ > 1);
452
453                         /*
454                          * This step puts all generated expression from the current
455                          * current block into Antic_in.
456                          * It is enough to do this in the first iteration only, because
457                          * the set info->exp_gen is not changed anymore.
458                          */
459                         if (env->first_iter) {
460                                 foreach_valueset(info->exp_gen, value, expr, iter) {
461                                         ir_valueset_insert(info->antic_in, value, expr);
462                                 }
463                         }
464
465                         /* Select a successor to compute the disjoint of all Nodes
466                            sets, it might be useful to select the block with the
467                            smallest number of nodes.  For simplicity we choose the
468                            first one. */
469                         succ0      = get_Block_cfg_out(block, 0);
470                         succ0_info = get_block_info(succ0);
471                         foreach_valueset(succ0_info->antic_in, value, expr, iter) {
472                                 /* we need the disjoint */
473                                 for (i = 1; i < n_succ; ++i) {
474                                         ir_node *succ = get_Block_cfg_out(block, i);
475                                         block_info *succ_info = get_block_info(succ);
476                                         if (ir_valueset_lookup(succ_info->antic_in, value) == NULL)
477                                                 break;
478                                 }
479                                 if (i >= n_succ) {
480                                         /* we found a value that is common in all Antic_in(succ(b)),
481                                             put it in Antic_in(b) if the value is NOT already represented. */
482                                         ir_valueset_insert(info->antic_in, value, expr);
483                                 }
484                         }
485                 }
486         }
487
488         /* we do not need a clean here, because we ensure that only cleaned nodes are in exp_gen
489          * and all other sets */
490
491         dump_value_set(info->antic_in, "Antic_in", block);
492         if (size != ir_valueset_size(info->antic_in)) {
493                 /* the Antic_in set has changed */
494                 env->changes |= 1;
495         }
496 }  /* compute_antic */
497
498 /**
499  * Perform insertion of partially redundant values.
500  * For every Block node, do the following:
501  * 1.  Propagate the NEW_SETS of the dominator into the current block.
502  * If the block has multiple predecessors,
503  *     2a. Iterate over the ANTIC expressions for the block to see if
504  *         any of them are partially redundant.
505  *     2b. If so, insert them into the necessary predecessors to make
506  *         the expression fully redundant.
507  *     2c. Insert a new Phi merging the values of the predecessors.
508  *     2d. Insert the new Phi, and the new expressions, into the
509  *         NEW_SETS set.
510  */
511 static void insert_nodes(ir_node *block, void *ctx)
512 {
513         pre_env    *env = ctx;
514         ir_node    *value, *expr, *idom, *first_s, *worklist;
515         block_info *curr_info, *idom_info;
516         int        pos, arity = get_irn_intra_arity(block);
517         int        all_same, by_some, updated;
518         ir_valueset_iterator_t iter;
519
520         /* ensure that even the start block has a new_set */
521         curr_info = get_block_info(block);
522         if (curr_info->new_set)
523                 ir_valueset_del(curr_info->new_set);
524         curr_info->new_set = ir_valueset_new(16);
525
526         if (block == env->start_block)
527                 return;
528
529         idom      = get_Block_idom(block);
530         idom_info = get_block_info(idom);
531
532         /* update the new_sets */
533         updated = 0;
534         dump_value_set(idom_info->new_set, "[New Set]", idom);
535         foreach_valueset(idom_info->new_set, value, expr, iter) {
536                 ir_valueset_insert(curr_info->new_set, value, expr);
537                 updated |= ir_valueset_replace(curr_info->avail_out, value, expr);
538         }
539         if (updated) {
540                 dump_value_set(curr_info->avail_out, "Updated [Avail_out]", block);
541         }
542
543         if (arity <= 1)
544                 return;
545
546         /* convert the set into a list. This allows the removal of
547          * elements from the set */
548         worklist = NULL;
549         foreach_valueset(curr_info->antic_in, value, expr, iter) {
550                 ir_mode *mode;
551
552                 /* If the value was already computed in the dominator, then
553                    it is totally redundant.  Hence we have nothing to insert. */
554                 if (ir_valueset_lookup(idom_info->avail_out, value)) {
555                         //      DB((dbg, LEVEL_2, "Found %+F from block %+F avail in dom %+F\n", v, block, idom));
556                         continue;
557                 }
558
559                 by_some  = 0;
560                 all_same = 1;
561                 first_s  = NULL;
562                 mode     = NULL;
563
564                 /* for all predecessor blocks */
565                 for (pos = 0; pos < arity; ++pos) {
566                         block_info *pred_info;
567                         ir_node *pred_blk = get_Block_cfgpred_block(block, pos);
568                         ir_node *e_prime, *v_prime, *e_dprime;
569
570                         /* ignore bad blocks. */
571                         if (is_Bad(pred_blk))
572                                 continue;
573
574                         e_prime = phi_translate(expr, block, pos, env);
575                         v_prime = lookup(e_prime);
576                         if (v_prime == NULL)
577                                 v_prime = value;
578
579                         pred_info = get_block_info(pred_blk);
580                         e_dprime  = ir_valueset_lookup(pred_info->avail_out, v_prime);
581
582                         if (e_dprime == NULL) {
583                                 pred_info->avail     = e_prime;
584                                 pred_info->not_found = 1;
585                                 all_same = 0;
586                         } else {
587                                 pred_info->avail     = e_dprime;
588                                 pred_info->not_found = 0;
589                                 mode     = get_irn_mode(e_dprime);
590                                 e_dprime = e_dprime;
591                                 by_some  = 1;
592                                 if (first_s == NULL)
593                                         first_s = e_dprime;
594                                 else if (first_s != e_dprime)
595                                         all_same = 0;
596
597                                 DB((dbg, LEVEL_2, "Found %+F from block %+F as %+F in pred %+F\n", expr, block, e_dprime, pred_blk));
598                         }  /* if */
599                 }  /* for */
600
601                 /* If it's not the same value already existing along every predecessor, and
602                    it's defined by some predecessor, it is partially redundant. */
603                 if (! all_same && by_some) {
604                         ir_node *phi, **in;
605
606                         DB((dbg, LEVEL_1, "Partial redundant %+F from block %+F found\n", expr, block));
607
608                         in = xmalloc(arity * sizeof(*in));
609                         /* for all predecessor blocks */
610                         for (pos = 0; pos < arity; ++pos) {
611                                 ir_node *pred_blk = get_Block_cfgpred_block(block, pos);
612                                 block_info *pred_info = get_block_info(pred_blk);
613
614                                 /* ignore bad blocks. */
615                                 if (is_Bad(pred_blk)) {
616                                         in[pos] = new_Bad();
617                                         continue;
618                                 }
619
620                                 /* ignore blocks that already have the expression */
621                                 if (pred_info->not_found) {
622                                         ir_node *e_prime = pred_info->avail;
623                                         ir_node *nn;
624                                         if (!is_Phi(e_prime)) {
625                                                 mode = get_irn_mode(e_prime);
626                                                 nn = new_ir_node(
627                                                         get_irn_dbg_info(e_prime),
628                                                         current_ir_graph, pred_blk,
629                                                         get_irn_op(e_prime),
630                                                         mode,
631                                                         get_irn_arity(e_prime),
632                                                         get_irn_in(e_prime) + 1);
633                                                 copy_node_attr(e_prime, nn);
634
635                                                 DB((dbg, LEVEL_2, "New node %+F in block %+F created\n", nn, pred_blk));
636                                                 ir_valueset_insert(pred_info->avail_out, add(nn, lookup(expr)), nn);
637                                                 pred_info->avail = nn;
638                                         }
639                                 }
640                                 in[pos] = pred_info->avail;
641                         }  /* for */
642                         phi = new_r_Phi(current_ir_graph, block, arity, in, mode);
643                         value = add(phi, lookup(expr));
644                         ir_valueset_replace(curr_info->avail_out, value, phi);
645                         ir_valueset_insert(curr_info->new_set, value, phi);
646                         free(in);
647                         DB((dbg, LEVEL_2, "New %+F for redundant %+F created\n", phi, expr));
648                         env->changes |= 1;
649                 }  /* if */
650   }  /* node_set_foreach */
651 }  /* insert_nodes */
652
653 /**
654  * Walker, change nodes by its value if different.
655  *
656  * We cannot do the changes right here, as this would change
657  * the hash values of the nodes in the avail_out set!
658  */
659 static void eliminate(ir_node *irn, void *ctx) {
660         pre_env *env = ctx;
661
662         if (is_no_Block(irn)) {
663                 ir_node *block = get_nodes_block(irn);
664                 block_info *bl = get_block_info(block);
665                 ir_node *value = lookup(irn);
666
667                 if (value != NULL) {
668                         ir_node *expr = ir_valueset_lookup(bl->avail_out, value);
669
670                         if (expr != NULL && expr != irn) {
671                                 elim_pair *p = obstack_alloc(env->obst, sizeof(*p));
672
673                                 p->old_node = irn;
674                                 p->new_node = expr;
675                                 p->next     = env->pairs;
676                                 env->pairs  = p;
677                         }
678                 }
679         }
680 }  /* eliminate */
681
682 /**
683  * Do all the recorded changes and optimize
684  * newly created Phi's.
685  */
686 static void eliminate_nodes(elim_pair *pairs) {
687         elim_pair *p;
688
689         for (p = pairs; p != NULL; p = p->next) {
690                 DB((dbg, LEVEL_2, "Replacing %+F by %+F\n", p->old_node, p->new_node));
691                 /*
692                  * PRE tends to create Phi(self, self, ... , x, self, self, ...)
693                  * which we can optimize here
694                  */
695                 if (is_Phi(p->new_node)) {
696                         int i;
697                         ir_node *res = NULL;
698
699                         for (i = get_irn_intra_arity(p->new_node) - 1; i >= 0; --i) {
700                                 ir_node *pred = get_irn_n(p->new_node, i);
701
702                                 if (pred != p->old_node) {
703                                         if (res) {
704                                                 res = NULL;
705                                                 break;
706                                         }
707                                         res = pred;
708                                 }
709                         }
710                         if (res)
711                                 p->new_node = res;
712                 }
713                 exchange(p->old_node, p->new_node);
714         }
715 }  /* eliminate_nodes */
716
717 /*
718  * Argh: Endless loops cause problems, because the
719  * insert algorithm did not terminate. We get translated nodes that
720  * references the origin. These nodes are translated again and again...
721  *
722  * The current fix is to use post-dominance. This simple ignores
723  * endless loops, ie we cannot optimize them.
724  */
725 void do_gvn_pre(ir_graph *irg)
726 {
727         struct obstack obst;
728         pre_env a_env;
729         optimization_state_t state;
730         block_info *bl_info;
731         unsigned antic_iter, insert_iter;
732
733         /* register a debug mask */
734         FIRM_DBG_REGISTER(dbg, "firm.opt.gvn_pre");
735         firm_dbg_set_mask(dbg, SET_LEVEL_2);
736
737         /* edges will crash if enabled due to our allocate on other obstack trick */
738         edges_deactivate(irg);
739
740         value_table = new_identities();
741         ir_nodemap_init(&value_map);
742
743         obstack_init(&obst);
744         a_env.obst        = &obst;
745         a_env.list        = NULL;
746         a_env.start_block = get_irg_start_block(irg);
747         a_env.end_block   = get_irg_end_block(irg);
748         a_env.pairs       = NULL;
749
750         /* Move Proj's into the same block as their args,
751            else we would assign the result to wrong blocks */
752         normalize_proj_nodes(irg);
753
754         /* critical edges MUST be removed */
755         remove_critical_cf_edges(irg);
756
757         /* we need dominator for Antic_out calculation */
758         assure_doms(irg);
759         assure_postdoms(irg);
760         /* we get all nodes of a block by following outs */
761         assure_irg_outs(irg);
762
763         /*
764          * Switch on GCSE. We need it to correctly compute
765          * the leader of a node by hashing.
766          */
767         save_optimization_state(&state);
768         set_opt_global_cse(1);
769
770         DB((dbg, LEVEL_1, "Doing GVN-PRE for %e\n", get_irg_entity(irg)));
771
772         /* allocate block info for all blocks */
773         irg_walk_blkwise_graph(irg, NULL, topo_walker, &a_env);
774
775         /* compute the available value sets for all blocks */
776         dom_tree_walk_irg(irg, compute_avail_top_down, NULL, &a_env);
777
778         /* compute the anticipated value sets for all blocks */
779         antic_iter = 0;
780         a_env.first_iter = 1;
781
782         /* we use the visited flag to mark non-clean nodes */
783         inc_irg_visited(irg);
784         do {
785                 DB((dbg, LEVEL_1, "Antic_in Iteration %d starts ...\n", ++antic_iter));
786                 a_env.changes = 0;
787                 //irg_block_walk_graph(irg, compute_antic, NULL, &a_env);
788                 postdom_tree_walk_irg(irg, compute_antic, NULL, &a_env);
789                 a_env.first_iter = 0;
790                 DB((dbg, LEVEL_1, "------------------------\n"));
791         } while (a_env.changes != 0);
792
793         /* compute redundant expressions */
794         insert_iter = 0;
795         do {
796                 DB((dbg, LEVEL_1, "Insert Iteration %d starts ...\n", ++insert_iter));
797                 a_env.changes = 0;
798                 dom_tree_walk_irg(irg, insert_nodes, NULL, &a_env);
799                 DB((dbg, LEVEL_1, "------------------------\n"));
800         } while (a_env.changes != 0);
801
802         /* last step: eliminate nodes */
803         irg_walk_graph(irg, NULL, eliminate, &a_env);
804         eliminate_nodes(a_env.pairs);
805
806         /* clean up: delete all sets */
807         for (bl_info = a_env.list; bl_info != NULL; bl_info = bl_info->next) {
808                 ir_valueset_del(bl_info->exp_gen);
809                 ir_valueset_del(bl_info->avail_out);
810                 ir_valueset_del(bl_info->antic_in);
811                 if (bl_info->new_set)
812                         ir_valueset_del(bl_info->new_set);
813         }
814         del_identities(value_table);
815         ir_nodemap_destroy(&value_map);
816         obstack_free(&obst, NULL);
817         value_table = NULL;
818
819         /* pin the graph again: This is needed due to the use of set_opt_global_cse(1) */
820         set_irg_pinned(irg, op_pin_state_pinned);
821         restore_optimization_state(&state);
822
823         if (a_env.pairs) {
824                 set_irg_outs_inconsistent(irg);
825                 set_irg_loopinfo_inconsistent(irg);
826
827         }
828         dump_ir_block_graph(irg, "-gvn");
829 }  /* do_gvn_pre */