3f9293044befa02c85d0f5e899cbda93ccb63cda
[libfirm] / ir / ir / irgwalk_blk.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/ir/irgwalk_blk.c
4  * Purpose:
5  * Author:      Michael Beck
6  * Modified by:
7  * Created:
8  * CVS-ID:      $Id$
9  * Copyright:   (c) 1999-2004 Universität Karlsruhe
10  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
11  */
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
15
16 #include "irnode_t.h"
17 #include "irgraph_t.h" /* visited flag */
18 #include "irgwalk.h"
19 #include "pdeq.h"
20 #include "pset.h"
21 #include "firmstat.h"
22
23 /**
24  * Metadata for block walker
25  */
26 typedef struct _blk_collect_data_t {
27   struct obstack obst;      /**< obstack to allocate objects on */
28   pset           *blk_map;  /**< Hash map: Block -> List */
29   pdeq           *blk_list; /**< the Block list */
30 } blk_collect_data_t;
31
32 /**
33  * An entry for a block in the blk_map
34  */
35 typedef struct _block_entry_t {
36   ir_node *block;    /**< the block */
37   pdeq    *list;     /**< the instruction list */
38 } block_entry_t;
39
40 /**
41  * compare two block_entries
42  */
43 static int addr_cmp(const void *elt, const void *key) {
44   const block_entry_t *e1 = elt;
45   const block_entry_t *e2 = key;
46
47   return e1->block != e2->block;
48 }
49
50 /**
51  * calculates a hash value for an block address
52  * Addresses are typically aligned at 32bit, so we ignore the lowest bits
53  */
54 static INLINE unsigned block_hash(const ir_node *node) {
55   return (unsigned)node >> 3;
56 }
57
58 /**
59  * Returns the associates block_entry_t for an block
60  */
61 static block_entry_t *block_find_entry(ir_node *block, blk_collect_data_t *ctx)
62 {
63   block_entry_t key;
64   block_entry_t *elem;
65
66   key.block = block;
67   elem = pset_find(ctx->blk_map, &key, block_hash(block));
68   if (elem)
69     return elem;
70
71   elem = obstack_alloc(&ctx->obst, sizeof(*elem));
72
73   elem->block = block;
74   elem->list  = new_pdeq();
75
76   return pset_insert(ctx->blk_map, elem, block_hash(block));
77 }
78
79 /**
80  * collect nodes
81  */
82 static void collect_nodes(ir_node *node, void *env)
83 {
84    blk_collect_data_t *ctx = env;
85    ir_node            *block;
86    block_entry_t      *entry;
87
88    if (is_Block(node))  {
89      /* it's a block, put it into the block list */
90      pdeq_putr(ctx->blk_list, node);
91      return;
92    }
93
94    block = get_nodes_block(node);
95    entry = block_find_entry(block, ctx);
96
97    if (get_irn_mode(node) == mode_X)
98      pdeq_putl(entry->list, node);
99    else
100      pdeq_putr(entry->list, node);
101 }
102
103 /**
104  * traverse the pre order only, from End to Start
105  */
106 static void traverse_pre(blk_collect_data_t* blks, irg_walk_func *pre, void *env)
107 {
108   int i, j;
109
110   for (i = pdeq_len(blks->blk_list); i > 0; --i) {
111     ir_node       *block = pdeq_getl(blks->blk_list);
112     block_entry_t *entry = block_find_entry(block, blks);
113
114     for (j = pdeq_len(entry->list); j > 0; --j) {
115       ir_node *node = pdeq_getl(entry->list);
116       pre(node, env);
117     }
118     pre(block, env);
119   }
120 }
121
122 /**
123  * traverse the post order only, from Start to End
124  */
125 static void traverse_post(blk_collect_data_t* blks, irg_walk_func *post, void *env)
126 {
127   int i, j;
128
129   for (i = pdeq_len(blks->blk_list); i > 0; --i) {
130     ir_node       *block = pdeq_getr(blks->blk_list);
131     block_entry_t *entry = block_find_entry(block, blks);
132
133     post(block, env);
134     for (j = pdeq_len(entry->list); j > 0; --j) {
135       ir_node *node = pdeq_getr(entry->list);
136       post(node, env);
137     }
138   }
139 }
140
141 /**
142  * traverse both
143  */
144 static void traverse_both(blk_collect_data_t* blks, irg_walk_func *pre, irg_walk_func *post, void *env)
145 {
146   int i, j;
147
148   /* pre walk, rotate all lists */
149   for (i = pdeq_len(blks->blk_list); i > 0; --i) {
150     ir_node       *block = pdeq_getl(blks->blk_list);
151     block_entry_t *entry = block_find_entry(block, blks);
152
153     pdeq_putr(blks->blk_list, block);
154
155     for (j = pdeq_len(entry->list); j > 0; --j) {
156       ir_node *node = pdeq_getl(entry->list);
157
158       pdeq_putr(entry->list, node);
159       pre(node, env);
160     }
161     pre(block, env);
162   }
163
164   /* second step */
165   traverse_post(blks, post, env);
166 }
167
168
169 /**
170  * Do the traversal
171  */
172 static void traverse(blk_collect_data_t* blks, irg_walk_func *pre, irg_walk_func *post, void *env)
173 {
174   if      (!post) traverse_pre (blks, pre, env);
175   else if (!pre)  traverse_post(blks, post, env);
176   else            traverse_both(blks, pre, post, env);
177 }
178
179 /**
180  * Intraprozedural graph walker over blocks.
181  */
182 static void
183 do_irg_walk_blk(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void *env)
184 {
185   blk_collect_data_t blks;
186   int old_view = interprocedural_view;
187
188   /* switch off interprocedural view */
189   interprocedural_view = 0;
190
191   obstack_init(&blks.obst);
192   blks.blk_map  = new_pset(addr_cmp, 1);
193   blks.blk_list = new_pdeq();
194
195   if (node->visited < current_ir_graph->visited) {
196     /* first step: traverse the graph and fill the lists */
197     irg_walk(node, collect_nodes, NULL, &blks);
198
199     /* second step: traverse the list */
200     traverse(&blks, pre, post, env);
201   }
202
203   del_pdeq(blks.blk_list);
204   del_pset(blks.blk_map);
205   obstack_free(&blks.obst, NULL);
206
207   interprocedural_view = old_view;
208 }
209
210 void irg_walk_blkwise(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void *env)
211 {
212   inc_irg_visited(current_ir_graph);
213   do_irg_walk_blk(node, pre, post, env);
214 }
215
216 void irg_walk_blkwise_graph(ir_graph *irg, irg_walk_func *pre, irg_walk_func *post, void *env)
217 {
218   ir_graph * rem = current_ir_graph;
219
220   stat_irg_walk_blkwise(irg, (void *)pre, (void *)post);
221   current_ir_graph = irg;
222   irg_walk_blkwise(get_irg_end(irg), pre, post, env);
223   current_ir_graph = rem;
224 }