fixed/warnings make it possible to build without interprocedural view and enable...
[libfirm] / ir / ir / irgwalk_blk.c
1 /*
2  * Copyright (C) 1995-2007 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   Blockwise walker implementation
23  * @author  Michael Beck
24  * @version $Id$
25  */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include "irnode_t.h"
31 #include "irgraph_t.h" /* visited flag */
32 #include "irgwalk.h"
33 #include "pset.h"
34 #include "irhooks.h"
35 #include "array.h"
36 #include "hashptr.h"
37
38 #define _get_walk_arity(env, node) \
39         ((env)->follow_deps ? get_irn_ins_or_deps((node)) : get_irn_arity((node)))
40 #define _get_walk_irn_n(env, node, pos) \
41         ((env)->follow_deps ? get_irn_in_or_dep((node), (pos)) : get_irn_n((node), (pos)))
42
43 /**
44  * Metadata for block walker
45  */
46 typedef struct _blk_collect_data_t {
47   struct obstack obst;            /**< obstack to allocate objects on */
48   pset           *blk_map;        /**< Hash map: Block -> List */
49   ir_node        **blk_list;      /**< the Block list */
50   unsigned       follow_deps : 1; /**< follow dependency edges */
51 } blk_collect_data_t;
52
53 /**
54  * An entry for a block in the blk_map
55  */
56 typedef struct _block_entry_t {
57   ir_node *block;       /**< the block */
58   ir_node **phi_list;   /**< the list of Phi instruction */
59   ir_node **df_list;    /**< the list of data flow instruction */
60   ir_node **cf_list;    /**< the list of control flow instructions */
61   ir_node **entry_list; /**< list of all block entries */
62 } block_entry_t;
63
64 /**
65  * compare two block_entries
66  */
67 static int addr_cmp(const void *elt, const void *key) {
68   const block_entry_t *e1 = elt;
69   const block_entry_t *e2 = key;
70
71   return e1->block != e2->block;
72 }
73
74 /**
75  * Returns the associates block_entry_t for an block
76  */
77 static block_entry_t *block_find_entry(ir_node *block, blk_collect_data_t *ctx)
78 {
79   block_entry_t key;
80   block_entry_t *elem;
81
82   key.block = block;
83   elem = pset_find(ctx->blk_map, &key, HASH_PTR(block));
84   if (elem)
85     return elem;
86
87   elem = obstack_alloc(&ctx->obst, sizeof(*elem));
88
89   elem->block      = block;
90   elem->phi_list   = NEW_ARR_F(ir_node *, 0);
91   elem->df_list    = NEW_ARR_F(ir_node *, 0);
92   elem->cf_list    = NEW_ARR_F(ir_node *, 0);
93   elem->entry_list = NEW_ARR_F(ir_node *, 0);
94
95   return pset_insert(ctx->blk_map, elem, HASH_PTR(block));
96 }
97
98 /**
99  * traverse the pre order only, from End to Start
100  */
101 static void traverse_pre(blk_collect_data_t* blks, irg_walk_func *pre, void *env)
102 {
103   int i, j;
104
105   for (i = ARR_LEN(blks->blk_list) - 1; i >= 0; --i) {
106     ir_node       *block = blks->blk_list[i];
107     block_entry_t *entry = block_find_entry(block, blks);
108
109     for (j = ARR_LEN(entry->cf_list) - 1; j >= 0; --j) {
110       ir_node *node = entry->cf_list[j];
111       pre(node, env);
112     }
113
114     for (j = ARR_LEN(entry->df_list) - 1; j >= 0; --j) {
115       ir_node *node = entry->df_list[j];
116       pre(node, env);
117     }
118
119     for (j = ARR_LEN(entry->phi_list) - 1; j >= 0; --j) {
120       ir_node *node = entry->phi_list[j];
121       pre(node, env);
122     }
123
124     pre(block, env);
125
126     DEL_ARR_F(entry->entry_list);
127     DEL_ARR_F(entry->phi_list);
128     DEL_ARR_F(entry->df_list);
129     DEL_ARR_F(entry->cf_list);
130   }
131 }
132
133 /**
134  * traverse the post order only, from Start to End
135  */
136 static void traverse_post(blk_collect_data_t* blks, irg_walk_func *post, void *env)
137 {
138   int i, j;
139
140   for (i = 0; i < ARR_LEN(blks->blk_list); ++i) {
141     ir_node       *block = blks->blk_list[i];
142     block_entry_t *entry = block_find_entry(block, blks);
143
144     post(block, env);
145
146     for (j = 0; j < ARR_LEN(entry->phi_list); ++j) {
147       ir_node *node = entry->phi_list[j];
148       post(node, env);
149     }
150
151     for (j = 0; j < ARR_LEN(entry->df_list); ++j) {
152       ir_node *node = entry->df_list[j];
153       post(node, env);
154     }
155
156     for (j = 0; j < ARR_LEN(entry->cf_list); ++j) {
157       ir_node *node = entry->cf_list[j];
158       post(node, env);
159     }
160
161     DEL_ARR_F(entry->entry_list);
162     DEL_ARR_F(entry->phi_list);
163     DEL_ARR_F(entry->df_list);
164     DEL_ARR_F(entry->cf_list);
165   }
166 }
167
168 /**
169  * traverse both
170  */
171 static void traverse_both(blk_collect_data_t* blks, irg_walk_func *pre, irg_walk_func *post, void *env)
172 {
173   int i, j;
174
175   for (i = ARR_LEN(blks->blk_list) - 1; i >= 0; --i) {
176     ir_node       *block = blks->blk_list[i];
177     block_entry_t *entry = block_find_entry(block, blks);
178
179     for (j = ARR_LEN(entry->cf_list) - 1; j >= 0; --j) {
180       ir_node *node = entry->cf_list[j];
181       pre(node, env);
182     }
183
184     for (j = ARR_LEN(entry->df_list) - 1; j >= 0; --j) {
185       ir_node *node = entry->df_list[j];
186       pre(node, env);
187     }
188
189     for (j = ARR_LEN(entry->phi_list) - 1; j >= 0; --j) {
190       ir_node *node = entry->phi_list[j];
191       pre(node, env);
192     }
193
194     pre(block, env);
195   }
196
197   /* second step */
198   traverse_post(blks, post, env);
199 }
200
201
202 /**
203  * Do the traversal
204  */
205 static void traverse(blk_collect_data_t* blks, irg_walk_func *pre, irg_walk_func *post, void *env)
206 {
207   if      (!post) traverse_pre (blks, pre, env);
208   else if (!pre)  traverse_post(blks, post, env);
209   else            traverse_both(blks, pre, post, env);
210 }
211
212
213 /**
214  * walks over the graph and collects all blocks and all block entries
215  */
216 static void collect_walk(ir_node *node, blk_collect_data_t *env)
217 {
218   int           i, is_phi;
219   block_entry_t *entry;
220   ir_node       *block;
221
222   mark_irn_visited(node);
223
224   if (node->op == op_Block) {
225     /* predecessors of a block are control flow nodes */
226     for (i = _get_walk_arity(env, node) - 1; i >= 0; --i) {
227       ir_node *pred = _get_walk_irn_n(env, node, i);
228       ir_node *blk  = get_nodes_block(pred);
229
230       if (irn_not_visited(pred)) {
231         collect_walk(pred, env);
232
233         /* control flow predecessors are always block inputs */
234         entry = block_find_entry(blk, env);
235         ARR_APP1(ir_node *, entry->entry_list, pred);
236       }
237     }
238
239     /* it's a block, put it into the block list */
240     if (node == get_irg_end_block(current_ir_graph)) {
241       /* Put the end block always last. If we don't do it here,
242        * it might be placed elsewhere if the graph contains
243        * endless loops.
244        */
245     }
246     else {
247       ARR_APP1(ir_node *, env->blk_list, node);
248     }
249   }
250   else {
251     block = get_nodes_block(node);
252
253     if (irn_not_visited(block))
254       collect_walk(block, env);
255
256     is_phi = is_Phi(node);
257     for (i = _get_walk_arity(env, node) - 1; i >= 0; --i) {
258       ir_node *pred = _get_walk_irn_n(env, node, i);
259
260       if (irn_not_visited(pred)) {
261         collect_walk(pred, env);
262
263       /* BEWARE: predecessors of End nodes might be blocks */
264       if (is_no_Block(pred)) {
265         ir_node *blk  = get_nodes_block(pred);
266
267           /*
268            * Note that Phi predecessors are always block entries
269            * because Phi edges are always "outside" a block
270            */
271           if (block != blk || is_phi) {
272             entry = block_find_entry(blk, env);
273             ARR_APP1(ir_node *, entry->entry_list, pred);
274           }
275         }
276       }
277     }
278   }
279 }
280
281 /**
282  * walks over the nodes of a block
283  * and collects them into the right list
284  */
285 static void collect_blks_lists(ir_node *node, ir_node *block,
286                                block_entry_t *entry, blk_collect_data_t *env)
287 {
288   int i;
289
290   mark_irn_visited(node);
291
292   /*
293    * Do not descent into Phi predecessors, these are always
294    * outside the current block because Phi edges are always
295    * "outside".
296    */
297   if (! is_Phi(node)) {
298     for (i = _get_walk_arity(env, node) - 1; i >= 0; --i) {
299       ir_node *pred = _get_walk_irn_n(env, node, i);
300
301       /* BEWARE: predecessors of End nodes might be blocks */
302       if (is_no_Block(pred)) {
303         ir_node *blk  = get_nodes_block(pred);
304
305         if (irn_not_visited(pred)) {
306           if (block != blk)
307             continue;
308           collect_blks_lists(pred, block, entry, env);
309         }
310       }
311     }
312   }
313   else {
314     ARR_APP1(ir_node *, entry->phi_list, node);
315     return;
316   }
317
318   if (get_irn_mode(node) == mode_X) {
319     ARR_APP1(ir_node *, entry->cf_list, node);
320   }
321   else {
322     ARR_APP1(ir_node *, entry->df_list, node);
323   }
324 }
325
326 /**
327  * walk over the graph and collect all lists
328  */
329 static void collect_lists(blk_collect_data_t *env)
330 {
331   int             i, j;
332   ir_node         *block, *node;
333   block_entry_t   *entry;
334
335   inc_irg_visited(current_ir_graph);
336
337   for (i = ARR_LEN(env->blk_list) - 1; i >= 0; --i) {
338     block = env->blk_list[i];
339     entry = block_find_entry(block, env);
340
341     for (j = ARR_LEN(entry->entry_list) - 1; j >= 0; --j) {
342       node = entry->entry_list[j];
343
344       /* a entry might already be visited due to Phi loops */
345       if (node->visited < current_ir_graph->visited)
346         collect_blks_lists(node, block, entry, env);
347     }
348   }
349 }
350
351 /**
352  * Intraprozedural graph walker over blocks.
353  */
354 static void
355 do_irg_walk_blk(ir_graph *irg, irg_walk_func *pre, irg_walk_func *post, void *env, unsigned follow_deps)
356 {
357   ir_node            *end_node = get_irg_end(irg);
358   ir_node            *end_blk = get_irg_end_block(irg);
359   blk_collect_data_t blks;
360   block_entry_t      *entry;
361
362 #ifdef INTERPROCEDURAL_VIEW
363   /* switch off interprocedural view */
364   int old_view       = get_interprocedural_view();
365   set_interprocedural_view(0);
366 #endif
367
368   obstack_init(&blks.obst);
369   blks.blk_map     = new_pset(addr_cmp, 1);
370   blks.blk_list    = NEW_ARR_F(ir_node *, 0);
371   blks.follow_deps = follow_deps != 0;
372
373   /* first step: traverse the graph and fill the lists */
374   set_using_visited(irg);
375   inc_irg_visited(irg);
376   collect_walk(end_node, &blks);
377
378   /* add the end block */
379   ARR_APP1(ir_node *, blks.blk_list, end_blk);
380
381   /* and the end node */
382   entry = block_find_entry(end_blk, &blks);
383   ARR_APP1(ir_node *, entry->entry_list, end_node);
384
385   collect_lists(&blks);
386
387   /* second step: traverse the list */
388   traverse(&blks, pre, post, env);
389
390   DEL_ARR_F(blks.blk_list);
391   del_pset(blks.blk_map);
392   obstack_free(&blks.obst, NULL);
393
394 #ifdef INTERPROCEDURAL_VIEW
395   set_interprocedural_view(old_view);
396 #endif
397   clear_using_visited(irg);
398 }
399
400 void irg_walk_blkwise_graph(ir_graph *irg, irg_walk_func *pre, irg_walk_func *post, void *env)
401 {
402   ir_graph * rem = current_ir_graph;
403
404   hook_irg_walk_blkwise(irg, (generic_func *)pre, (generic_func *)post);
405   current_ir_graph = irg;
406   do_irg_walk_blk(irg, pre, post, env, 0);
407   current_ir_graph = rem;
408 }
409
410
411 void irg_walk_in_or_dep_blkwise_graph(ir_graph *irg, irg_walk_func *pre, irg_walk_func *post, void *env)
412 {
413   ir_graph * rem = current_ir_graph;
414
415   hook_irg_walk_blkwise(irg, (generic_func *)pre, (generic_func *)post);
416   current_ir_graph = irg;
417   do_irg_walk_blk(irg, pre, post, env, 1);
418   current_ir_graph = rem;
419 }