comments, removed unused fields
[libfirm] / ir / ana / cgana.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/ana/cgana.c
4  * Purpose:     Intraprozedural analyses to estimate the call graph.
5  * Author:      Hubert Schmid
6  * Modified by:
7  * Created:     09.06.2002
8  * CVS-ID:      $Id$
9  * Copyright:   (c) 1999-2003 Universität Karlsruhe
10  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
11  */
12
13 /**
14  * @file cgana.c
15  * Intraprozedurale Analyse zur Abschätzung der Aufrufrelation. Es
16  * wird eine Menge von freien Methoden und anschließend die an den
17  * Call-Operationen aufrufbaren Methoden bestimmt.
18  *
19  */
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include "cgana.h"
26 #include "rta.h"
27
28 #include "irnode_t.h"
29 #include "irmode_t.h"
30 #include "irprog_t.h"
31 #include "irgwalk.h"
32 #include "ircons.h"
33 #include "irgmod.h"
34
35 #include "irflag_t.h"
36 #include "dbginfo_t.h"
37 #include "iropt_dbg.h"
38
39 #include "eset.h"
40 #include "pmap.h"
41 #include "array.h"
42
43 #include "irdump.h"
44
45 #include "firmstat.h"
46
47 /* Eindeutige Adresse zur Markierung von besuchten Knoten und zur
48  * Darstellung der unbekannten Methode. */
49 static void * MARK = &MARK;
50
51
52
53 /* --- sel methods ---------------------------------------------------------- */
54
55
56 static eset * entities = NULL;
57
58
59 /** Bestimmt die eindeutige Methode, die die Methode für den
60  *  übergebenen (dynamischen) Typ überschreibt. */
61 static entity * get_implementation(type * class, entity * method) {
62   int i;
63   if (get_entity_peculiarity(method) != peculiarity_description &&
64       get_entity_owner(method) == class) {
65     return method;
66   }
67   for (i = get_entity_n_overwrittenby(method) - 1; i >= 0; --i) {
68     entity * e = get_entity_overwrittenby(method, i);
69     if (get_entity_peculiarity(e) != peculiarity_description && get_entity_owner(e) == class) {
70       return e;
71     }
72   }
73   for (i = get_class_n_supertypes(class) - 1; i >= 0; --i) {
74     entity * e = get_implementation(get_class_supertype(class, i), method);
75     if (e) {
76       return e;
77     }
78   }
79   assert(0 && "implementation not found");
80   return NULL;
81 }
82
83 /** Returns the entity that contains the implementation of the inherited
84     entity if available, else returns the entity passed. */
85 static entity *get_inherited_methods_implementation(entity *inh_meth) {
86   entity *impl_meth = NULL;
87   ir_node *addr = get_atomic_ent_value(inh_meth);
88
89   assert(addr && "constant entity without value");
90
91   if ((get_irn_op(addr) == op_SymConst) &&
92       (get_SymConst_kind(addr) == symconst_addr_ent)) {
93     impl_meth = get_SymConst_entity(addr);
94   } else {
95     assert(0 && "Complex constant values not supported -- address of method should be straight constant!");
96   }
97
98   if (impl_meth && (get_entity_peculiarity(impl_meth) != peculiarity_existent)) {
99     /*
100       printf("this_meth: "); DDMEO(inh_meth);
101       printf("impl meth: "); DDMEO(impl_meth);
102       assert(!impl_meth || get_entity_peculiarity(impl_meth) == peculiarity_existent);
103     */
104     impl_meth = NULL;
105   }
106   return impl_meth? impl_meth : inh_meth;
107 }
108
109
110 /** Collect the entity representing the implementation of this
111  *  entity (not the same if inherited) and all entities for overwriting
112  *  implementations in "set".
113  *  If the implementation of the method is not included in the
114  *  compilation unit "open" is set to true.
115  *  A recursive descend in the overwritten relation.
116  *  Cycle-free, therefore must terminate.
117  *
118  * @param method
119  * @param set      A set of entities.
120  * @param size     Number of entities in set.
121  * @param open
122  */
123 static void collect_impls(entity *method, eset *set, int *size, bool *open) {
124   int i;
125
126   if (get_entity_peculiarity(method) == peculiarity_existent) {
127     if ((get_entity_visibility(method) == visibility_external_allocated)
128         && (NULL == get_entity_irg(method))) {
129       *open = true;
130     } else {
131       assert(get_entity_irg(method) != NULL);
132       if (!eset_contains(set, method)) {
133         eset_insert(set, method);
134         ++(*size);
135       }
136     }
137   }
138
139   if (get_entity_peculiarity(method) == peculiarity_inherited) {
140     entity *impl_ent = get_inherited_methods_implementation(method);
141     assert(impl_ent && "no implementation for inherited entity");
142     if (get_entity_visibility(impl_ent) == visibility_external_allocated) {
143       assert(get_entity_irg(impl_ent) == NULL);
144       *open = true;
145     } else {
146       assert(get_entity_irg(impl_ent) != NULL);
147       if (!eset_contains(set, impl_ent)) {
148         eset_insert(set, impl_ent);
149         ++(*size);
150       }
151     }
152   }
153   /*- recursive descent -*/
154   for (i = get_entity_n_overwrittenby(method) - 1; i >= 0; --i)
155     collect_impls(get_entity_overwrittenby(method, i), set, size, open);
156 }
157
158
159 /** Alle Methoden bestimmen, die die übergebene Methode überschreiben
160  *  (und implementieren). In der zurückgegebenen Reihung kommt jede
161  *  Methode nur einmal vor. Der Wert 'NULL' steht für unbekannte
162  *  (externe) Methoden. Die zurückgegebene Reihung muß vom Aufrufer
163  *  wieder freigegeben werden (siehe "DEL_ARR_F"). Gibt es überhaupt
164  *  keine Methoden, die "method" überschreiben, so gibt die Methode
165  *  "NULL" zurück.
166  *
167  *  @param method
168  */
169 static entity ** get_impl_methods(entity * method) {
170   eset * set = eset_create();
171   int size = 0;
172   entity ** arr;
173   bool open = false;
174
175   /* Collect all method entities that can be called here */
176   collect_impls(method, set, &size, &open);
177
178   /* Vorgaenger einfuegen. */
179   if (size == 0 && !open) {
180     /* keine implementierte überschriebene Methode */
181     arr = NULL;
182   } else if (open) {
183     entity * ent;
184     arr = NEW_ARR_F(entity *, size + 1);
185     arr[0] = NULL;  /* Represents open method */
186     for (ent = eset_first(set); size > 0; ent = eset_next(set), --size)
187       arr[size] = ent;
188   } else {
189     entity * ent;
190     arr = NEW_ARR_F(entity *, size);
191     for (size -= 1, ent = eset_first(set); size >= 0; ent = eset_next(set), --size)
192       arr[size] = ent;
193   }
194   eset_destroy(set);
195   return arr;
196 }
197
198 /** Analyse address computations.
199  *
200  *  - If the node is a SymConst(name) replace it by SymConst(ent) if possible.
201  *  - If the node is a Sel:
202  *    * If the pointer to the Sel comes directly from an Alloc node
203  *      replace the Sel by a SymConst(ent).
204  *
205  *
206  *  @param node The node to analyze
207  *  @param ldname_map A map that mapps names of entities to the entities.
208  */
209 static void sel_methods_walker(ir_node * node, pmap * ldname_map) {
210
211   /* replace SymConst(name)-operations by SymConst(ent) */
212   if (get_irn_op(node) == op_SymConst) {
213     if (get_SymConst_kind(node) == symconst_addr_name) {
214       pmap_entry * entry = pmap_find(ldname_map, (void *) get_SymConst_name(node));
215       if (entry != NULL) { /* Method is declared in the compiled code */
216         entity * ent = entry->value;
217         if (get_opt_normalize() && (get_entity_visibility(ent) != visibility_external_allocated)) { /* Meth. is defined */
218           set_irg_current_block(current_ir_graph, get_nodes_block(node));
219           ir_node *new_node = copy_const_value(get_atomic_ent_value(ent));
220
221           DBG_OPT_CSTEVAL(node, new_node);
222
223           assert(get_entity_irg(ent));
224           DDMN(new_node);
225           exchange(node, new_node);
226         }
227       }
228     }
229   }
230
231   else if (get_irn_op(node) == op_Sel &&
232            is_method_type(get_entity_type(get_Sel_entity(node)))) {
233     entity * ent = get_Sel_entity(node);
234
235     /* Sel from Alloc: replace by constant */
236     if (get_opt_optimize() && get_opt_dyn_meth_dispatch() &&
237         (get_irn_op(skip_Proj(get_Sel_ptr(node))) == op_Alloc)) {
238       ir_node *new_node;
239       entity *called_ent;
240       /* We know which method will be called, no dispatch necessary. */
241       called_ent = resolve_ent_polymorphy(get_Alloc_type(skip_Proj(get_Sel_ptr(node))), ent);
242       set_irg_current_block(current_ir_graph, get_nodes_block(node));
243       /* called_ent may not be description: has no Address/Const to Call! */
244       assert(get_entity_peculiarity(called_ent) != peculiarity_description);
245       new_node = copy_const_value(get_atomic_ent_value(called_ent));
246
247       DBG_OPT_POLY_ALLOC(node, new_node);
248       exchange(node, new_node);
249     }
250
251     else {
252       assert(get_entity_peculiarity(ent) != peculiarity_inherited);
253       if (!eset_contains(entities, ent)) {
254         /* Entity noch nicht behandelt. Alle (intern oder extern)
255          * implementierten Methoden suchen, die diese Entity
256          * überschreiben. Die Menge an entity.link speichern. */
257         set_entity_link(ent, get_impl_methods(ent));
258         eset_insert(entities, ent);
259       }
260       if (get_entity_link(ent) == NULL) {
261         /* Die Sel-Operation kann nie einen Zeiger auf eine aufrufbare
262          * Methode zurückgeben. Damit ist sie insbesondere nicht
263          * ausführbar und nicht erreichbar. */
264         /* Gib eine Warnung aus wenn die Entitaet eine Beschreibung ist
265            fuer die es keine Implementierung gibt. */
266         if (get_entity_peculiarity(ent) == peculiarity_description) {
267           /* This is possible:  We call a method in a dead part of the program. */
268         } else {
269           DDMN(node);
270           assert(0);  /* Why should this happen ??? */
271           //exchange(node, new_Bad());
272         }
273       } else {
274         entity ** arr = get_entity_link(ent);
275
276 #if 0
277         int i;
278         printf("\nCall site "); DDMN(node);
279         printf("  in "); DDME(get_irg_entity(current_ir_graph));
280         printf("  can call:\n");
281         for (i = 0; i < ARR_LEN(arr); i++) {
282           printf("   - "); DDME(arr[i]);
283           printf("     with owner "); DDMT(get_entity_owner(arr[i]));
284         }
285         printf("\n");
286 #endif
287
288         if (get_opt_optimize() && get_opt_dyn_meth_dispatch() &&
289             (ARR_LEN(arr) == 1 && arr[0] != NULL)) {
290           ir_node *new_node;
291           /* Die Sel-Operation kann immer nur _einen_ Wert auf eine
292            * interne Methode zurückgeben. Wir können daher die
293            * Sel-Operation durch eine Const- bzw. SymConst-Operation
294            * ersetzen. */
295           set_irg_current_block(current_ir_graph, get_nodes_block(node));
296           assert(get_entity_peculiarity(get_SymConst_entity(get_atomic_ent_value(arr[0]))) ==
297                  peculiarity_existent);
298           new_node = copy_const_value(get_atomic_ent_value(arr[0]));
299           DBG_OPT_POLY(node, new_node);
300           exchange (node, new_node);
301         }
302       }
303     }
304   }
305 }
306
307
308 /** Datenstruktur initialisieren. Zusätzlich werden alle
309  *  SymConst(name)-Operationen, die auf interne Methoden verweisen, durch
310  *  SymConst(entity)-Operationen ersetzt. */
311 static void sel_methods_init(void) {
312   int i;
313   pmap * ldname_map = pmap_create();   /* Map entitiy names to entities: to replace SymConst(name) by SymConst(ent). */
314
315   assert(entities == NULL);
316   entities = eset_create();
317   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
318     entity * ent = get_irg_entity(get_irp_irg(i));
319     /* Nur extern sichtbare Methode können überhaupt mit SymConst
320      * aufgerufen werden. */
321     if (get_entity_visibility(ent) != visibility_local) {
322       pmap_insert(ldname_map, (void *) get_entity_ld_ident(ent), ent);
323     }
324   }
325   all_irg_walk((irg_walk_func *) sel_methods_walker, NULL, ldname_map);
326   pmap_destroy(ldname_map);
327 }
328
329 /*****************************************************************************/
330
331 /* Datenstruktur freigeben. */
332 static void sel_methods_dispose(void) {
333   entity * ent;
334   assert(entities);
335   for (ent = eset_first(entities); ent; ent = eset_next(entities)) {
336     entity ** arr = get_entity_link(ent);
337     if (arr) {
338       DEL_ARR_F(arr);
339     }
340     set_entity_link(ent, NULL);
341   }
342   eset_destroy(entities);
343   entities = NULL;
344 }
345
346
347 /* Gibt die Menge aller Methoden zurück, die an diesem Sel-Knoten
348  * zurückgegeben werden können. Die Liste enthält keine doppelten
349  * Einträge. */
350 static entity ** get_Sel_arr(ir_node * sel) {
351   static entity ** NULL_ARRAY = NULL;
352   entity * ent;
353   entity ** arr;
354   assert(sel && get_irn_op(sel) == op_Sel);
355   ent = get_Sel_entity(sel);
356   assert(is_method_type(get_entity_type(ent))); /* what else? */
357   arr = get_entity_link(ent);
358   if (arr) {
359     return arr;
360   } else {
361     /* "NULL" zeigt an, dass keine Implementierung existiert. Dies
362      * kann für polymorphe (abstrakte) Methoden passieren. */
363     if (!NULL_ARRAY) {
364       NULL_ARRAY = NEW_ARR_F(entity *, 0);
365     }
366     return NULL_ARRAY;
367   }
368 }
369
370
371 static int get_Sel_n_methods(ir_node * sel) {
372   return ARR_LEN(get_Sel_arr(sel));
373 }
374
375
376 static entity * get_Sel_method(ir_node * sel, int pos) {
377   entity ** arr = get_Sel_arr(sel);
378   assert(pos >= 0 && pos < ARR_LEN(arr));
379   return arr[pos];
380 }
381
382
383
384 /* --- callee analysis ------------------------------------------------------ */
385
386
387 static void callee_ana_node(ir_node * node, eset * methods);
388
389
390 static void callee_ana_proj(ir_node * node, long n, eset * methods) {
391   assert(get_irn_mode(node) == mode_T);
392   if (get_irn_link(node) == MARK) {
393     /* already visited */
394     return;
395   }
396   set_irn_link(node, MARK);
397
398   switch (get_irn_opcode(node)) {
399   case iro_Proj: {
400     /* proj_proj: in einem "sinnvollen" Graphen kommt jetzt ein
401      * op_Tuple oder ein Knoten, der eine "freie Methode"
402      * zurückgibt. */
403     ir_node * pred = get_Proj_pred(node);
404     if (get_irn_link(pred) != MARK) {
405       if (get_irn_op(pred) == op_Tuple) {
406     callee_ana_proj(get_Tuple_pred(pred, get_Proj_proj(node)), n, methods);
407       } else {
408     eset_insert(methods, MARK); /* free method -> unknown */
409       }
410     }
411     break;
412   }
413
414   case iro_Tuple:
415     callee_ana_node(get_Tuple_pred(node, n), methods);
416     break;
417
418   case iro_Id:
419     callee_ana_proj(get_Id_pred(node), n, methods);
420     break;
421
422   default:
423     eset_insert(methods, MARK); /* free method -> unknown */
424     break;
425   }
426
427   set_irn_link(node, NULL);
428 }
429
430
431 static void callee_ana_node(ir_node * node, eset * methods) {
432   int i;
433
434   assert(mode_is_reference(get_irn_mode(node)) || is_Bad(node));
435   /* rekursion verhindern */
436   if (get_irn_link(node) == MARK) {
437     /* already visited */
438     return;
439   }
440   set_irn_link(node, MARK);
441
442   switch (get_irn_opcode(node)) {
443   case iro_SymConst:
444     if (get_SymConst_kind(node) == symconst_addr_ent) {
445       entity * ent = get_SymConst_entity(node);
446       assert(ent && is_method_type(get_entity_type(ent)));
447       if (get_entity_visibility(ent) != visibility_external_allocated) {
448         assert(get_entity_irg(ent));
449         eset_insert(methods, ent);
450       } else {
451         eset_insert(methods, MARK); /* free method -> unknown */
452       }
453     } else {
454       assert(get_SymConst_kind(node) == symconst_addr_name);
455       /* externe Methode (wegen fix_symconst!) */
456       eset_insert(methods, MARK); /* free method -> unknown */
457     }
458     break;
459   case iro_Sel:
460     /* polymorphe Methode */
461     for (i = get_Sel_n_methods(node) - 1; i >= 0; --i) {
462       entity * ent = get_Sel_method(node, i);
463       if (ent) {
464         eset_insert(methods, ent);
465       } else {
466         eset_insert(methods, MARK);
467       }
468     }
469     break;
470
471   case iro_Bad:
472     /* nothing */
473     break;
474
475   case iro_Phi: /* Vereinigung */
476     for (i = get_Phi_n_preds(node) - 1; i >= 0; --i) {
477       callee_ana_node(get_Phi_pred(node, i), methods);
478     }
479     break;
480
481   case iro_Id:
482     callee_ana_node(get_Id_pred(node), methods);
483     break;
484
485   case iro_Proj:
486     callee_ana_proj(get_Proj_pred(node), get_Proj_proj(node), methods);
487     break;
488
489   case iro_Add:
490   case iro_Sub:
491   case iro_Conv:
492     /* extern */
493     eset_insert(methods, MARK); /* free method -> unknown */
494     break;
495
496   default:
497     assert(0 && "invalid opcode or opcode not implemented");
498     break;
499   }
500
501   set_irn_link(node, NULL);
502 }
503
504
505 static void callee_walker(ir_node * call, void * env) {
506   if (get_irn_op(call) == op_Call) {
507     eset * methods = eset_create();
508     entity * ent;
509     entity ** arr = NEW_ARR_F(entity *, 0);
510     callee_ana_node(skip_Id(get_Call_ptr(call)), methods);
511     if (eset_contains(methods, MARK)) { /* unknown method */
512       ARR_APP1(entity *, arr, NULL);
513     }
514     for (ent = eset_first(methods); ent; ent = eset_next(methods)) {
515       if (ent != MARK) {
516         ARR_APP1(entity *, arr, ent);
517       }
518     }
519 #if 0  /* This generates Bad nodes when we don't want it.
520           Call it with a check for valid cgana information in local_optimize. */
521     if (ARR_LEN(arr) == 0 && get_opt_optimize() && get_opt_dyn_meth_dispatch()) {
522       /* Kann vorkommen, wenn der Vorgänger beispielsweise eine
523        * Sel-Operation war, die keine Methoden zurückgeben
524        * konnte. Wir ersetzen die Call-Operation ebenfalls durch
525        * eine Bad-Operation. Die Verlinkung muss wiederhergestellt
526        * werden! */
527       ir_node *mem = get_Call_mem(call);
528       turn_into_tuple (call, 5 /* pn_Call_max */);
529       set_Tuple_pred(call, pn_Call_M_regular       , mem);
530       set_Tuple_pred(call, pn_Call_T_result        , new_Bad());
531       set_Tuple_pred(call, pn_Call_P_value_res_base, new_Bad());
532       set_Tuple_pred(call, pn_Call_X_except        , new_Bad());  /* new_Jmp() ?? new_Raise() ?? */
533       set_Tuple_pred(call, pn_Call_M_except        , new_Bad());
534
535     } else
536 #endif
537     {
538       set_Call_callee_arr(call, ARR_LEN(arr), arr);
539     }
540     DEL_ARR_F(arr);
541     eset_destroy(methods);
542   }
543 }
544
545
546 static void remove_Tuples(ir_node * proj, void * env) {
547   ir_node *new;
548   if (get_irn_opcode(proj) != iro_Proj) return;
549
550   new = skip_Tuple(proj);
551   if (new != proj) exchange(proj, new);
552 }
553
554
555 /* Bestimmt für jede Call-Operation die Menge der aufrufbaren Methode
556  * und speichert das Ergebnis in der Call-Operation. (siehe
557  * "set_Call_callee"). "sel_methods" wird für den Aufbau benötigt und
558  * muss bereits aufgebaut sein. */
559 static void callee_ana(void) {
560   int i;
561   /* Alle Graphen analysieren. */
562   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
563     irg_walk_graph(get_irp_irg(i), callee_walker, remove_Tuples, NULL);
564     set_irg_callee_info_state(get_irp_irg(i), irg_callee_info_consistent);
565   }
566   set_irp_callee_info_state(irg_callee_info_consistent);
567 }
568
569
570
571 /* --- free method analysis ------------------------------------------------- */
572
573
574 static void free_mark(ir_node * node, eset * set);
575
576 static void free_mark_proj(ir_node * node, long n, eset * set) {
577   assert(get_irn_mode(node) == mode_T);
578   if (get_irn_link(node) == MARK) {
579     /* already visited */
580     return;
581   }
582   set_irn_link(node, MARK);
583   switch (get_irn_opcode(node)) {
584   case iro_Proj: {
585     /* proj_proj: in einem "sinnvollen" Graphen kommt jetzt ein
586      * op_Tuple oder ein Knoten, der in "free_ana_walker" behandelt
587      * wird. */
588     ir_node * pred = get_Proj_pred(node);
589     if (get_irn_link(pred) != MARK && get_irn_op(pred) == op_Tuple) {
590       free_mark_proj(get_Tuple_pred(pred, get_Proj_proj(node)), n, set);
591     } else {
592       /* nothing: da in "free_ana_walker" behandelt. */
593     }
594     break;
595   }
596
597   case iro_Tuple:
598     free_mark(get_Tuple_pred(node, n), set);
599     break;
600
601   case iro_Id:
602     free_mark_proj(get_Id_pred(node), n, set);
603     break;
604
605   case iro_Start:
606   case iro_Alloc:
607   case iro_Load:
608     /* nothing: Die Operationen werden in "free_ana_walker" selbst
609      * behandelt. */
610     break;
611
612   default:
613     assert(0 && "unexpected opcode or opcode not implemented");
614     break;
615   }
616   set_irn_link(node, NULL);
617 }
618
619
620 static void free_mark(ir_node * node, eset * set) {
621   int i;
622 //  assert(mode_is_reference(get_irn_mode(node)));
623   if (get_irn_link(node) == MARK) {
624     return; /* already visited */
625   }
626   set_irn_link(node, MARK);
627   switch (get_irn_opcode(node)) {
628   case iro_Sel: {
629     entity * ent = get_Sel_entity(node);
630     if (is_method_type(get_entity_type(ent))) {
631       for (i = get_Sel_n_methods(node) - 1; i >= 0; --i) {
632     eset_insert(set, get_Sel_method(node, i));
633       }
634     }
635     break;
636   }
637   case iro_SymConst:
638     if (get_SymConst_kind(node) == symconst_addr_ent) {
639       entity * ent = get_SymConst_entity(node);
640       if (is_method_type(get_entity_type(ent))) {
641         eset_insert(set, ent);
642       }
643     } else {
644       assert(get_SymConst_kind(node) == symconst_addr_name);
645       /* nothing: SymConst points to extern method */
646     }
647     break;
648
649   case iro_Phi:
650     for (i = get_Phi_n_preds(node) - 1; i >= 0; --i) {
651       free_mark(get_Phi_pred(node, i), set);
652     }
653     break;
654   case iro_Id:
655     free_mark(get_Id_pred(node), set);
656     break;
657   case iro_Proj:
658     free_mark_proj(get_Proj_pred(node), get_Proj_proj(node), set);
659     break;
660   default:
661     /* nothing: Wird unten behandelt! */
662     break;
663   }
664   set_irn_link(node, NULL);
665 }
666
667
668 static void free_ana_walker(ir_node * node, eset * set) {
669   int i;
670   if (get_irn_link(node) == MARK) {
671     /* bereits in einem Zyklus besucht. */
672     return;
673   }
674   switch (get_irn_opcode(node)) {
675   /* special nodes */
676   case iro_Sel:
677   case iro_SymConst:
678   case iro_Const:
679   case iro_Phi:
680   case iro_Id:
681   case iro_Proj:
682   case iro_Tuple:
683     /* nothing */
684     break;
685   /* Sonderbehandlung, da der Funktionszeigereingang natürlich kein
686    * Verräter ist. */
687   case iro_Call:
688     set_irn_link(node, MARK);
689     for (i = get_Call_arity(node) - 1; i >= 0; --i) {
690       ir_node * pred = get_Call_param(node, i);
691       if (mode_is_reference(get_irn_mode(pred))) {
692         free_mark(pred, set);
693       }
694     }
695     break;
696   /* other nodes: Alle anderen Knoten nehmen wir als Verräter an, bis
697    * jemand das Gegenteil implementiert. */
698   default:
699     set_irn_link(node, MARK);
700     for (i = get_irn_arity(node) - 1; i >= 0; --i) {
701       ir_node * pred = get_irn_n(node, i);
702       if (mode_is_reference(get_irn_mode(pred))) {
703         free_mark(pred, set);
704       }
705     }
706     break;
707   }
708   set_irn_link(node, NULL);
709 }
710
711
712 /* Die Datenstrukturen für sel-Methoden (sel_methods) muß vor dem
713  * Aufruf von "get_free_methods" aufgebaut sein. Die (internen)
714  * SymConst-Operationen müssen in passende Const-Operationen
715  * umgewandelt worden sein, d.h. SymConst-Operationen verweisen immer
716  * auf eine echt externe Methode.  */
717 static entity ** get_free_methods(void)
718 {
719   eset * set = eset_create();
720   int i;
721   entity ** arr = NEW_ARR_F(entity *, 0);
722   entity * ent;
723
724   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
725     ir_graph * irg = get_irp_irg(i);
726     entity * ent = get_irg_entity(irg);
727     /* insert "external visible" methods. */
728     if (get_entity_visibility(ent) != visibility_local) {
729       eset_insert(set, ent);
730     }
731     /* Finde alle Methoden die in dieser Methode extern sichtbar werden,
732        z.B. da die Adresse einer Methode abgespeichert wird. */
733     irg_walk_graph(irg, NULL, (irg_walk_func *) free_ana_walker, set);
734   }
735
736   /* insert sticky methods, too */
737   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
738     ir_graph * irg = get_irp_irg(i);
739     entity * ent = get_irg_entity(irg);
740     /* insert "external visible" methods. */
741     if (get_entity_stickyness (ent) == stickyness_sticky) {
742       eset_insert(set, ent);
743     }
744   }
745
746   /* Hauptprogramm ist auch dann frei, wenn es nicht "external
747    * visible" ist. */
748   if (get_irp_main_irg()) {
749     eset_insert(set, get_irg_entity(get_irp_main_irg()));
750   }
751   /* Wandle Menge in Feld um.  Effizienter. */
752   for (ent = eset_first(set); ent; ent = eset_next(set)) {
753     ARR_APP1(entity *, arr, ent);
754   }
755   eset_destroy(set);
756
757   return arr;
758 }
759
760 void cgana(int *length, entity ***free_methods) {
761   entity ** free_meths, **p;
762
763   sel_methods_init();
764   free_meths = get_free_methods();
765   callee_ana();
766   sel_methods_dispose();
767
768   /* Convert the flexible array to an array that can be handled
769      by standard C. */
770   p = (entity **)malloc(sizeof(*p) * ARR_LEN(free_meths));
771   memcpy(p, free_meths, ARR_LEN(free_meths) * sizeof(*p));
772
773   *length       = ARR_LEN(free_meths);
774   *free_methods = p;
775
776   DEL_ARR_F(free_meths);
777 }
778
779
780
781 static void destruct_walker(ir_node * node, void * env) {
782   if (get_irn_op(node) == op_Call) {
783     remove_Call_callee_arr(node);
784   }
785 }
786
787 void free_callee_info(ir_graph *irg) {
788   irg_walk_graph(irg, destruct_walker, NULL, NULL);
789   set_irg_callee_info_state(irg, irg_callee_info_none);
790 }
791
792
793 /* Optimize the address expressions passed to call nodes.
794  *
795  * This optimization performs the following transformations for
796  * all ir graphs:
797  * - All SymConst operations that refer to intern methods are replaced
798  *   by Const operations refering to the corresponding entity.
799  * - Sel nodes, that select entities that are not overwritten are
800  *   replaced by Const nodes refering to the selected entity.
801  * - Sel nodes, for witch no method exists at all are replaced by Bad
802  *   nodes.
803  * - Sel nodes with a pointer input that is an Alloc node are replaced
804  *   by Const nodes refering to the entity that implements the method in
805  *   the type given by the Alloc node.
806  */
807 void opt_call_addrs(void) {
808   sel_methods_init();
809   sel_methods_dispose();
810 #if 0
811   int i;
812   pmap * ldname_map = pmap_create();
813   assert(entities == NULL);
814   entities = eset_create();
815   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
816     entity * ent = get_irg_entity(get_irp_irg(i));
817     /* Nur extern sichtbare Methoden können überhaupt mit SymConst
818      * aufgerufen werden. */
819     if (get_entity_visibility(ent) != local) {
820       pmap_insert(ldname_map, (void *) get_entity_ld_ident(ent), ent);
821     }
822   }
823   all_irg_walk((irg_walk_func *) sel_methods_walker, NULL, ldname_map);
824   pmap_destroy(ldname_map);
825 #endif
826 }