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