2 * Copyright (C) 1995-2011 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
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.
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.
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
22 * @brief Functions for traversing ir graphs
23 * @author Boris Boesler, Goetz Lindenmaier, Michael Beck
25 * traverse an ir graph
26 * - execute the pre function before recursion
27 * - execute the post function after recursion
34 #include "irgraph_t.h"
46 * specialized version of irg_walk_2, called if only pre callback exists
48 static void irg_walk_2_pre(ir_node *node, irg_walk_func *pre, void *env)
51 ir_graph *irg = get_irn_irg(node);
53 set_irn_visited(node, irg->visited);
57 if (!is_Block(node)) {
58 ir_node *pred = get_nodes_block(node);
59 if (pred->visited < irg->visited)
60 irg_walk_2_pre(pred, pre, env);
62 for (i = get_irn_arity(node) - 1; i >= 0; --i) {
63 ir_node *pred = get_irn_n(node, i);
64 if (pred->visited < irg->visited)
65 irg_walk_2_pre(pred, pre, env);
70 * specialized version of irg_walk_2, called if only post callback exists
72 static void irg_walk_2_post(ir_node *node, irg_walk_func *post, void *env)
75 ir_graph *irg = get_irn_irg(node);
77 set_irn_visited(node, irg->visited);
79 if (!is_Block(node)) {
80 ir_node *pred = get_nodes_block(node);
81 if (pred->visited < irg->visited)
82 irg_walk_2_post(pred, post, env);
84 for (i = get_irn_arity(node) - 1; i >= 0; --i) {
85 ir_node *pred = get_irn_n(node, i);
86 if (pred->visited < irg->visited)
87 irg_walk_2_post(pred, post, env);
94 * specialized version of irg_walk_2, called if pre and post callbacks exist
96 static void irg_walk_2_both(ir_node *node, irg_walk_func *pre,
97 irg_walk_func *post, void *env)
100 ir_graph *irg = get_irn_irg(node);
102 set_irn_visited(node, irg->visited);
106 if (!is_Block(node)) {
107 ir_node *pred = get_nodes_block(node);
108 if (pred->visited < irg->visited)
109 irg_walk_2_both(pred, pre, post, env);
111 for (i = get_irn_arity(node) - 1; i >= 0; --i) {
112 ir_node *pred = get_irn_n(node, i);
113 if (pred->visited < irg->visited)
114 irg_walk_2_both(pred, pre, post, env);
120 void irg_walk_2(ir_node *node, irg_walk_func *pre, irg_walk_func *post,
123 if (irn_visited(node))
126 if (!post) irg_walk_2_pre (node, pre, env);
127 else if (!pre) irg_walk_2_post(node, post, env);
128 else irg_walk_2_both(node, pre, post, env);
131 void irg_walk_core(ir_node *node, irg_walk_func *pre, irg_walk_func *post,
134 assert(is_ir_node(node));
135 irg_walk_2(node, pre, post, env);
138 void irg_walk(ir_node *node, irg_walk_func *pre, irg_walk_func *post,
141 ir_graph *irg = get_irn_irg(node);
142 ir_graph *rem = current_ir_graph;
144 current_ir_graph = irg;
145 ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED);
146 inc_irg_visited(irg);
147 irg_walk_core(node, pre, post, env);
148 ir_free_resources(irg, IR_RESOURCE_IRN_VISITED);
149 current_ir_graph = rem;
152 void irg_walk_graph(ir_graph *irg, irg_walk_func *pre, irg_walk_func *post, void *env)
154 ir_graph * rem = current_ir_graph;
156 hook_irg_walk(irg, (generic_func *)pre, (generic_func *)post);
157 current_ir_graph = irg;
158 irg_walk(get_irg_end(irg), pre, post, env);
159 current_ir_graph = rem;
162 void all_irg_walk(irg_walk_func *pre, irg_walk_func *post, void *env)
167 for (i = 0, n = get_irp_n_irgs(); i < n; i++) {
168 irg = get_irp_irg(i);
169 irg_walk_graph(irg, pre, post, env);
174 * specialized version of irg_walk_in_or_dep_2, called if only pre callback exists
176 static void irg_walk_in_or_dep_2_pre(ir_node *node, irg_walk_func *pre, void *env)
179 ir_graph *irg = get_irn_irg(node);
181 set_irn_visited(node, irg->visited);
185 if (!is_Block(node)) {
186 ir_node *pred = get_nodes_block(node);
187 if (pred->visited < irg->visited)
188 irg_walk_in_or_dep_2_pre(pred, pre, env);
190 for (i = get_irn_ins_or_deps(node) - 1; i >= 0; --i) {
191 ir_node *pred = get_irn_in_or_dep(node, i);
192 if (pred->visited < irg->visited)
193 irg_walk_in_or_dep_2_pre(pred, pre, env);
198 * specialized version of irg_walk_in_or_dep_2, called if only post callback exists
200 static void irg_walk_in_or_dep_2_post(ir_node *node, irg_walk_func *post, void *env)
203 ir_graph *irg = get_irn_irg(node);
205 set_irn_visited(node, irg->visited);
207 if (!is_Block(node)) {
208 ir_node *pred = get_nodes_block(node);
209 if (pred->visited < irg->visited)
210 irg_walk_in_or_dep_2_post(pred, post, env);
212 for (i = get_irn_ins_or_deps(node) - 1; i >= 0; --i) {
213 ir_node *pred = get_irn_in_or_dep(node, i);
214 if (pred->visited < irg->visited)
215 irg_walk_in_or_dep_2_post(pred, post, env);
222 * specialized version of irg_walk_in_or_dep_2, called if pre and post callbacks exist
224 static void irg_walk_in_or_dep_2_both(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void *env)
227 ir_graph *irg = get_irn_irg(node);
229 set_irn_visited(node, irg->visited);
233 if (!is_Block(node)) {
234 ir_node *pred = get_nodes_block(node);
235 if (pred->visited < irg->visited)
236 irg_walk_in_or_dep_2_both(pred, pre, post, env);
238 for (i = get_irn_ins_or_deps(node) - 1; i >= 0; --i) {
239 ir_node *pred = get_irn_in_or_dep(node, i);
240 if (pred->visited < irg->visited)
241 irg_walk_in_or_dep_2_both(pred, pre, post, env);
248 * Intraprozedural graph walker. Follows dependency edges as well.
250 static void irg_walk_in_or_dep_2(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void *env)
252 if (irn_visited(node))
255 if (! post) return irg_walk_in_or_dep_2_pre (node, pre, env);
256 else if (! pre) return irg_walk_in_or_dep_2_post(node, post, env);
257 else return irg_walk_in_or_dep_2_both(node, pre, post, env);
260 void irg_walk_in_or_dep(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void *env)
262 assert(is_ir_node(node));
264 ir_reserve_resources(current_ir_graph, IR_RESOURCE_IRN_VISITED);
265 inc_irg_visited(current_ir_graph);
266 irg_walk_in_or_dep_2(node, pre, post, env);
267 ir_free_resources(current_ir_graph, IR_RESOURCE_IRN_VISITED);
270 void irg_walk_in_or_dep_graph(ir_graph *irg, irg_walk_func *pre, irg_walk_func *post, void *env)
272 ir_graph * rem = current_ir_graph;
274 hook_irg_walk(irg, (generic_func *)pre, (generic_func *)post);
275 current_ir_graph = irg;
276 irg_walk_in_or_dep(get_irg_end(irg), pre, post, env);
277 current_ir_graph = rem;
280 /* Walks back from n until it finds a real cf op. */
281 static ir_node *get_cf_op(ir_node *n)
283 while (!is_cfop(n) && !is_fragile_op(n) && !is_Bad(n)) {
291 static void irg_block_walk_2(ir_node *node, irg_walk_func *pre,
292 irg_walk_func *post, void *env)
296 if (Block_block_visited(node))
298 mark_Block_block_visited(node);
303 for (i = get_Block_n_cfgpreds(node) - 1; i >= 0; --i) {
304 /* find the corresponding predecessor block. */
305 ir_node *pred = get_cf_op(get_Block_cfgpred(node, i));
306 pred = get_nodes_block(pred);
307 if (get_irn_opcode(pred) == iro_Block) {
309 irg_block_walk_2(pred, pre, post, env);
311 assert(get_irn_opcode(pred) == iro_Bad);
319 void irg_block_walk(ir_node *node, irg_walk_func *pre, irg_walk_func *post,
322 ir_graph *irg = get_irn_irg(node);
323 ir_node *block = is_Block(node) ? node : get_nodes_block(node);
325 hook_irg_block_walk(irg, node, (generic_func *)pre, (generic_func *)post);
327 ir_reserve_resources(irg, IR_RESOURCE_BLOCK_VISITED);
328 inc_irg_block_visited(irg);
329 irg_block_walk_2(block, pre, post, env);
331 /* Some blocks might be only reachable through keep-alive edges */
333 int arity = get_irn_arity(node);
335 for (i = 0; i < arity; i++) {
336 ir_node *pred = get_irn_n(node, i);
339 irg_block_walk_2(pred, pre, post, env);
343 ir_free_resources(irg, IR_RESOURCE_BLOCK_VISITED);
346 void irg_block_walk_graph(ir_graph *irg, irg_walk_func *pre,
347 irg_walk_func *post, void *env)
349 ir_graph * rem = current_ir_graph;
350 current_ir_graph = irg;
351 irg_block_walk(get_irg_end(irg), pre, post, env);
352 current_ir_graph = rem;
355 void irg_walk_anchors(ir_graph *irg, irg_walk_func *pre, irg_walk_func *post, void *env)
357 ir_graph * rem = current_ir_graph;
358 current_ir_graph = irg;
360 ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED);
361 inc_irg_visited(irg);
362 irg_walk_2(irg->anchor, pre, post, env);
363 ir_free_resources(irg, IR_RESOURCE_IRN_VISITED);
365 current_ir_graph = rem;
368 typedef struct walk_env {
374 static void walk_initializer(ir_initializer_t *initializer, walk_env *env)
376 switch (initializer->kind) {
377 case IR_INITIALIZER_CONST:
378 irg_walk(initializer->consti.value, env->pre, env->post, env->env);
380 case IR_INITIALIZER_TARVAL:
381 case IR_INITIALIZER_NULL:
384 case IR_INITIALIZER_COMPOUND: {
386 for (i = 0; i < initializer->compound.n_initializers; ++i) {
387 ir_initializer_t *subinitializer
388 = initializer->compound.initializers[i];
389 walk_initializer(subinitializer, env);
394 panic("invalid initializer found");
398 * Walk to all constant expressions in this entity.
400 static void walk_entity(ir_entity *ent, void *env)
402 walk_env *my_env = (walk_env *)env;
404 if (ent->initializer != NULL) {
405 walk_initializer(ent->initializer, my_env);
409 void walk_const_code(irg_walk_func *pre, irg_walk_func *post, void *env)
416 ir_graph *rem = current_ir_graph;
417 current_ir_graph = get_const_code_irg();
418 inc_irg_visited(current_ir_graph);
424 /* Walk all types that can contain constant entities. */
425 for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s)
426 walk_types_entities(get_segment_type(s), &walk_entity, &my_env);
427 n_types = get_irp_n_types();
428 for (i = 0; i < n_types; i++)
429 walk_types_entities(get_irp_type(i), &walk_entity, &my_env);
430 for (i = 0; i < get_irp_n_irgs(); i++)
431 walk_types_entities(get_irg_frame_type(get_irp_irg(i)), &walk_entity, &my_env);
433 /* Walk constant array bounds. */
434 for (i = 0; i < n_types; i++) {
435 ir_type *tp = get_irp_type(i);
436 if (is_Array_type(tp)) {
437 size_t j, n_dim = get_array_n_dimensions(tp);
438 for (j = 0; j < n_dim; j++) {
439 ir_node *n = get_array_lower_bound(tp, j);
440 if (n) irg_walk(n, pre, post, env);
441 n = get_array_upper_bound(tp, j);
442 if (n) irg_walk(n, pre, post, env);
447 current_ir_graph = rem;