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