3 * File name: ir/ana/cgana.c
4 * Purpose: Intraprozedural analyses to estimate the call graph.
5 * Author: Hubert Schmid
9 * Copyright: (c) 1999-2003 Universität Karlsruhe
10 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
14 * Intraprozedurale Analyse zur Abschätzung der Aufrulrelation. Es
15 * wird eine Menge von freien Methoden und anschließend die an den
16 * Call-Operationen aufrufbaren Methoden bestimmt.
34 #include "dbginfo_t.h"
36 /* Eindeutige Adresse zur Markierung von besuchten Knoten und zur
37 * Darstellung der unbekannten Methode. */
38 static void * MARK = &MARK;
42 /* --- sel methods ---------------------------------------------------------- */
45 static eset * entities = NULL;
48 /* Bestimmt die eindeutige Methode, die die Methode für den
49 * übergebenene (dynamischen) Typ überschreibt. */
50 static entity * get_implementation(type * class, entity * method) {
52 if (get_entity_peculiarity(method) != peculiarity_description &&
53 get_entity_owner(method) == class) {
56 for (i = get_entity_n_overwrittenby(method) - 1; i >= 0; --i) {
57 entity * e = get_entity_overwrittenby(method, i);
58 if (get_entity_peculiarity(e) != peculiarity_description && get_entity_owner(e) == class) {
62 for (i = get_class_n_supertypes(class) - 1; i >= 0; --i) {
63 entity * e = get_implementation(get_class_supertype(class, i), method);
68 assert(0 && "implemenation not found");
72 /* Returns the entity that contains the implementation of the inherited
73 entity if available, else returns the entity passed. */
74 entity *get_inherited_methods_implementation(entity *inh_meth) {
75 entity *impl_meth = NULL;
76 ir_node *addr = get_atomic_ent_value(inh_meth);
77 assert(addr && "constant entity without value");
79 if (get_irn_op(addr) == op_Const) {
80 impl_meth = tarval_to_entity(get_Const_tarval(addr));
82 assert(0 && "Complex constant values not supported -- adress of method should be straight constant!");
84 if (impl_meth && (get_entity_peculiarity(impl_meth) != peculiarity_existent)) {
85 printf("this_meth: "); DDMEO(inh_meth);
86 printf("impl meth: "); DDMEO(impl_meth);
87 assert(!impl_meth || get_entity_peculiarity(impl_meth) == peculiarity_existent);
89 return impl_meth? impl_meth : inh_meth;
93 /* Collect the entity representing the implementation of this
94 entity (not the same if inherited) and all entities for overwriting
95 implementations in "set".
96 If the implementation of the method is not included in the
97 compilation unit "open" is set to true.
98 A recursive descend in the overwritten relation.
99 Cycle-free, therefore must terminate. */
100 void collect_impls(entity *method, eset *set, int *size, bool *open) {
102 if (get_entity_peculiarity(method) == peculiarity_existent) {
103 if (get_entity_visibility(method) == visibility_external_allocated) {
104 assert(get_entity_irg(method) == NULL);
107 assert(get_entity_irg(method) != NULL);
108 if (!eset_contains(set, method)) {
109 eset_insert(set, method);
114 if (get_entity_peculiarity(method) == peculiarity_inherited) {
115 entity *impl_ent = get_inherited_methods_implementation(method);
116 assert(impl_ent && "no implementation for inherited entity");
117 if (get_entity_visibility(impl_ent) == visibility_external_allocated) {
118 assert(get_entity_irg(impl_ent) == NULL);
121 assert(get_entity_irg(impl_ent) != NULL);
122 if (!eset_contains(set, impl_ent)) {
123 eset_insert(set, impl_ent);
128 /** recursive descend **/
129 for (i = get_entity_n_overwrittenby(method) - 1; i >= 0; --i)
130 collect_impls(get_entity_overwrittenby(method, i), set, size, open);
134 /* Alle Methoden bestimmen, die die übergebene Methode überschreiben
135 * (und implementieren). In der zurückgegebenen Reihung kommt jede
136 * Methode nur einmal vor. Der Wert 'NULL' steht für unbekannte
137 * (externe) Methoden. Die zurückgegebene Reihung muß vom Aufrufer
138 * wieder freigegeben werden (siehe "DEL_ARR_F"). Gibt es überhaupt
139 * keine Methoden, die die "method" überschreiben, so gibt die Methode
141 static entity ** get_impl_methods(entity * method) {
142 eset * set = eset_create();
147 /** Collect all method entities that can be called here **/
148 collect_impls(method, set, &size, &open);
151 Vorgaenger einfuegen. **/
152 if (size == 0 && !open) {
153 /* keine implementierte überschriebene Methode */
157 arr = NEW_ARR_F(entity *, size + 1);
158 arr[0] = NULL; /* Represents open method */
159 for (ent = eset_first(set); size > 0; ent = eset_next(set), --size)
163 arr = NEW_ARR_F(entity *, size);
164 for (size -= 1, ent = eset_first(set); size >= 0; ent = eset_next(set), --size)
172 /* debug makros used in sel_methods_walker */
173 #define SIZ(x) sizeof(x)/sizeof((x)[0])
175 #define DBG_OPT_NORMALIZE \
176 __dbg_info_merge_pair(new_node, node, dbg_const_eval)
177 #define DBG_OPT_POLY_ALLOC \
181 ons[1] = skip_Proj(get_Sel_ptr(node)); \
182 __dbg_info_merge_sets(&new_node, 1, ons, SIZ(ons), dbg_rem_poly_call); \
184 #define DBG_OPT_POLY \
185 __dbg_info_merge_pair(new_node, node, dbg_rem_poly_call)
188 static void sel_methods_walker(ir_node * node, pmap * ldname_map) {
189 if (get_irn_op(node) == op_SymConst) {
190 /* Wenn möglich SymConst-Operation durch Const-Operation
192 if (get_SymConst_kind(node) == linkage_ptr_info) {
193 pmap_entry * entry = pmap_find(ldname_map, (void *) get_SymConst_ptrinfo(node));
194 if (entry != NULL) { /* Method is declared in the compiled code */
195 entity * ent = entry->value;
196 if (get_opt_normalize() && (get_entity_visibility(ent) != visibility_external_allocated)) { /* Meth. is defined */
198 assert(get_entity_irg(ent));
199 set_irg_current_block(current_ir_graph, get_nodes_Block(node));
200 new_node = new_d_Const(get_irn_dbg_info(node),
201 mode_P_mach, new_tarval_from_entity(ent, mode_P_mach)); DBG_OPT_NORMALIZE;
202 exchange(node, new_node);
206 } else if (get_irn_op(node) == op_Sel &&
207 is_method_type(get_entity_type(get_Sel_entity(node)))) {
208 entity * ent = get_Sel_entity(node);
209 if (get_optimize() && get_opt_dyn_meth_dispatch() &&
210 (get_irn_op(skip_Proj(get_Sel_ptr(node))) == op_Alloc)) {
213 /* We know which method will be called, no dispatch necessary. */
215 assert(get_entity_peculiarity(ent) != peculiarity_description);
216 set_irg_current_block(current_ir_graph, get_nodes_Block(node));
217 /* @@@ Is this correct?? Alloc could reference a subtype of the owner
218 of Sel that overwrites the method referenced in Sel. */
219 /* @@@ Yes, this is wrong. GL, 10.3.04 */
220 new_node = copy_const_value(get_atomic_ent_value(ent)); DBG_OPT_POLY_ALLOC;
222 called_ent = resolve_ent_polymorphy(get_Alloc_type(skip_Proj(get_Sel_ptr(node))), ent);
223 set_irg_current_block(current_ir_graph, get_nodes_Block(node));
224 /* called_ent may not be description: has no Address/Const to Call! */
225 assert(get_entity_peculiarity(called_ent) != peculiarity_description);
226 new_node = copy_const_value(get_atomic_ent_value(called_ent)); DBG_OPT_POLY_ALLOC;
228 exchange (node, new_node);
230 assert(get_entity_peculiarity(ent) != peculiarity_inherited);
231 if (!eset_contains(entities, ent)) {
232 /* Entity noch nicht behandelt. Alle (intern oder extern)
233 * implementierten Methoden suchen, die diese Entity
234 * überschreiben. Die Menge an entity.link speichern. */
235 set_entity_link(ent, get_impl_methods(ent));
236 eset_insert(entities, ent);
238 if (get_entity_link(ent) == NULL) {
239 /* Die Sel-Operation kann nie einen Zeiger auf eine aufrufbare
240 * Methode zurückgeben. Damit ist sie insbesondere nicht
241 * ausführbar und nicht erreichbar. */
242 /* Gib eine Warnung aus wenn die Entitaet eine Beschreibung ist
243 fuer die es keine Implementierung gibt. */
244 if (get_entity_peculiarity(ent) == peculiarity_description) {
245 /* @@@ GL Methode um Fehler anzuzeigen aufrufen! */
246 printf("WARNING: Calling method description %s in method %s which has "
247 "no implementation!\n", get_entity_name(ent),
248 get_entity_name(get_irg_ent(current_ir_graph)));
250 exchange(node, new_Bad());
253 entity ** arr = get_entity_link(ent);
257 printf("\nCall site "); DDMN(node);
258 printf(" in "); DDME(get_irg_ent(current_ir_graph));
259 printf(" can call:\n");
260 for (i = 0; i < ARR_LEN(arr); i++) {
261 printf(" - "); DDME(arr[i]);
262 printf(" with owner "); DDMT(get_entity_owner(arr[i]));
267 if (get_optimize() && get_opt_dyn_meth_dispatch() &&
268 (ARR_LEN(arr) == 1 && arr[0] != NULL)) {
270 /* Die Sel-Operation kann immer nur einen Wert auf eine
271 * interne Methode zurückgeben. Wir können daher die
272 * Sel-Operation durch eine Const- bzw. SymConst-Operation
274 set_irg_current_block(current_ir_graph, get_nodes_Block(node));
275 new_node = copy_const_value(get_atomic_ent_value(arr[0])); DBG_OPT_POLY;
276 exchange (node, new_node);
284 /* Datenstruktur initialisieren. Zusätzlich werden alle
285 * SymConst-Operationen, die auf interne Methoden verweisen, durch
286 * Const-Operationen ersetzt. */
287 static void sel_methods_init(void) {
289 pmap * ldname_map = pmap_create();
290 assert(entities == NULL);
291 entities = eset_create();
292 for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
293 entity * ent = get_irg_ent(get_irp_irg(i));
294 /* Nur extern sichtbare Methode können überhaupt mit SymConst
295 * aufgerufen werden. */
296 if (get_entity_visibility(ent) != visibility_local) {
297 pmap_insert(ldname_map, (void *) get_entity_ld_ident(ent), ent);
300 all_irg_walk((irg_walk_func *) sel_methods_walker, NULL, ldname_map);
301 pmap_destroy(ldname_map);
304 /*****************************************************************************/
306 /* Datenstruktur freigeben. */
307 static void sel_methods_dispose(void) {
310 for (ent = eset_first(entities); ent; ent = eset_next(entities)) {
311 entity ** arr = get_entity_link(ent);
315 set_entity_link(ent, NULL);
317 eset_destroy(entities);
322 /* Gibt die Menge aller Methoden zurück, die an diesem Sel-Knoten
323 * zurückgegeben werden können. Die Liste enthält keine doppelten
325 static entity ** get_Sel_arr(ir_node * sel) {
326 static entity ** NULL_ARRAY = NULL;
329 assert(sel && get_irn_op(sel) == op_Sel);
330 ent = get_Sel_entity(sel);
331 assert(is_method_type(get_entity_type(ent))); /* what else? */
332 arr = get_entity_link(ent);
336 /* "NULL" zeigt an, dass keine Implementierung existiert. Dies
337 * kann für polymorphe (abstrakte) Methoden passieren. */
339 NULL_ARRAY = NEW_ARR_F(entity *, 0);
346 static int get_Sel_n_methods(ir_node * sel) {
347 return ARR_LEN(get_Sel_arr(sel));
351 static entity * get_Sel_method(ir_node * sel, int pos) {
352 entity ** arr = get_Sel_arr(sel);
353 assert(pos >= 0 && pos < ARR_LEN(arr));
359 /* --- callee analysis ------------------------------------------------------ */
362 static void callee_ana_node(ir_node * node, eset * methods);
365 static void callee_ana_proj(ir_node * node, long n, eset * methods) {
366 assert(get_irn_mode(node) == mode_T);
367 if (get_irn_link(node) == MARK) {
368 /* already visited */
371 set_irn_link(node, MARK);
373 switch (get_irn_opcode(node)) {
375 /* proj_proj: in einem "sinnvollen" Graphen kommt jetzt ein
376 * op_Tuple oder ein Knoten, der eine "freie Methode"
378 ir_node * pred = get_Proj_pred(node);
379 if (get_irn_link(pred) != MARK) {
380 if (get_irn_op(pred) == op_Tuple) {
381 callee_ana_proj(get_Tuple_pred(pred, get_Proj_proj(node)), n, methods);
383 eset_insert(methods, MARK); /* free method -> unknown */
390 callee_ana_node(get_Tuple_pred(node, n), methods);
394 callee_ana_proj(get_Id_pred(node), n, methods);
398 eset_insert(methods, MARK); /* free method -> unknown */
402 set_irn_link(node, NULL);
406 static void callee_ana_node(ir_node * node, eset * methods) {
409 assert(mode_is_reference(get_irn_mode(node)) || is_Bad(node));
410 /* rekursion verhindern */
411 if (get_irn_link(node) == MARK) {
412 /* already visited */
415 set_irn_link(node, MARK);
417 switch (get_irn_opcode(node)) {
419 /* externe Methode (wegen fix_symconst!) */
420 eset_insert(methods, MARK); /* free method -> unknown */
424 /* interne Methode */
425 entity * ent = tarval_to_entity(get_Const_tarval(node));
426 assert(ent && is_method_type(get_entity_type(ent)));
427 if (get_entity_visibility(ent) != visibility_external_allocated) {
428 assert(get_entity_irg(ent));
429 eset_insert(methods, ent);
431 eset_insert(methods, MARK); /* free method -> unknown */
437 /* polymorphe Methode */
438 for (i = get_Sel_n_methods(node) - 1; i >= 0; --i) {
439 entity * ent = get_Sel_method(node, i);
441 eset_insert(methods, ent);
443 eset_insert(methods, MARK);
452 case iro_Phi: /* Vereinigung */
453 for (i = get_Phi_n_preds(node) - 1; i >= 0; --i) {
454 callee_ana_node(get_Phi_pred(node, i), methods);
459 callee_ana_node(get_Id_pred(node), methods);
463 callee_ana_proj(get_Proj_pred(node), get_Proj_proj(node), methods);
470 eset_insert(methods, MARK); /* free method -> unknown */
474 assert(0 && "invalid opcode or opcode not implemented");
478 set_irn_link(node, NULL);
482 static void callee_walker(ir_node * call, void * env) {
483 if (get_irn_op(call) == op_Call) {
484 eset * methods = eset_create();
486 entity ** arr = NEW_ARR_F(entity *, 0);
487 callee_ana_node(skip_nop(get_Call_ptr(call)), methods);
488 if (eset_contains(methods, MARK)) { /* unknown method */
489 ARR_APP1(entity *, arr, NULL);
491 for (ent = eset_first(methods); ent; ent = eset_next(methods)) {
493 ARR_APP1(entity *, arr, ent);
496 if (ARR_LEN(arr) == 0) {
497 /* Kann vorkommen, wenn der Vorgänger beispielsweise eine
498 * Sel-Operation war, die keine Methoden zurückgeben
499 * konnte. Wir ersetzen die Call-Operation ebenfalls durch
500 * eine Bad-Operation. Die Verlinkung muss wiederhergestellt
502 exchange(call, new_Bad());
504 set_Call_callee_arr(call, ARR_LEN(arr), arr);
507 eset_destroy(methods);
512 /* Bestimmt für jede Call-Operation die Menge der aufrufbaren Methode
513 * und speichert das Ergebnis in der Call-Operation. (siehe
514 * "set_Call_callee"). "sel_methods" wird für den Aufbau benötigt und
515 * muss bereits aufgebaut sein. */
516 static void callee_ana(void) {
518 /* Alle Graphen analysieren. */
519 for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
520 irg_walk_graph(get_irp_irg(i), callee_walker, NULL, NULL);
521 set_irg_callee_info_state(get_irp_irg(i), irg_callee_info_consistent);
527 /* --- free method analysis ------------------------------------------------- */
530 static void free_mark(ir_node * node, eset * set);
532 static void free_mark_proj(ir_node * node, long n, eset * set) {
533 assert(get_irn_mode(node) == mode_T);
534 if (get_irn_link(node) == MARK) {
535 /* already visited */
538 set_irn_link(node, MARK);
539 switch (get_irn_opcode(node)) {
541 /* proj_proj: in einem "sinnvollen" Graphen kommt jetzt ein
542 * op_Tuple oder ein Knoten, der in "free_ana_walker" behandelt
544 ir_node * pred = get_Proj_pred(node);
545 if (get_irn_link(pred) != MARK && get_irn_op(pred) == op_Tuple) {
546 free_mark_proj(get_Tuple_pred(pred, get_Proj_proj(node)), n, set);
548 /* nothing: da in "free_ana_walker" behandelt. */
554 free_mark(get_Tuple_pred(node, n), set);
558 free_mark_proj(get_Id_pred(node), n, set);
564 /* nothing: Die Operationen werden in "free_ana_walker" selbst
569 assert(0 && "unexpected opcode or opcode not implemented");
572 set_irn_link(node, NULL);
576 static void free_mark(ir_node * node, eset * set) {
578 assert(mode_is_reference(get_irn_mode(node)));
579 if (get_irn_link(node) == MARK) {
580 return; /* already visited */
582 set_irn_link(node, MARK);
583 switch (get_irn_opcode(node)) {
585 entity * ent = get_Sel_entity(node);
586 if (is_method_type(get_entity_type(ent))) {
587 for (i = get_Sel_n_methods(node) - 1; i >= 0; --i) {
588 eset_insert(set, get_Sel_method(node, i));
594 /* nothing: SymConst points to extern method */
597 tarval * val = get_Const_tarval(node);
598 if (tarval_is_entity(val)) { /* filter null pointer */
599 entity * ent = tarval_to_entity(val);
600 if (is_method_type(get_entity_type(ent))) {
601 eset_insert(set, ent);
607 for (i = get_Phi_n_preds(node) - 1; i >= 0; --i) {
608 free_mark(get_Phi_pred(node, i), set);
612 free_mark(get_Id_pred(node), set);
615 free_mark_proj(get_Proj_pred(node), get_Proj_proj(node), set);
618 /* nothing: Wird unten behandelt! */
621 set_irn_link(node, NULL);
625 static void free_ana_walker(ir_node * node, eset * set) {
627 if (get_irn_link(node) == MARK) {
628 /* bereits in einem Zyklus besucht. */
631 switch (get_irn_opcode(node)) {
642 /* Sonderbehandlung, da der Funktionszeigereingang natürlich kein
645 set_irn_link(node, MARK);
646 for (i = get_Call_arity(node) - 1; i >= 0; --i) {
647 ir_node * pred = get_Call_param(node, i);
648 if (mode_is_reference(get_irn_mode(pred))) {
649 free_mark(pred, set);
653 /* other nodes: Alle anderen Knoten nehmen wir als Verräter an, bis
654 * jemand das Gegenteil implementiert. */
656 set_irn_link(node, MARK);
657 for (i = get_irn_arity(node) - 1; i >= 0; --i) {
658 ir_node * pred = get_irn_n(node, i);
659 if (mode_is_reference(get_irn_mode(pred))) {
660 free_mark(pred, set);
665 set_irn_link(node, NULL);
669 /* Die Datenstrukturen für sel-Methoden (sel_methods) muß vor dem
670 * Aufruf von "get_free_methods" aufgebaut sein. Die (internen)
671 * SymConst-Operationen müssen in passende Const-Operationen
672 * umgewandelt worden sein, d.h. SymConst-Operationen verweisen immer
673 * auf eine echt externe Methode. */
674 static entity ** get_free_methods(void) {
675 eset * set = eset_create();
677 entity ** arr = NEW_ARR_F(entity *, 0);
679 for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
680 ir_graph * irg = get_irp_irg(i);
681 entity * ent = get_irg_ent(irg);
682 /* insert "external visible" methods. */
683 if (get_entity_visibility(ent) != visibility_local) {
684 eset_insert(set, ent);
686 irg_walk_graph(irg, NULL, (irg_walk_func *) free_ana_walker, set);
688 /* Hauptprogramm ist auch frei, auch wenn es nicht "external
690 if(get_irp_main_irg()) {
691 eset_insert(set, get_irg_ent(get_irp_main_irg()));
693 for (ent = eset_first(set); ent; ent = eset_next(set)) {
694 ARR_APP1(entity *, arr, ent);
701 void cgana(int *length, entity ***free_methods) {
702 entity ** free_meths;
706 free_meths = get_free_methods();
708 sel_methods_dispose();
710 /* Convert the flexible array to an array that can be handled
712 *length = ARR_LEN(free_meths);
713 *free_methods = (entity **)malloc(sizeof(entity *) * (*length));
714 for (i = 0; i < (*length); i++) (*free_methods)[i] = free_meths[i];
715 DEL_ARR_F(free_meths);
718 /* Optimize the address expressions passed to call nodes.
719 * Alle SymConst-Operationen, die auf interne Methoden verweisen,
720 * werden durch Const-Operationen ersetzt.
721 * Sel Knoten deren entitaeten nicht ueberschrieben werden, werden
722 * durch Const ersetzt.
723 * Sel Knoten, fuer die keine Implementierung existiert, werden
724 * durch Bad ersetzt. */
725 void opt_call_addrs(void) {
727 sel_methods_dispose();
730 pmap * ldname_map = pmap_create();
731 assert(entities == NULL);
732 entities = eset_create();
733 for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
734 entity * ent = get_irg_ent(get_irp_irg(i));
735 /* Nur extern sichtbare Methoden können überhaupt mit SymConst
736 * aufgerufen werden. */
737 if (get_entity_visibility(ent) != local) {
738 pmap_insert(ldname_map, (void *) get_entity_ld_ident(ent), ent);
741 all_irg_walk((irg_walk_func *) sel_methods_walker, NULL, ldname_map);
742 pmap_destroy(ldname_map);