renamed fucntions is_x*_type() to is_X*_type() to prevent name clash with EDg frontend
[libfirm] / ir / ir / irgwalk.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/ir/irgwalk.c
4  * Purpose:
5  * Author:      Boris Boesler
6  * Modified by: Goetz Lindenmaier
7  * Created:
8  * CVS-ID:      $Id$
9  * Copyright:   (c) 1999-2003 Universität Karlsruhe
10  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
11  */
12
13 /**
14  * @file irgwalk.c
15  *
16  * traverse an ir graph
17  * - execute the pre function before recursion
18  * - execute the post function after recursion
19  */
20
21
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #ifdef HAVE_STDLIB_H
27 # include <stdlib.h>
28 #endif
29
30 #include "irnode_t.h"
31 #include "irgraph_t.h" /* visited flag */
32 #include "irprog.h"
33 #include "irgwalk.h"
34 #include "typewalk.h"
35 #include "firmstat.h"
36 #include "ircgcons.h"
37
38 #include "eset.h"
39 #include "array.h"
40
41 /**
42  * Walk over an interprocedural graph (callgraph).
43  * Visits only graphs in irg_set.
44  */
45 static void irg_walk_cg(ir_node * node, unsigned long visited, eset * irg_set,
46                         irg_walk_func *pre, irg_walk_func *post, void * env) {
47   int i;
48   ir_graph * rem = current_ir_graph;
49   ir_node * pred;
50
51   assert(node && node->kind == k_ir_node);
52   if (get_irn_visited(node) >= visited) return;
53
54   set_irn_visited(node, visited);
55
56   if (pre) pre(node, env);
57
58   pred = skip_Proj(node);
59   if (get_irn_op(pred) == op_CallBegin
60       || get_irn_op(pred) == op_EndReg
61       || get_irn_op(pred) == op_EndExcept) {
62     current_ir_graph = get_irn_irg(pred);
63   }
64
65   if (is_no_Block(node)) { /* not block */
66     irg_walk_cg(get_nodes_block(node), visited, irg_set, pre, post, env);
67   }
68
69   if (get_irn_op(node) == op_Block) { /* block */
70     for (i = get_irn_arity(node) - 1; i >= 0; --i) {
71       ir_node * exec = get_irn_n(node, i);
72       ir_node * pred = skip_Proj(exec);
73       if ((get_irn_op(pred) != op_CallBegin
74            && get_irn_op(pred) != op_EndReg
75            && get_irn_op(pred) != op_EndExcept)
76           || eset_contains(irg_set, get_irn_irg(pred))) {
77         irg_walk_cg(exec, visited, irg_set, pre, post, env);
78       }
79     }
80   } else if (get_irn_op(node) == op_Filter) { /* filter */
81     for (i = get_irn_arity(node) - 1; i >= 0; --i) {
82       ir_node * pred = get_irn_n(node, i);
83       if (get_irn_op(pred) == op_Unknown || get_irn_op(pred) == op_Bad) {
84         irg_walk_cg(pred, visited, irg_set, pre, post, env);
85       } else {
86         ir_node * exec;
87         exec = skip_Proj(get_Block_cfgpred(get_nodes_block(node), i));
88
89         if (op_Bad == get_irn_op (exec)) {
90           continue;
91         }
92
93         assert(get_irn_op(exec) == op_CallBegin
94                || get_irn_op(exec) == op_EndReg
95                || get_irn_op(exec) == op_EndExcept);
96         if (eset_contains(irg_set, get_irn_irg(exec))) {
97           current_ir_graph = get_irn_irg(exec);
98           irg_walk_cg(pred, visited, irg_set, pre, post, env);
99           current_ir_graph = rem;
100         }
101       }
102     }
103   } else {                      /* everything else */
104     for (i = get_irn_arity(node) - 1; i >= 0; --i) {
105       irg_walk_cg(get_irn_n(node, i), visited, irg_set, pre, post, env);
106     }
107   }
108
109   if (post) post(node, env);
110
111   current_ir_graph = rem;
112 }
113
114
115 /**
116  * Insert all ir_graphs in irg_set, that are (transitive) reachable.
117  */
118 static void collect_irgs(ir_node * node, eset * irg_set) {
119   if (get_irn_op(node) == op_Call) {
120     int i;
121     for (i = get_Call_n_callees(node) - 1; i >= 0; --i) {
122       entity * ent = get_Call_callee(node, i);
123       ir_graph * irg = get_entity_irg(ent);
124       if (irg && !eset_contains(irg_set, irg)) {
125         eset_insert(irg_set, irg);
126         irg_walk_graph(irg, (irg_walk_func *) collect_irgs, NULL, irg_set);
127       }
128     }
129   }
130 }
131
132 /**
133  * specialized version of irg_walk_2, called if only pre callback exists
134  */
135 static void
136 irg_walk_2_pre(ir_node *node, irg_walk_func *pre, void * env) {
137   int i;
138   set_irn_visited(node, current_ir_graph->visited);
139
140   pre(node, env);
141
142   if (node->op != op_Block) {
143     ir_node *pred = get_irn_n(node, -1);
144     if (pred->visited < current_ir_graph->visited)
145       irg_walk_2_pre(pred, pre, env);
146   }
147   for (i = get_irn_arity(node) - 1; i >= 0; --i) {
148     ir_node *pred = get_irn_n(node, i);
149     if (pred->visited < current_ir_graph->visited)
150       irg_walk_2_pre(pred, pre, env);
151   }
152 }
153
154 /**
155  * specialized version of irg_walk_2, called if only post callback exists
156  */
157 static void
158 irg_walk_2_post(ir_node *node, irg_walk_func *post, void * env) {
159   int i;
160   set_irn_visited(node, current_ir_graph->visited);
161
162   if (node->op != op_Block) {
163     ir_node *pred = get_irn_n(node, -1);
164     if (pred->visited < current_ir_graph->visited)
165       irg_walk_2_post(pred, post, env);
166   }
167   for (i = get_irn_arity(node) - 1; i >= 0; --i) {
168     ir_node *pred = get_irn_n(node, i);
169     if (pred->visited < current_ir_graph->visited)
170       irg_walk_2_post(pred, post, env);
171   }
172
173   post(node, env);
174 }
175
176 /**
177  * specialized version of irg_walk_2, called if pre and post callbacks exist
178  */
179 static void
180 irg_walk_2_both(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void * env) {
181   int i;
182   set_irn_visited(node, current_ir_graph->visited);
183
184   pre(node, env);
185
186   if (node->op != op_Block) {
187     ir_node *pred = get_irn_n(node, -1);
188     if (pred->visited < current_ir_graph->visited)
189       irg_walk_2_both(pred, pre, post, env);
190   }
191   for (i = get_irn_arity(node) - 1; i >= 0; --i) {
192     ir_node *pred = get_irn_n(node, i);
193     if (pred->visited < current_ir_graph->visited)
194       irg_walk_2_both(pred, pre, post, env);
195   }
196
197   post(node, env);
198 }
199
200 /**
201  * Intraprozedural graph walker.
202  */
203 static void
204 irg_walk_2(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void * env)
205 {
206   if (node->visited < current_ir_graph->visited) {
207     if      (!post) irg_walk_2_pre (node, pre, env);
208     else if (!pre)  irg_walk_2_post(node, post, env);
209     else            irg_walk_2_both(node, pre, post, env);
210   }
211 }
212
213 /*
214  * generic graph walker
215  */
216 void irg_walk(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void *env)
217 {
218   assert(node  && node->kind==k_ir_node);
219
220   if (get_interprocedural_view()) {
221     eset * irg_set = eset_create();
222     unsigned long visited;
223     ir_graph * irg;
224     assert(get_irp_ip_view_state() == ip_view_valid);
225
226     set_interprocedural_view(false);
227     eset_insert(irg_set, current_ir_graph);
228     irg_walk(node, (irg_walk_func *) collect_irgs, NULL, irg_set);
229     set_interprocedural_view(true);
230     visited = get_max_irg_visited() + 1;
231     for (irg = eset_first(irg_set); irg; irg = eset_next(irg_set)) {
232       set_irg_visited(irg, visited);
233     }
234     irg_walk_cg(node, visited, irg_set, pre, post, env);
235     eset_destroy(irg_set);
236   } else {
237     inc_irg_visited(current_ir_graph);
238     irg_walk_2(node, pre, post, env);
239   }
240   return;
241 }
242
243 /*
244  * walk over a graph
245  */
246 void irg_walk_graph(ir_graph *irg, irg_walk_func *pre, irg_walk_func *post, void *env) {
247   ir_graph * rem = current_ir_graph;
248
249   stat_irg_walk(irg, (void *)pre, (void *)post);
250   current_ir_graph = irg;
251   irg_walk(get_irg_end(irg), pre, post, env);
252   current_ir_graph = rem;
253 }
254
255 /* Executes irg_walk(end, pre, post, env) for all irgraphs in irprog.
256    Sets current_ir_graph properly for each walk.  Conserves current
257    current_ir_graph. */
258 void all_irg_walk(irg_walk_func *pre, irg_walk_func *post, void *env) {
259   int i;
260   ir_graph *irg, *rem;
261
262   rem = current_ir_graph;
263
264   for (i = 0; i < get_irp_n_irgs(); i++) {
265     irg = get_irp_irg(i);
266     current_ir_graph = irg;
267     irg_walk(get_irg_end(irg), pre, post, env);
268   }
269   current_ir_graph = rem;
270 }
271
272 /***************************************************************************/
273
274 /* Returns current_ir_graph and sets it to the irg of predecessor index
275    of node n. */
276 static INLINE ir_graph *
277 switch_irg (ir_node *n, int index) {
278   ir_graph *old_current = current_ir_graph;
279
280   if (get_interprocedural_view()) {
281     /* Only Filter and Block nodes can have predecessors in other graphs. */
282     if (get_irn_op(n) == op_Filter)
283       n = get_nodes_block(n);
284     if (get_irn_op(n) == op_Block) {
285       ir_node *cfop = skip_Proj(get_Block_cfgpred(n, index));
286       if (is_ip_cfop(cfop)) {
287         current_ir_graph = get_irn_irg(cfop);
288       }
289     }
290   }
291
292   return old_current;
293 }
294
295 static void
296 cg_walk_2(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void * env)
297 {
298   int i;
299   ir_graph *rem = NULL;
300   assert(node);
301
302   if (get_irn_visited(node) < get_irg_visited(current_ir_graph)) {
303     set_irn_visited(node, get_irg_visited(current_ir_graph));
304
305     if (pre) pre(node, env);
306
307     if (is_no_Block(node))
308       cg_walk_2(get_nodes_block(node), pre, post, env);
309     for (i = get_irn_arity(node) - 1; i >= 0; --i) {
310       rem = switch_irg(node, i);  /* @@@ AS: Is this wrong? We do have to
311                                              switch to the irg of the predecessor, don't we? */
312       cg_walk_2(get_irn_n(node, i), pre, post, env);
313       current_ir_graph = rem;
314     }
315
316     if (post) post(node, env);
317   }
318   return;
319 }
320
321
322 /* Walks all irgs in interprocedural view.  Visits each node only once. */
323 void cg_walk(irg_walk_func *pre, irg_walk_func *post, void *env) {
324   int i;
325   ir_graph *rem = current_ir_graph;
326   int rem_view = get_interprocedural_view();
327
328   set_interprocedural_view(true);
329
330   inc_max_irg_visited();
331   /* Fix all irg_visited flags */
332   for (i = 0; i < get_irp_n_irgs(); i++)
333     set_irg_visited(get_irp_irg(i), get_max_irg_visited());
334
335   /* Walk starting at unreachable procedures. Only these
336    * have End blocks visible in interprocedural view. */
337   for (i = 0; i < get_irp_n_irgs(); i++) {
338     ir_node *sb;
339     current_ir_graph = get_irp_irg(i);
340
341     sb = get_irg_start_block(current_ir_graph);
342
343     if ((get_Block_n_cfgpreds(sb) > 1) ||
344     (get_nodes_block(get_Block_cfgpred(sb, 0)) != sb)) continue;
345
346     cg_walk_2(get_irg_end(current_ir_graph), pre, post, env);
347   }
348
349   /* Check whether we walked all procedures: there could be procedures
350      with cyclic calls but no call from the outside. */
351   for (i = 0; i < get_irp_n_irgs(); i++) {
352     ir_node *sb;
353     current_ir_graph = get_irp_irg(i);
354
355     /* Test start block: if inner procedure end and end block are not
356      * visible and therefore not marked. */
357     sb = get_irg_start_block(current_ir_graph);
358     if (get_irn_visited(sb) < get_irg_visited(current_ir_graph)) {
359       cg_walk_2(sb, pre, post, env);
360     }
361   }
362
363   /* Walk all endless loops in inner procedures.
364    * We recognize an inner procedure if the End node is not visited. */
365   for (i = 0; i < get_irp_n_irgs(); i++) {
366     ir_node *e;
367     current_ir_graph = get_irp_irg(i);
368     e = get_irg_end(current_ir_graph);
369     if (get_irn_visited(e) < get_irg_visited(current_ir_graph)) {
370       int j;
371       /* Don't visit the End node. */
372       for (j = 0; j < get_End_n_keepalives(e); j++)
373     cg_walk_2(get_End_keepalive(e, j), pre, post, env);
374     }
375   }
376
377   set_interprocedural_view(rem_view);
378   current_ir_graph = rem;
379 }
380
381
382 /***************************************************************************/
383
384 /* Walks back from n until it finds a real cf op. */
385 static ir_node *get_cf_op(ir_node *n) {
386   ir_node *pred;
387
388   n = skip_Id(n);
389   n = skip_Tuple(n);
390   pred = skip_Proj(n);
391   if (!(is_cfop(pred) || is_fragile_op(pred) ||
392     (get_irn_op(pred) == op_Bad)))
393     n = get_cf_op(n);
394
395   return skip_Proj(n);
396 }
397
398 static void irg_block_walk_2(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void *env)
399 {
400   int i;
401
402   if(get_Block_block_visited(node) < get_irg_block_visited(current_ir_graph)) {
403     set_Block_block_visited(node, get_irg_block_visited(current_ir_graph));
404
405     if(pre) pre(node, env);
406
407     for(i = get_Block_n_cfgpreds(node) - 1; i >= 0; --i) {
408       /* find the corresponding predecessor block. */
409       ir_node *pred = get_cf_op(get_Block_cfgpred(node, i));
410       pred = get_nodes_block(pred);
411       if(get_irn_opcode(pred) == iro_Block) {
412         /* recursion */
413         irg_block_walk_2(pred, pre, post, env);
414       }
415       else {
416         assert(get_irn_opcode(pred) == iro_Bad);
417       }
418     }
419
420     if(post) post(node, env);
421   }
422   return;
423 }
424
425
426 /* walks only over Block nodes in the graph.  Has it's own visited
427    flag, so that it can be interleaved with the other walker.         */
428 void irg_block_walk(ir_node *node, irg_walk_func *pre, irg_walk_func *post, void *env)
429 {
430   ir_node *block, *pred;
431   int i;
432
433   stat_irg_block_walk(current_ir_graph, node, (void *)pre, (void *)post);
434
435   assert(node);
436   assert(!get_interprocedural_view());   /* interprocedural_view not implemented, because it
437                     * interleaves with irg_walk */
438   inc_irg_block_visited(current_ir_graph);
439   if (is_no_Block(node)) block = get_nodes_block(node); else block = node;
440   assert(get_irn_opcode(block)  == iro_Block);
441   irg_block_walk_2(block, pre, post, env);
442
443   /* keepalive: the endless loops ... */
444   if (get_irn_op(node) == op_End) {
445     int arity = get_irn_arity(node);
446     for (i = 0; i < arity; i++) {
447       pred = get_irn_n(node, i);
448       if (get_irn_op(pred) == op_Block)
449         irg_block_walk_2(pred, pre, post, env);
450     }
451     /* Sometimes the blocks died, but are still reachable through Phis.
452      * Make sure the algorithms that try to remove these reach them. */
453     for (i = 0; i < arity; i++) {
454       pred = get_irn_n(node, i);
455       if (get_irn_op(pred) == op_Phi) {
456         ir_node *block = get_nodes_block(pred);
457
458         if (! is_Bad(block))
459           irg_block_walk_2(block, pre, post, env);
460       }
461     }
462   }
463
464   return;
465 }
466
467 /*
468  * walk over a graph block wise
469  */
470 void irg_block_walk_graph(ir_graph *irg, irg_walk_func *pre,
471               irg_walk_func *post, void *env) {
472   ir_graph * rem = current_ir_graph;
473   current_ir_graph = irg;
474   irg_block_walk(get_irg_end(irg), pre, post, env);
475   current_ir_graph = rem;
476 }
477
478 /********************************************************************/
479
480 typedef struct walk_env {
481   irg_walk_func *pre;
482   irg_walk_func *post;
483   void *env;
484 } walk_env;
485
486 /**
487  * Walk to all constant expressions in this entity.
488  */
489 static void walk_entity(entity *ent, void *env)
490 {
491   walk_env *my_env = (walk_env *)env;
492
493   if (get_entity_variability(ent) != variability_uninitialized) {
494     if (is_atomic_entity(ent)) {
495       irg_walk(get_atomic_ent_value(ent), my_env->pre, my_env->post, my_env->env);
496     }
497     else {
498       int i, n_vals = get_compound_ent_n_values(ent);
499
500       for (i = 0; i < n_vals; i++)
501         irg_walk(get_compound_ent_value(ent, i), my_env->pre, my_env->post, my_env->env);
502     }
503   }
504 }
505
506 /* Walks over all code in const_code_irg. */
507 void walk_const_code(irg_walk_func *pre, irg_walk_func *post, void *env) {
508   int i, j;
509   walk_env my_env;
510
511   ir_graph *rem = current_ir_graph;
512   current_ir_graph = get_const_code_irg();
513   inc_irg_visited(current_ir_graph);
514
515   my_env.pre = pre;
516   my_env.post = post;
517   my_env.env = env;
518
519   /* Walk all types that can contain constant entities.  */
520   walk_types_entities(get_glob_type(), &walk_entity, &my_env);
521   for (i = 0; i < get_irp_n_types(); i++)
522     walk_types_entities(get_irp_type(i), &walk_entity, &my_env);
523   for (i = 0; i < get_irp_n_irgs(); i++)
524     walk_types_entities(get_irg_frame_type(get_irp_irg(i)), &walk_entity, &my_env);
525
526   /* Walk constant array bounds. */
527   for (i = 0; i < get_irp_n_types(); i++) {
528     type *tp = get_irp_type(i);
529     if (is_Array_type(tp)) {
530       for (j = 0; j < get_array_n_dimensions(tp); j++) {
531         ir_node *n = get_array_lower_bound(tp, j);
532         if (n) irg_walk(n, pre, post, env);
533         n = get_array_upper_bound(tp, j);
534         if (n) irg_walk(n, pre, post, env);
535       }
536     }
537   }
538
539   current_ir_graph = rem;
540 }