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"
45 * specialized version of irg_walk_2, called if only pre callback exists
47 * @return number of visited nodes
49 static unsigned irg_walk_2_pre(ir_node *node, irg_walk_func *pre, void *env)
53 ir_graph *irg = get_irn_irg(node);
55 set_irn_visited(node, irg->visited);
59 if (node->op != op_Block) {
60 ir_node *pred = get_irn_n(node, -1);
61 if (pred->visited < irg->visited)
62 cnt += irg_walk_2_pre(pred, pre, env);
64 for (i = get_irn_arity(node) - 1; i >= 0; --i) {
65 ir_node *pred = get_irn_n(node, i);
66 if (pred->visited < irg->visited)
67 cnt += irg_walk_2_pre(pred, pre, env);
73 * specialized version of irg_walk_2, called if only post callback exists
75 * @return number of visited nodes
77 static unsigned irg_walk_2_post(ir_node *node, irg_walk_func *post, void *env)
81 ir_graph *irg = get_irn_irg(node);
83 set_irn_visited(node, irg->visited);
85 if (node->op != op_Block) {
86 ir_node *pred = get_irn_n(node, -1);
87 if (pred->visited < irg->visited)
88 cnt += irg_walk_2_post(pred, post, env);
90 for (i = get_irn_arity(node) - 1; i >= 0; --i) {
91 ir_node *pred = get_irn_n(node, i);
92 if (pred->visited < irg->visited)
93 cnt += irg_walk_2_post(pred, post, env);
102 * specialized version of irg_walk_2, called if pre and post callbacks exist
104 * @return number of visited nodes
106 static unsigned irg_walk_2_both(ir_node *node, irg_walk_func *pre,
107 irg_walk_func *post, void *env)
111 ir_graph *irg = get_irn_irg(node);
113 set_irn_visited(node, irg->visited);
117 if (node->op != op_Block) {
118 ir_node *pred = get_irn_n(node, -1);
119 if (pred->visited < irg->visited)
120 cnt += irg_walk_2_both(pred, pre, post, env);
122 for (i = get_irn_arity(node) - 1; i >= 0; --i) {
123 ir_node *pred = get_irn_n(node, i);
124 if (pred->visited < irg->visited)
125 cnt += irg_walk_2_both(pred, pre, post, env);
133 unsigned irg_walk_2(ir_node *node, irg_walk_func *pre, irg_walk_func *post,
136 if (irn_visited(node))
139 if (!post) return irg_walk_2_pre (node, pre, env);
140 else if (!pre) return irg_walk_2_post(node, post, env);
141 else return irg_walk_2_both(node, pre, post, env);
145 static unsigned nodes_touched = 0;
147 void irg_walk_core(ir_node *node, irg_walk_func *pre, irg_walk_func *post,
150 assert(is_ir_node(node));
151 nodes_touched = irg_walk_2(node, pre, post, env);
154 void irg_walk(ir_node *node, irg_walk_func *pre, irg_walk_func *post,
157 ir_graph *irg = get_irn_irg(node);
158 ir_graph *rem = current_ir_graph;
160 current_ir_graph = irg;
161 ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED);
162 inc_irg_visited(irg);
163 irg_walk_core(node, pre, post, env);
164 ir_free_resources(irg, IR_RESOURCE_IRN_VISITED);
165 current_ir_graph = rem;
168 void irg_walk_graph(ir_graph *irg, irg_walk_func *pre, irg_walk_func *post, void *env)
170 ir_graph * rem = current_ir_graph;
172 hook_irg_walk(irg, (generic_func *)pre, (generic_func *)post);
173 current_ir_graph = irg;
174 irg_walk(get_irg_end(irg), pre, post, env);
175 irg->estimated_node_count = nodes_touched;
176 current_ir_graph = rem;
179 void all_irg_walk(irg_walk_func *pre, irg_walk_func *post, void *env)
184 for (i = 0, n = get_irp_n_irgs(); i < n; i++) {
185 irg = get_irp_irg(i);
186 irg_walk_graph(irg, pre, post, env);
191 * specialized version of irg_walk_in_or_dep_2, called if only pre callback exists
193 * @return number of visited nodes
195 static unsigned irg_walk_in_or_dep_2_pre(ir_node *node, irg_walk_func *pre, void *env)
199 ir_graph *irg = get_irn_irg(node);
201 set_irn_visited(node, irg->visited);
205 if (node->op != op_Block) {
206 ir_node *pred = get_irn_n(node, -1);
207 if (pred->visited < irg->visited)
208 cnt += irg_walk_in_or_dep_2_pre(pred, pre, env);
210 for (i = get_irn_ins_or_deps(node) - 1; i >= 0; --i) {
211 ir_node *pred = get_irn_in_or_dep(node, i);
212 if (pred->visited < irg->visited)
213 cnt += irg_walk_in_or_dep_2_pre(pred, pre, env);
219 * specialized version of irg_walk_in_or_dep_2, called if only post callback exists
221 * @return number of visited nodes
223 static unsigned irg_walk_in_or_dep_2_post(ir_node *node, irg_walk_func *post, void *env)
227 ir_graph *irg = get_irn_irg(node);
229 set_irn_visited(node, irg->visited);
231 if (node->op != op_Block) {
232 ir_node *pred = get_irn_n(node, -1);
233 if (pred->visited < irg->visited)
234 cnt += irg_walk_in_or_dep_2_post(pred, post, env);
236 for (i = get_irn_ins_or_deps(node) - 1; i >= 0; --i) {
237 ir_node *pred = get_irn_in_or_dep(node, i);
238 if (pred->visited < irg->visited)
239 cnt += irg_walk_in_or_dep_2_post(pred, post, env);
248 * specialized version of irg_walk_in_or_dep_2, called if pre and post callbacks exist
250 * @return number of visited nodes
252 static unsigned irg_walk_in_or_dep_2_both(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void *env)
256 ir_graph *irg = get_irn_irg(node);
258 set_irn_visited(node, irg->visited);
262 if (node->op != op_Block) {
263 ir_node *pred = get_irn_n(node, -1);
264 if (pred->visited < irg->visited)
265 cnt += irg_walk_in_or_dep_2_both(pred, pre, post, env);
267 for (i = get_irn_ins_or_deps(node) - 1; i >= 0; --i) {
268 ir_node *pred = get_irn_in_or_dep(node, i);
269 if (pred->visited < irg->visited)
270 cnt += irg_walk_in_or_dep_2_both(pred, pre, post, env);
279 * Intraprozedural graph walker. Follows dependency edges as well.
281 * @return number of visited nodes
283 static unsigned irg_walk_in_or_dep_2(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void *env)
285 if (irn_visited(node))
288 if (! post) return irg_walk_in_or_dep_2_pre (node, pre, env);
289 else if (! pre) return irg_walk_in_or_dep_2_post(node, post, env);
290 else return irg_walk_in_or_dep_2_both(node, pre, post, env);
293 void irg_walk_in_or_dep(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void *env)
295 assert(is_ir_node(node));
297 ir_reserve_resources(current_ir_graph, IR_RESOURCE_IRN_VISITED);
298 inc_irg_visited(current_ir_graph);
299 nodes_touched = irg_walk_in_or_dep_2(node, pre, post, env);
300 ir_free_resources(current_ir_graph, IR_RESOURCE_IRN_VISITED);
303 void irg_walk_in_or_dep_graph(ir_graph *irg, irg_walk_func *pre, irg_walk_func *post, void *env)
305 ir_graph * rem = current_ir_graph;
307 hook_irg_walk(irg, (generic_func *)pre, (generic_func *)post);
308 current_ir_graph = irg;
309 irg_walk_in_or_dep(get_irg_end(irg), pre, post, env);
310 irg->estimated_node_count = nodes_touched;
311 current_ir_graph = rem;
314 /* Walks back from n until it finds a real cf op. */
315 static ir_node *get_cf_op(ir_node *n)
317 while (!is_cfop(n) && !is_fragile_op(n) && !is_Bad(n)) {
325 static void irg_block_walk_2(ir_node *node, irg_walk_func *pre,
326 irg_walk_func *post, void *env)
330 if (Block_block_visited(node))
332 mark_Block_block_visited(node);
337 for (i = get_Block_n_cfgpreds(node) - 1; i >= 0; --i) {
338 /* find the corresponding predecessor block. */
339 ir_node *pred = get_cf_op(get_Block_cfgpred(node, i));
340 pred = get_nodes_block(pred);
341 if (get_irn_opcode(pred) == iro_Block) {
343 irg_block_walk_2(pred, pre, post, env);
345 assert(get_irn_opcode(pred) == iro_Bad);
353 void irg_block_walk(ir_node *node, irg_walk_func *pre, irg_walk_func *post,
356 ir_graph *irg = get_irn_irg(node);
357 ir_node *block = is_Block(node) ? node : get_nodes_block(node);
359 hook_irg_block_walk(irg, node, (generic_func *)pre, (generic_func *)post);
361 ir_reserve_resources(irg, IR_RESOURCE_BLOCK_VISITED);
362 inc_irg_block_visited(irg);
363 irg_block_walk_2(block, pre, post, env);
365 /* Some blocks might be only reachable through keep-alive edges */
367 int arity = get_irn_arity(node);
369 for (i = 0; i < arity; i++) {
370 ir_node *pred = get_irn_n(node, i);
373 irg_block_walk_2(pred, pre, post, env);
377 ir_free_resources(irg, IR_RESOURCE_BLOCK_VISITED);
380 void irg_block_walk_graph(ir_graph *irg, irg_walk_func *pre,
381 irg_walk_func *post, void *env)
383 ir_graph * rem = current_ir_graph;
384 current_ir_graph = irg;
385 irg_block_walk(get_irg_end(irg), pre, post, env);
386 current_ir_graph = rem;
389 void irg_walk_anchors(ir_graph *irg, irg_walk_func *pre, irg_walk_func *post, void *env)
391 ir_graph * rem = current_ir_graph;
392 current_ir_graph = irg;
394 ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED);
395 inc_irg_visited(irg);
396 irg_walk_2(irg->anchor, pre, post, env);
397 ir_free_resources(irg, IR_RESOURCE_IRN_VISITED);
399 current_ir_graph = rem;
402 typedef struct walk_env {
408 static void walk_initializer(ir_initializer_t *initializer, walk_env *env)
410 switch (initializer->kind) {
411 case IR_INITIALIZER_CONST:
412 irg_walk(initializer->consti.value, env->pre, env->post, env->env);
414 case IR_INITIALIZER_TARVAL:
415 case IR_INITIALIZER_NULL:
418 case IR_INITIALIZER_COMPOUND: {
420 for (i = 0; i < initializer->compound.n_initializers; ++i) {
421 ir_initializer_t *subinitializer
422 = initializer->compound.initializers[i];
423 walk_initializer(subinitializer, env);
428 panic("invalid initializer found");
432 * Walk to all constant expressions in this entity.
434 static void walk_entity(ir_entity *ent, void *env)
436 walk_env *my_env = (walk_env *)env;
438 if (ent->initializer != NULL) {
439 walk_initializer(ent->initializer, my_env);
440 } else if (entity_has_compound_ent_values(ent)) {
441 size_t i, n_vals = get_compound_ent_n_values(ent);
443 for (i = 0; i < n_vals; i++)
444 irg_walk(get_compound_ent_value(ent, i), my_env->pre, my_env->post, my_env->env);
448 void walk_const_code(irg_walk_func *pre, irg_walk_func *post, void *env)
455 ir_graph *rem = current_ir_graph;
456 current_ir_graph = get_const_code_irg();
457 inc_irg_visited(current_ir_graph);
463 /* Walk all types that can contain constant entities. */
464 for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s)
465 walk_types_entities(get_segment_type(s), &walk_entity, &my_env);
466 n_types = get_irp_n_types();
467 for (i = 0; i < n_types; i++)
468 walk_types_entities(get_irp_type(i), &walk_entity, &my_env);
469 for (i = 0; i < get_irp_n_irgs(); i++)
470 walk_types_entities(get_irg_frame_type(get_irp_irg(i)), &walk_entity, &my_env);
472 /* Walk constant array bounds. */
473 for (i = 0; i < n_types; i++) {
474 ir_type *tp = get_irp_type(i);
475 if (is_Array_type(tp)) {
476 size_t j, n_dim = get_array_n_dimensions(tp);
477 for (j = 0; j < n_dim; j++) {
478 ir_node *n = get_array_lower_bound(tp, j);
479 if (n) irg_walk(n, pre, post, env);
480 n = get_array_upper_bound(tp, j);
481 if (n) irg_walk(n, pre, post, env);
486 current_ir_graph = rem;