Typo fixed.
[libfirm] / ir / ir / ircgcons.c
1 /* -------------------------------------------------------------------
2  * $Id$
3  * -------------------------------------------------------------------
4  * Auf- und Abbau der interprozeduralen Darstellung (Explizite
5  * interprozedurale Abhängigkeiten).
6  *
7  * Erstellt: Hubert Schmid, 09.06.2002
8  * ---------------------------------------------------------------- */
9
10
11 #include <string.h>
12 #include "ircgcons.h"
13
14 #include "array.h"
15 #include "irprog.h"
16 #include "ircons.h"
17 #include "irgmod.h"
18 #include "irgwalk.h"
19 #include "irflag.h"
20 #include "misc.h"
21
22
23 /* Datenstruktur für jede Methode */
24 typedef struct {
25   int count;
26   bool open;                      /* offene Methode (mit unbekanntem Aufrufer) */
27   ir_node * reg, * mem, ** res;   /* EndReg, Mem und Rückgabewerte */
28   ir_node * except, * except_mem; /* EndExcept und Mem für Ausnahmeabbruch */
29 } irg_data_t;
30
31
32 static irg_data_t * irg_data_create(void) {
33   irg_data_t * data = xmalloc(sizeof(irg_data_t));
34   memset(data, 0, sizeof(irg_data_t)); /* init */
35   return data;
36 }
37
38
39 /* Die Anzahl der Aufrufer jeder Methode zählen (irg_data_t->count), und die
40  * offenen Methoden (mit unbekannten Vorgänger) markieren. */
41 static void caller_init(int arr_length, entity ** free_methods) {
42   int i, j;
43   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
44     set_entity_link(get_irg_ent(get_irp_irg(i)), irg_data_create());
45   }
46   for (i = arr_length - 1; i >= 0; --i) {
47     irg_data_t * data = get_entity_link(free_methods[i]);
48     data->open = true;
49   }
50   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
51     ir_graph * irg = get_irp_irg(i);
52     ir_node * call;
53     /* Die Call-Knoten sind (mit den Proj-Knoten) am End-Knoten verlinkt! */
54     for (call = get_irn_link(get_irg_end(irg)); call; call = get_irn_link(call)) {
55       if (get_irn_op(call) != op_Call) continue;
56       for (j = get_Call_n_callees(call) - 1; j >= 0; --j) {
57         entity * ent = get_Call_callee(call, j);
58         if (ent) {
59           irg_data_t * data = get_entity_link(ent);
60           assert(get_entity_irg(ent) && data);
61           ++data->count;
62         }
63       }
64     }
65   }
66 }
67
68
69 static INLINE void clear_link(ir_node * node, void * env) {
70   set_irn_link(node, NULL);
71 }
72
73 /*
74 static INLINE ir_node * tail(ir_node * node) {
75   ir_node * link;
76   for (; (link = get_irn_link(node)); node = link) ;
77   return node;
78 }
79 */
80
81 /* Call-Operationen an die "link"-Liste von "call_tail" anhängen (und
82  * "call_tail" aktualisieren), Proj-Operationen in die Liste ihrer Definition
83  * (auch bei Proj->Call Operationen) und Phi-Operationen in die Liste ihres
84  * Grundblocks einfügen. */
85 static void collect_phicallproj_walker(ir_node * node, ir_node ** call_tail) {
86   if (get_irn_op(node) == op_Call) {
87     /* Die Liste von Call an call_tail anhängen. */
88     ir_node * link;
89     assert(get_irn_link(*call_tail) == NULL);
90     set_irn_link(*call_tail, node);
91     /* call_tail aktualisieren: */
92     for (link = get_irn_link(*call_tail); link; *call_tail = link, link = get_irn_link(link)) ;
93   } else if (get_irn_op(node) == op_Proj) {
94     ir_node * head = skip_Proj(get_Proj_pred(node));
95     set_irn_link(node, get_irn_link(head));
96     set_irn_link(head, node);
97     /* call_tail gegebenenfalls aktualisieren: */
98     if (head == *call_tail) {
99       *call_tail = node;
100     }
101   } else if (get_irn_op(node) == op_Phi) {
102     ir_node * block = get_nodes_Block(node);
103     set_irn_link(node, get_irn_link(block));
104     set_irn_link(block, node);
105   }
106 }
107
108
109 static void link(ir_node * head, ir_node * node) {
110   if (node) {
111     set_irn_link(node, get_irn_link(head));
112     set_irn_link(head, node);
113   }
114 }
115
116
117 /* Die Call-Operationen aller Graphen an den End-Operationen
118  * verlinken, die Proj-Operationen an ihren Definitionen und die
119  * Phi-Operationen an ihren Grundblöcken. Die Liste der Calls sieht
120  * dann so aus: End -> Call -> Proj -> ... -> Proj -> Call -> Proj ->
121  * ... -> Proj -> NULL. */
122 static void collect_phicallproj(void) {
123   int i;
124   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
125     ir_graph * irg = get_irp_irg(i);
126     ir_node * start = get_irg_start(irg);
127     ir_node * end = get_irg_end(irg);
128     current_ir_graph = irg;
129     assert(irg && start);
130     /* Die speziellen Parameter der Start-Operation extra verlinken,
131      * auch wenn sie nicht im intraprozeduralen Graphen erreichbar
132      * sind. */
133     link(start, get_irg_frame(irg));
134     link(start, get_irg_globals(irg));
135     /* walk */
136     irg_walk_graph(irg, clear_link, (irg_walk_func *) collect_phicallproj_walker, &end);
137   }
138 }
139
140
141 /* Proj-Operation durch Filter-Operation im aktuellen Block ersetzen. */
142 static ir_node * exchange_proj(ir_node * proj) {
143   ir_node * filter;
144   assert(get_irn_op(proj) == op_Proj);
145   filter = new_Filter(get_Proj_pred(proj), get_irn_mode(proj), get_Proj_proj(proj));
146   assert(get_Proj_proj(proj) == get_Filter_proj(filter)); /* XXX:SID */
147   /* Die Proj- (Id-) Operation sollte im gleichen Grundblock stehen, wie die
148    * Filter-Operation. */
149   set_nodes_Block(proj, get_nodes_Block(filter));
150   exchange(proj, filter);
151   return filter;
152 }
153
154
155 /* Echt neue Block-Operation erzeugen. CSE abschalten! */
156 static ir_node * create_Block(int n, ir_node ** in) {
157   /* Turn off optimizations so that blocks are not merged again. */
158   int rem_opt = get_optimize();
159   ir_node * block;
160   set_optimize(0);
161   block = new_Block(n, in);
162   set_optimize(rem_opt);
163   return block;
164 }
165
166
167 static void prepare_irg_end(ir_graph * irg, irg_data_t * data);
168 static void prepare_irg_end_except(ir_graph * irg, irg_data_t * data);
169
170
171 /* IRG vorbereiten. Proj-Operationen der Start-Operation in Filter-Operationen
172  * umwandeln. Die künstlichen Steuerzusammenflüsse EndReg und EndExcept
173  * einfügen. An der Start-Operation hängt nach dem Aufruf eine Liste der
174  * entsprechenden Filter-Knoten. */
175 static void prepare_irg(ir_graph * irg, irg_data_t * data) {
176   ir_node * start_block = get_irg_start_block(irg);
177   ir_node * link, * proj;
178   int n_callers = data->count + (data->open ? 1 : 0);
179   ir_node ** in = NEW_ARR_F(ir_node *, n_callers);
180
181   current_ir_graph = irg;
182   set_irg_current_block(irg, start_block);
183
184   /* Grundblock interprozedural machen. */
185   /* "in" ist nicht initialisiert. Das passiert erst in "construct_start". */
186   set_Block_cg_cfgpred_arr(start_block, n_callers, in);
187   /* Proj-Operationen durch Filter-Operationen ersetzen und (sonst) in
188    * den Start-Block verschieben. */
189   for (proj = get_irn_link(get_irg_start(irg)); proj; proj = get_irn_link(proj)) {
190     if (get_Proj_pred(proj) != get_irg_start(irg)
191         || (get_Proj_proj(proj) != pns_initial_exec && get_Proj_proj(proj) != pns_args)) {
192       ir_node * filter = exchange_proj(proj);
193       set_Filter_cg_pred_arr(filter, n_callers, in);
194     } else {
195       set_nodes_Block(proj, start_block);
196     }
197   }
198
199   DEL_ARR_F(in);
200
201   /* Liste der Filter-Operationen herstellen. Dabei muss man beachten,
202    * dass oben für "verschiedene" Proj-Operationen wegen CSE nur eine
203    * Filter-Operation erzeugt worden sein kann. */
204   for (link = get_irg_start(irg), proj = get_irn_link(link); proj; proj = get_irn_link(proj)) {
205     if (get_irn_op(proj) == op_Id) { /* replaced with filter */
206       ir_node * filter = get_Id_pred(proj);
207       assert(get_irn_op(filter) == op_Filter);
208       if (filter != link && get_irn_link(filter) == NULL) {
209         set_irn_link(link, filter);
210         link = filter;
211       }
212     }
213   }
214   /* Globle Einträge für ersetzte Operationen korrigieren. */
215   set_irg_frame(irg, skip_nop(get_irg_frame(irg)));
216   set_irg_globals(irg, skip_nop(get_irg_globals(irg)));
217
218   /* Unbekannten Aufrufer sofort eintragen. */
219   if (data->open) {
220     set_Block_cg_cfgpred(start_block, 0, new_Unknown());
221     for (proj = get_irn_link(get_irg_start(irg)); proj; proj = get_irn_link(proj)) {
222       if (get_irn_op(proj) == op_Filter) {
223         set_Filter_cg_pred(proj, 0, new_Unknown());
224       }
225     }
226     data->count = 1;
227   } else {
228     data->count = 0;
229   }
230
231   prepare_irg_end(irg, data);
232   prepare_irg_end_except(irg, data);
233 }
234
235
236 /* Künstlicher Steuerzusammenfluss EndReg einfügen. */
237 static void prepare_irg_end(ir_graph * irg, irg_data_t * data) {
238   ir_node * end_block = get_irg_end_block(irg);
239   ir_node * end  = get_irg_end(irg);
240   ir_node ** ret_arr = NULL;
241   int i, j;
242   int n_ret = 0;
243   ir_node ** cfgpred_arr = get_Block_cfgpred_arr(end_block);
244   for (i = get_Block_n_cfgpreds(end_block) - 1; i >= 0; --i) {
245     if (get_irn_op(cfgpred_arr[i]) == op_Return) {
246       if (ret_arr) {
247         ARR_APP1(ir_node *, ret_arr, cfgpred_arr[i]);
248       } else {
249         ret_arr = NEW_ARR_F(ir_node *, 1);
250         ret_arr[0] = cfgpred_arr[i];
251       }
252       ++n_ret;
253     }
254   }
255   if (n_ret > 0) {
256     int n_res = get_method_n_ress(get_entity_type(get_irg_ent(irg)));
257     ir_node ** in = NEW_ARR_F(ir_node *, n_ret);
258     /* block */
259     for (i = n_ret - 1; i >= 0; --i) {
260       set_irg_current_block(irg, get_nodes_Block(ret_arr[i]));
261       in[i] = new_Jmp();
262     }
263     create_Block(n_ret, in);
264     /* end */
265     data->reg = new_EndReg();
266     /* mem */
267     for (i = n_ret - 1; i >= 0; --i) {
268       in[i] = get_Return_mem(ret_arr[i]);
269     }
270     data->mem = new_Phi(n_ret, in, mode_M);
271     /* This Phi is a merge, therefor needs not be kept alive.
272        It might be optimized away, though.  */
273     if (get_End_keepalive(end, get_End_n_keepalives(end)-1 ) == data->mem)
274       set_End_keepalive(end, get_End_n_keepalives(end)-1, new_Bad());
275     /* res */
276     data->res = NEW_ARR_F(ir_node *, n_res);
277     for (j = n_res - 1; j >= 0; --j) {
278       ir_mode *mode = NULL;
279       /* In[0] could be a Bad node with wrong mode. */
280       for (i = n_ret - 1; i >= 0; --i) {
281         in[i] = get_Return_res(ret_arr[i], j);
282         if (!mode && get_irn_mode(in[i]) != mode_T)
283           mode = get_irn_mode(in[i]);
284       }
285       if (mode)
286         data->res[j] = new_Phi(n_ret, in, mode);
287       else  /* All preds are Bad */
288         data->res[j] = new_Bad();
289     }
290     DEL_ARR_F(in);
291   }
292   if (ret_arr) DEL_ARR_F(ret_arr);
293 }
294
295
296 /* Künstlicher Steuerzusammenfluss EndExcept einfügen. */
297 static void prepare_irg_end_except(ir_graph * irg, irg_data_t * data) {
298   ir_node * end_block = get_irg_end_block(irg);
299   ir_node * end = get_irg_end(irg);
300   ir_node ** except_arr = NULL;
301   int i;
302   int n_except = 0;
303   ir_node ** cfgpred_arr = get_Block_cfgpred_arr(end_block);
304   for (i = get_Block_n_cfgpreds(end_block) - 1; i >= 0; --i) {
305     if (get_irn_op(cfgpred_arr[i]) != op_Return) {
306       if (except_arr) {
307         ARR_APP1(ir_node *, except_arr, cfgpred_arr[i]);
308       } else {
309         except_arr = NEW_ARR_F(ir_node *, 1);
310         except_arr[0] = cfgpred_arr[i];
311       }
312       ++n_except;
313     }
314   }
315   if (n_except > 0) {
316     ir_node ** in = NEW_ARR_F(ir_node *, n_except);
317     /* block */
318     create_Block(n_except, except_arr);
319     /* end_except */
320     data->except = new_EndExcept();
321     /* mem */
322     for (i = n_except - 1; i >= 0; --i) {
323       ir_node * node = skip_Proj(except_arr[i]);
324       if (get_irn_op(node) == op_Call) {
325         in[i] = new_r_Proj(irg, get_nodes_Block(node), node, mode_M, 3);
326       } else if (get_irn_op(node) == op_Raise) {
327         in[i] = new_r_Proj(irg, get_nodes_Block(node), node, mode_M, 1);
328       } else {
329         assert(is_fragile_op(node));
330         /* We rely that all cfops have the memory output at the same position. */
331         in[i] = new_r_Proj(irg, get_nodes_Block(node), node, mode_M, 0);
332       }
333     }
334     data->except_mem = new_Phi(n_except, in, mode_M);
335     /* This Phi is a merge, therefor needs not be kept alive.
336        It might be optimized away, though.  */
337     if (get_End_keepalive(end, get_End_n_keepalives(end)-1 )
338         == data->except_mem)
339       set_End_keepalive(end, get_End_n_keepalives(end)-1, new_Bad());
340     DEL_ARR_F(in);
341   }
342   if (except_arr) DEL_ARR_F(except_arr);
343 }
344
345
346 /* Zwischengespeicherte Daten wieder freigeben. */
347 static void cleanup_irg(ir_graph * irg) {
348   entity * ent = get_irg_ent(irg);
349   irg_data_t * data = get_entity_link(ent);
350   assert(data);
351   if (data->res) DEL_ARR_F(data->res);
352   set_entity_link(ent, NULL);
353   free(data);
354 }
355
356
357 /* Alle Phi-Operationen aus "from_block" nach "to_block"
358  * verschieben. Die Phi-Operationen müssen am zugehörigen Grundblock
359  * verlinkt sein. Danach sind sie am neuen Grundblock verlinkt. */
360 static void move_phis(ir_node * from_block, ir_node * to_block) {
361   ir_node * phi;
362   for (phi = get_irn_link(from_block); phi != NULL; phi = get_irn_link(phi)) {
363     set_nodes_Block(phi, to_block);
364   }
365   assert(get_irn_link(to_block) == NULL);
366   set_irn_link(to_block, get_irn_link(from_block));
367   set_irn_link(from_block, NULL);
368 }
369
370
371 /* Rekursiv die Operation "node" und alle ihre Vorgänger aus dem Block
372  * "from_block" nach "to_block" verschieben. */
373 static void move_nodes(ir_node * from_block, ir_node * to_block, ir_node * node) {
374   int i;
375   for (i = get_irn_arity(node) - 1; i >= 0; --i) {
376     ir_node * pred = get_irn_n(node, i);
377     if (get_nodes_Block(pred) == from_block) {
378       move_nodes(from_block, to_block, pred);
379     }
380   }
381   set_nodes_Block(node, to_block);
382 }
383
384
385 /* Abhängigkeiten vom Start-Block und den Filter-Operationen im
386  * Start-Block auf den Aufrufer hinzufügen. */
387 static void construct_start(entity * caller, entity * callee,
388                             ir_node * call, ir_node * exec) {
389   irg_data_t * data = get_entity_link(callee);
390   ir_graph * irg = get_entity_irg(callee);
391   ir_node * start = get_irg_start(irg), * filter;
392
393   assert(irg);
394   assert(get_entity_peculiarity(callee) == existent); /* Else data is not initalized. */
395   assert((0 <= data->count) &&
396          (data->count < get_Block_cg_n_cfgpreds(get_nodes_Block(start))));
397   set_Block_cg_cfgpred(get_nodes_Block(start), data->count, exec);
398   for (filter = get_irn_link(start); filter; filter = get_irn_link(filter)) {
399     if (get_irn_op(filter) != op_Filter) continue;
400     if (get_Proj_pred(filter) == start) {
401       switch ((int) get_Proj_proj(filter)) {
402       case pns_global_store:
403         set_Filter_cg_pred(filter, data->count, get_Call_mem(call));
404         break;
405       case pns_frame_base:
406         /* "frame_base" wird nur durch Unknown dargestellt. Man kann ihn aber
407          * auch explizit darstellen, wenn sich daraus Vorteile für die
408          * Datenflussanalyse ergeben. */
409         set_Filter_cg_pred(filter, data->count, new_Unknown());
410         break;
411       case pns_globals:
412         /* "globals" wird nur durch Unknown dargestellt. Man kann ihn aber auch
413          * explizit darstellen, wenn sich daraus Vorteile für die
414          * Datenflussanalyse ergeben. */
415         set_Filter_cg_pred(filter, data->count, new_Unknown());
416         break;
417       default:
418         /* not reached */
419         assert(0 && "not reached");
420         break;
421       }
422     } else {
423       set_Filter_cg_pred(filter, data->count, get_Call_param(call, get_Proj_proj(filter)));
424     }
425   }
426   ++data->count;
427 }
428
429
430 /* Abhängigkeiten für den Speicherzustand über alle aufgerufenen
431  * Methoden bestimmen. */
432 static void fill_mem(int length, irg_data_t * data[], ir_node * in[]) {
433   int i;
434   for (i = 0; i < length; ++i) {
435     if (data[i]) { /* explicit */
436       if (data[i]->reg) {
437         in[i] = data[i]->mem;
438       } else {
439         in[i] = new_Bad();
440       }
441     } else { /* unknown */
442       in[i] = new_Unknown();
443     }
444   }
445 }
446
447
448 /* Abhängigkeiten für den Ausnahme-Speicherzustand über alle
449  * aufgerufenen Methoden bestimmen. */
450 static void fill_except_mem(int length, irg_data_t * data[], ir_node * in[]) {
451   int i;
452   for (i = 0; i < length; ++i) {
453     if (data[i]) { /* explicit */
454       if (data[i]->except) {
455         in[i] = data[i]->except_mem;
456       } else {
457         in[i] = new_Bad();
458       }
459     } else { /* unknown */
460       in[i] = new_Unknown();
461     }
462   }
463 }
464
465
466 /* Abhängigkeiten für ein Ergebnis über alle aufgerufenen Methoden
467  * bestimmen. */
468 static void fill_result(int pos, int length, irg_data_t * data[], ir_node * in[]) {
469   int i;
470   for (i = 0; i < length; ++i) {
471     if (data[i]) { /* explicit */
472       if (data[i]->reg) {
473         in[i] = data[i]->res[pos];
474       } else {
475         in[i] = new_Bad();
476       }
477     } else { /* unknown */
478       in[i] = new_Unknown();
479     }
480   }
481 }
482
483
484 /* Proj auf Except-X einer Call-Operation (aus der Link-Liste) bestimmen. */
485 static ir_node * get_except(ir_node * call) {
486   /* Mit CSE könnte man das effizienter machen! Die Methode wird aber für jede
487    * Aufrufstelle nur ein einziges Mal aufgerufen. */
488   ir_node * proj;
489   for (proj = get_irn_link(call); proj && get_irn_op(proj) == op_Proj; proj = get_irn_link(proj)) {
490     if (get_Proj_proj(proj) == 1 && get_irn_op(get_Proj_pred(proj)) == op_Call) {
491       return proj;
492     }
493   }
494   return NULL;
495 }
496
497
498 /* Grundblock der Call-Operation aufteilen. CallBegin- und Filter-Operationen
499  * einfügen. Die Steuer- und Datenflussabhängigkeiten von den aufgerufenen
500  * Methoden auf die CallBegin-Operation, und von der Aufrufstelle auf die
501  * aufgerufenen Methoden eintragen. */
502 static void construct_call(ir_node * call) {
503   int n_callees = get_Call_n_callees(call);
504   ir_node * post_block = get_nodes_Block(call); /* block nach dem Aufruf */
505   ir_node * pre_block = create_Block(get_Block_n_cfgpreds(post_block),
506                                      get_Block_cfgpred_arr(post_block)); /* block vor dem Aufruf (mit CallBegin) */
507   ir_node * except_block = NULL, * proj;
508   ir_node * jmp = new_Break(); /* Sprung für intraprozedurale Darstellung (in
509                                 * pre_block) */
510   ir_node * call_begin = new_CallBegin(call); /* (in pre_block) */
511   ir_node ** in = NEW_ARR_F(ir_node *, n_callees);
512   entity * caller = get_irg_ent(current_ir_graph); /* entity des aktuellen ir_graph */
513   entity ** callees = NEW_ARR_F(entity *, n_callees); /* aufgerufene Methoden: entity */
514   ir_graph ** irgs = NEW_ARR_F(ir_graph *, n_callees); /* aufgerufene Methoden: ir_graph */
515   irg_data_t ** data = NEW_ARR_F(irg_data_t *, n_callees); /* aufgerufene Methoden: irg_data_t */
516   int i;
517
518   /* post_block kann bereits interprozedurale Steuerflussvorgänger
519    * besitzen. Diese müssen dann auch noch für den pre_block gesetzt werden. */
520   if (get_Block_cg_cfgpred_arr(post_block)) {
521     set_Block_cg_cfgpred_arr(pre_block, get_Block_cg_n_cfgpreds(post_block),
522                              get_Block_cg_cfgpred_arr(post_block));
523     remove_Block_cg_cfgpred_arr(post_block);
524   }
525
526   /* Operationen verschieben */
527   move_phis(post_block, pre_block);
528   move_nodes(post_block, pre_block, call);
529   /* @@@ GL Wer setzt die Laenge des PostBlock cgfpred array auf 1?
530      GL: na, dieser Befehl... generiert neuen array. */
531   set_irn_in(post_block, 1, &jmp);
532
533   /* Wiederverwendete Daten initialisieren. */
534   for (i = 0; i < n_callees; ++i) {
535     callees[i] = get_Call_callee(call, i);
536     irgs[i] = callees[i] ? get_entity_irg(callees[i]) : NULL;
537     data[i] = get_entity_link(callees[i]);
538   }
539
540   /*
541    * Set flag to suppress verifying placement on proper irg:
542    * optimization can return block on other irg.
543    */
544   set_interprocedural_view(1);
545
546   /* Die interprozeduralen Steuerflussvorgänger des post_block
547    * bestimmen. */
548   for (i = 0; i < n_callees; ++i) {
549     if (data[i]) { /* explicit */
550       if (data[i]->reg) {
551         in[i] = new_r_Proj(irgs[i], get_nodes_Block(data[i]->reg),
552                            data[i]->reg, mode_X, data[i]->count);
553       } else {
554         in[i] = new_Bad();
555       }
556     } else { /* unknown */
557       in[i] = new_Unknown();
558     }
559   }
560   set_interprocedural_view(0);
561
562   set_Block_cg_cfgpred_arr(post_block, n_callees, in);
563
564   /* Die interprozeduralen Steuerflussvorgänger des except_block
565    * bestimmen. */
566   if ((proj = get_except(call)) != NULL) {
567     except_block = create_Block(1, &proj);
568     set_nodes_Block(proj, except_block);
569     exchange(proj, new_Break());
570     set_irg_current_block(current_ir_graph, pre_block);
571     set_irn_n(except_block, 0, new_Proj(call, mode_X, 1));
572     set_irg_current_block(current_ir_graph, post_block);
573
574     /*
575      * Set flag to suppress verifying placement on proper irg:
576      * optimization can return block on other irg.
577      */
578     set_interprocedural_view(1);
579
580     for (i = 0; i < n_callees; ++i) {
581       entity * callee = get_Call_callee(call, i);
582       if (data[i]) { /* explicit */
583         if (data[i]->except) {
584           in[i] = new_r_Proj(get_entity_irg(callee), get_nodes_Block(data[i]->except),
585                              data[i]->except, mode_X, data[i]->count);
586         } else {
587           in[i] = new_Bad();
588         }
589       } else { /* unknown */
590         in[i] = new_Unknown();
591       }
592     }
593     set_Block_cg_cfgpred_arr(except_block, n_callees, in);
594   }
595
596   set_interprocedural_view(0);
597
598   /* Diesen Vorgänger in den Start-Blöcken der aufgerufenen Methoden
599    * eintragen. */
600   set_irg_current_block(current_ir_graph, pre_block);
601   for (i = 0; i < n_callees; ++i) {
602     construct_start(caller, callees[i], call, new_Proj(call_begin, mode_X, i));
603   }
604
605   /* Proj-Operationen in Filter-Operationen umwandeln und
606    * interprozedurale Vorgänger einfügen. */
607   set_irg_current_block(current_ir_graph, post_block);
608   for (proj = get_irn_link(call); proj && get_irn_op(proj) == op_Proj; proj = get_irn_link(proj)) {
609     if (get_Proj_pred(proj) == call) {
610       if (get_Proj_proj(proj) == 0) { /* memory */
611         /* memory */
612         ir_node * filter = exchange_proj(proj);
613         /* filter in die Liste der Phis aufnehmen */
614         if (get_irn_link(filter) == NULL) { /* note CSE */
615           set_irn_link(filter, get_irn_link(post_block));
616           set_irn_link(post_block, filter);
617         }
618         fill_mem(n_callees, data, in);
619         set_Filter_cg_pred_arr(filter, n_callees, in);
620       } else if (get_Proj_proj(proj) == 1) { /* except */
621         /* nothing: siehe oben */
622       } else if (get_Proj_proj(proj) == 2) { /* results */
623         set_nodes_Block(proj, pre_block);
624       } else if (get_Proj_proj(proj) == 3) { /* except_mem */
625         /* except_mem */
626         ir_node * filter;
627         assert(except_block);
628         set_irg_current_block(current_ir_graph, except_block);
629         filter = exchange_proj(proj);
630         /* filter in die Liste der Phis aufnehmen */
631         if (get_irn_link(filter) == NULL) { /* note CSE */
632           set_irn_link(filter, get_irn_link(except_block));
633           set_irn_link(except_block, filter);
634         }
635         set_irg_current_block(current_ir_graph, post_block);
636         fill_except_mem(n_callees, data, in);
637         set_Filter_cg_pred_arr(filter, n_callees, in);
638       } else {
639         assert(0 && "not reached");
640       }
641     } else {
642       /* result */
643       ir_node * filter = exchange_proj(proj);
644       /* filter in die Liste der Phis aufnehmen */
645       if (get_irn_link(filter) == NULL) { /* note CSE */
646         set_irn_link(filter, get_irn_link(post_block));
647         set_irn_link(post_block, filter);
648       }
649       fill_result(get_Proj_proj(filter), n_callees, data, in);
650       set_Filter_cg_pred_arr(filter, n_callees, in);
651     }
652   }
653   DEL_ARR_F(in);
654   DEL_ARR_F(callees);
655   DEL_ARR_F(irgs);
656   DEL_ARR_F(data);
657 }
658
659
660 void cg_construct(int arr_len, entity ** free_methods_arr) {
661   int i;
662
663   collect_phicallproj();
664
665   /* count callers */
666   caller_init(arr_len, free_methods_arr);
667
668   /* prepare irgs */
669   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
670     ir_graph * irg = get_irp_irg(i);
671     entity * ent = get_irg_ent(irg);
672     irg_data_t * data = get_entity_link(ent);
673     if (data->count) {
674       prepare_irg(irg, data);
675     } else if (data->open) {
676       /* Die Methode wird nur von "der" unbekannten Aufrufstelle
677        * aufgerufen. Darstellung wird für diese Methode nicht
678        * geändert. */
679     } else {
680       /* Methode kann nicht aufgerufen werden. Die Darstellung wird
681        * für diese Methode nicht geändert. Das kann nicht vorkommen,
682        * wenn zuvor "gc_irgs()" aufgerufen wurde. */
683     }
684   }
685
686   /* construct calls */
687   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
688     ir_node * node;
689     current_ir_graph = get_irp_irg(i);
690     for (node = get_irn_link(get_irg_end(current_ir_graph)); node; node = get_irn_link(node)) {
691       if (get_irn_op(node) == op_Call) {
692         int n_callees = get_Call_n_callees(node);
693         if (n_callees > 1 || (n_callees == 1 && get_Call_callee(node, 0) != NULL)) {
694           construct_call(node);
695         }
696       }
697     }
698   }
699
700   /* cleanup irgs: Abschlussarbeiten: Die Vorgänger der Methoden noch
701    * explizit setzen und die zwischengespeicherten Daten wieder
702    * freigeben. */
703   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
704     cleanup_irg(get_irp_irg(i));
705   }
706 }
707
708
709
710 static void destruct_walker(ir_node * node, void * env) {
711   if (get_irn_op(node) == op_Block) {
712     remove_Block_cg_cfgpred_arr(node);
713   } else if (get_irn_op(node) == op_Filter) {
714     set_irg_current_block(current_ir_graph, get_nodes_Block(node));
715     exchange(node, new_Proj(get_Filter_pred(node), get_irn_mode(node), get_Filter_proj(node)));
716   } else if (get_irn_op(node) == op_Break) {
717     set_irg_current_block(current_ir_graph, get_nodes_Block(node));
718     exchange(node, new_Jmp());
719   } else if (get_irn_op(node) == op_Call) {
720     remove_Call_callee_arr(node);
721   }
722 }
723
724
725 void cg_destruct(void) {
726   int i;
727   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
728     ir_graph * irg = get_irp_irg(i);
729     irg_walk_graph(irg, destruct_walker, clear_link, NULL);
730     set_irg_frame(irg, skip_nop(get_irg_frame(irg)));
731     set_irg_globals(irg, skip_nop(get_irg_globals(irg)));
732   }
733 }