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