e3e82075b54c4ffcde1a27a554c3f877f20c6a11
[libfirm] / ir / ana / cgana.c
1 /* -------------------------------------------------------------------
2  * $Id$
3  * -------------------------------------------------------------------
4  * Intraprozedurale Analyse zur Abschätzung der Aufrulrelation. Es
5  * wird eine Menge von freien Methoden und anschließend die an den
6  * Call-Operationen aufrufbaren Methoden bestimmt.
7  *
8  * Erstellt: Hubert Schmid, 09.06.2002
9  * ---------------------------------------------------------------- */
10
11 #include "stdlib.h"
12 #include "cgana.h"
13
14
15 #include "eset.h"
16 #include "pmap.h"
17 #include "array.h"
18 #include "irprog.h"
19 #include "irgwalk.h"
20 #include "ircons.h"
21 #include "irgmod.h"
22 #include "xprintf.h"
23
24
25 /* Eindeutige Adresse zur Markierung von besuchten Knoten und zur
26  * Darstellung der unbekannten Methode. */
27 static void * MARK = &MARK;
28
29
30
31 /* --- sel methods ---------------------------------------------------------- */
32
33
34 static eset * entities = NULL;
35
36
37 /* Bestimmt die eindeutige Methode, die die Methode für den
38  * übergebenene (dynamischen) Typ überschreibt. */
39 static entity * get_implementation(type * class, entity * method) {
40   int i;
41   if (get_entity_peculiarity(method) != description &&
42       get_entity_owner(method) == class) {
43     return method;
44   }
45   for (i = get_entity_n_overwrittenby(method) - 1; i >= 0; --i) {
46     entity * e = get_entity_overwrittenby(method, i);
47     if (get_entity_peculiarity(e) != description && get_entity_owner(e) == class) {
48       return e;
49     }
50   }
51   for (i = get_class_n_supertype(class) - 1; i >= 0; --i) {
52     entity * e = get_implementation(get_class_supertype(class, i), method);
53     if (e) {
54       return e;
55     }
56   }
57   assert(0 && "implemenation not found");
58 }
59
60 /* Returns the entity that contains the implementation of the inherited
61    entity if available, else returns the entity passed. */
62 entity *get_inherited_methods_implementation(entity *inh_meth) {
63   entity *impl_meth = NULL;
64   ir_node *addr = get_atomic_ent_value(inh_meth);
65   assert(addr && "constant entity without value");
66
67   if (get_irn_op(addr) == op_Const) {
68     impl_meth = get_tv_entity(get_Const_tarval(addr));
69   }
70
71   assert(!impl_meth || get_entity_peculiarity(impl_meth) == existent);
72   return impl_meth? impl_meth : inh_meth;
73 }
74
75
76 /* A recursive descend in the overwritten relation.
77    Cycle-free, therefore must terminate. */
78 void collect_impls(entity *method, eset *set, int *size, bool *open) {
79   int i;
80   if (get_entity_peculiarity(method) == existent) {
81     if (get_entity_visibility(method) == external_allocated) {
82       assert(get_entity_irg(method) == NULL);
83       *open = true;
84     } else {
85       assert(get_entity_irg(method) != NULL);
86       if (!eset_contains(set, method)) {
87         eset_insert(set, method);
88         ++(*size);
89         /* printf("Adding existent method %d ", *size); DDME(method);
90            printf(" with owner "); DDMT(get_entity_owner(method)); */
91       }
92     }
93   }
94   if (get_entity_peculiarity(method) == inherited) {
95     entity *impl_ent = get_inherited_methods_implementation(method);
96     assert(impl_ent && "no implementation for inherited entity");
97     if (get_entity_visibility(impl_ent) == external_allocated) {
98       assert(get_entity_irg(impl_ent) == NULL);
99       *open = true;
100     } else {
101       assert(get_entity_irg(impl_ent) != NULL);
102       if (!eset_contains(set, impl_ent)) {
103         eset_insert(set, impl_ent);
104         ++(*size);
105         /* printf("Adding inherited method %d ", *size); DDME(impl_ent);
106            printf(" with owner "); DDMT(get_entity_owner(impl_ent)); */
107       }
108     }
109   }
110   /** recursive descend **/
111   for (i = get_entity_n_overwrittenby(method) - 1; i >= 0; --i)
112     collect_impls(get_entity_overwrittenby(method, i) ,set, size, open);
113 }
114
115
116 /* Alle Methoden bestimmen, die die übergebene Methode überschreiben
117  * (und implementieren). In der zurückgegebenen Reihung kommt jede
118  * Methode nur einmal vor. Der Wert 'NULL' steht für unbekannte
119  * (externe) Methoden. Die zurückgegebene Reihung muß vom Aufrufer
120  * wieder freigegeben werden (siehe "DEL_ARR_F"). Gibt es überhaupt
121  * keine Methoden, die die "method" überschreiben, so gibt die Methode
122  * "NULL" zurück. */
123 static entity ** get_impl_methods(entity * method) {
124   eset * set = eset_create();
125   int size = 0;
126   entity ** arr;
127   bool open = false;
128
129   /** Collect all method entities that can be called here **/
130   collect_impls(method, set, &size, &open);
131
132   /** Gefunden Entitaeten in ein Feld kopieren, ev. Unbekannten
133      Vorgaenger einfuegen. **/
134   if (size == 0 && !open) {
135     /* keine implementierte überschriebene Methode */
136     arr = NULL;
137   } else if (open) {
138     entity * ent;
139     arr = NEW_ARR_F(entity *, size + 1);
140     arr[0] = NULL;  /* Represents open method */
141     for (ent = eset_first(set); size > 0; ent = eset_next(set), --size)
142       arr[size] = ent;
143   } else {
144     entity * ent;
145     arr = NEW_ARR_F(entity *, size);
146     for (size -= 1, ent = eset_first(set); size >= 0; ent = eset_next(set), --size)
147       arr[size] = ent;
148   }
149   eset_destroy(set);
150   return arr;
151 }
152
153
154 static void sel_methods_walker(ir_node * node, pmap * ldname_map) {
155   if (get_irn_op(node) == op_SymConst) {
156     /* Wenn möglich SymConst-Operation durch Const-Operation
157      * ersetzen. */
158     if (get_SymConst_kind(node) == linkage_ptr_info) {
159       pmap_entry * entry = pmap_find(ldname_map, (void *) get_SymConst_ptrinfo(node));
160       if (entry != NULL) { /* Method is declared in the compiled code */
161         entity * ent = entry->value;
162         if (get_entity_visibility(ent) != external_allocated) { /* Meth. is defined */
163           assert(get_entity_irg(ent));
164           set_irg_current_block(current_ir_graph, get_nodes_Block(node));
165           exchange(node, new_d_Const(get_irn_dbg_info(node),
166                                      mode_p, tarval_p_from_entity(ent)));
167         }
168       }
169     }
170   } else if (get_irn_op(node) == op_Sel &&
171              is_method_type(get_entity_type(get_Sel_entity(node)))) {
172     entity * ent = get_Sel_entity(node);
173     if (get_irn_op(skip_Proj(get_Sel_ptr(node))) == op_Alloc) {
174       /* We know which method will be called, no dispatch necessary. */
175       assert(get_entity_peculiarity(ent) != description);
176       set_irg_current_block(current_ir_graph, get_nodes_Block(node));
177       exchange (node, copy_const_value(get_atomic_ent_value(ent)));
178     } else {
179       assert(get_entity_peculiarity(ent) != inherited);
180       if (!eset_contains(entities, ent)) {
181         /* Entity noch nicht behandelt. Alle (intern oder extern)
182          * implementierten Methoden suchen, die diese Entity
183          * überschreiben. Die Menge an entity.link speichern. */
184         set_entity_link(ent, get_impl_methods(ent));
185         eset_insert(entities, ent);
186       }
187       if (get_entity_link(ent) == NULL) {
188         /* Die Sel-Operation kann nie einen Zeiger auf eine aufrufbare
189          * Methode zurückgeben. Damit ist sie insbesondere nicht
190          * ausführbar und nicht erreichbar. */
191         /* Gib eine Warnung aus wenn die Entitaet eine Beschreibung ist
192            fuer die es keine Implementierung gibt. */
193         if (get_entity_peculiarity(ent) == description) {
194           /* @@@ GL Methode um Fehler anzuzeigen aufrufen! */
195           xprintf("WARNING: Calling method description %I in method %I which has "
196                   "no implementation!\n", get_entity_ident(ent),
197                   get_entity_ident(get_irg_ent(current_ir_graph)));
198         } else {
199           exchange(node, new_Bad());
200         }
201       } else {
202         entity ** arr = get_entity_link(ent);
203
204 #if 0
205         int i;
206         printf("\nCall site "); DDMN(node);
207         printf("  in "); DDME(get_irg_ent(current_ir_graph));
208         printf("  can call:\n");
209         for (i = 0; i < ARR_LEN(arr); i++) {
210           printf("   - "); DDME(arr[i]);
211           printf("     with owner "); DDMT(get_entity_owner(arr[i]));
212         }
213         printf("\n");
214 #endif
215
216         if (ARR_LEN(arr) == 1 && arr[0] != NULL) {
217           /* Die Sel-Operation kann immer nur einen Wert auf eine
218            * interne Methode zurückgeben. Wir können daher die
219            * Sel-Operation durch eine Const- bzw. SymConst-Operation
220            * ersetzen. */
221           set_irg_current_block(current_ir_graph, get_nodes_Block(node));
222           exchange (node, copy_const_value(get_atomic_ent_value(arr[0])));
223         }
224       }
225     }
226   }
227 }
228
229
230 /* Datenstruktur initialisieren. Zusätzlich werden alle
231  * SymConst-Operationen, die auf interne Methoden verweisen, durch
232  * Const-Operationen ersetzt. */
233 static void sel_methods_init(void) {
234   int i;
235   pmap * ldname_map = pmap_create();
236   assert(entities == NULL);
237   entities = eset_create();
238   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
239     entity * ent = get_irg_ent(get_irp_irg(i));
240     /* Nur extern sichtbare Methode können überhaupt mit SymConst
241      * aufgerufen werden. */
242     if (get_entity_visibility(ent) != local) {
243       pmap_insert(ldname_map, (void *) get_entity_ld_ident(ent), ent);
244     }
245   }
246   all_irg_walk((irg_walk_func) sel_methods_walker, NULL, ldname_map);
247   pmap_destroy(ldname_map);
248 }
249
250 /*****************************************************************************/
251
252 /* Datenstruktur freigeben. */
253 static void sel_methods_dispose(void) {
254   entity * ent;
255   assert(entities);
256   for (ent = eset_first(entities); ent; ent = eset_next(entities)) {
257     entity ** arr = get_entity_link(ent);
258     if (arr) {
259       DEL_ARR_F(arr);
260     }
261     set_entity_link(ent, NULL);
262   }
263   eset_destroy(entities);
264   entities = NULL;
265 }
266
267
268 /* Gibt die Menge aller Methoden zurück, die an diesem Sel-Knoten
269  * zurückgegeben werden können. Die Liste enthält keine doppelten
270  * Einträge. */
271 static entity ** get_Sel_arr(ir_node * sel) {
272   static entity ** NULL_ARRAY = NULL;
273   entity * ent;
274   entity ** arr;
275   assert(sel && get_irn_op(sel) == op_Sel);
276   ent = get_Sel_entity(sel);
277   assert(is_method_type(get_entity_type(ent))); /* what else? */
278   arr = get_entity_link(ent);
279   if (arr) {
280     return arr;
281   } else {
282     /* "NULL" zeigt an, dass keine Implementierung existiert. Dies
283      * kann für polymorphe (abstrakte) Methoden passieren. */
284     if (!NULL_ARRAY) {
285       NULL_ARRAY = NEW_ARR_F(entity *, 0);
286     }
287     return NULL_ARRAY;
288   }
289 }
290
291
292 static int get_Sel_n_methods(ir_node * sel) {
293   return ARR_LEN(get_Sel_arr(sel));
294 }
295
296
297 static entity * get_Sel_method(ir_node * sel, int pos) {
298   entity ** arr = get_Sel_arr(sel);
299   assert(pos >= 0 && pos < ARR_LEN(arr));
300   return arr[pos];
301 }
302
303
304
305 /* --- callee analysis ------------------------------------------------------ */
306
307
308 static void callee_ana_node(ir_node * node, eset * methods);
309
310
311 static void callee_ana_proj(ir_node * node, long n, eset * methods) {
312   assert(get_irn_mode(node) == mode_T);
313   if (get_irn_link(node) == MARK) {
314     /* already visited */
315     return;
316   }
317   set_irn_link(node, MARK);
318
319   switch (get_irn_opcode(node)) {
320   case iro_Proj: {
321     /* proj_proj: in einem "sinnvollen" Graphen kommt jetzt ein
322      * op_Tuple oder ein Knoten, der eine "freie Methode"
323      * zurückgibt. */
324     ir_node * pred = get_Proj_pred(node);
325     if (get_irn_link(pred) != MARK) {
326       if (get_irn_op(pred) == op_Tuple) {
327         callee_ana_proj(get_Tuple_pred(pred, get_Proj_proj(node)), n, methods);
328       } else {
329         eset_insert(methods, MARK); /* free method -> unknown */
330       }
331     }
332     break;
333   }
334
335   case iro_Tuple:
336     callee_ana_node(get_Tuple_pred(node, n), methods);
337     break;
338
339   case iro_Id:
340     callee_ana_proj(get_Id_pred(node), n, methods);
341     break;
342
343   default:
344     eset_insert(methods, MARK); /* free method -> unknown */
345     break;
346   }
347
348   set_irn_link(node, NULL);
349 }
350
351
352 static void callee_ana_node(ir_node * node, eset * methods) {
353   int i;
354
355   assert((get_irn_mode(node) == mode_p) || is_Bad(node));
356   /* rekursion verhindern */
357   if (get_irn_link(node) == MARK) {
358     /* already visited */
359     return;
360   }
361   set_irn_link(node, MARK);
362
363   switch (get_irn_opcode(node)) {
364   case iro_SymConst:
365     /* externe Methode (wegen fix_symconst!) */
366     eset_insert(methods, MARK); /* free method -> unknown */
367     break;
368
369   case iro_Const: {
370     /* interne Methode */
371     entity * ent = get_Const_tarval(node)->u.p.ent;
372     assert(ent && is_method_type(get_entity_type(ent)));
373     if (get_entity_visibility(ent) != external_allocated) {
374       assert(get_entity_irg(ent));
375       eset_insert(methods, ent);
376     } else {
377       eset_insert(methods, MARK); /* free method -> unknown */
378     }
379     break;
380   }
381
382   case iro_Sel:
383     /* polymorphe Methode */
384     for (i = get_Sel_n_methods(node) - 1; i >= 0; --i) {
385       entity * ent = get_Sel_method(node, i);
386       if (ent) {
387         eset_insert(methods, ent);
388       } else {
389         eset_insert(methods, MARK);
390       }
391     }
392     break;
393
394   case iro_Bad:
395     /* nothing */
396     break;
397
398   case iro_Phi: /* Vereinigung */
399     for (i = get_Phi_n_preds(node) - 1; i >= 0; --i) {
400       callee_ana_node(get_Phi_pred(node, i), methods);
401     }
402     break;
403
404   case iro_Id:
405     callee_ana_node(get_Id_pred(node), methods);
406     break;
407
408   case iro_Proj:
409     callee_ana_proj(get_Proj_pred(node), get_Proj_proj(node), methods);
410     break;
411
412   case iro_Add:
413   case iro_Sub:
414   case iro_Conv:
415     /* extern */
416     eset_insert(methods, MARK); /* free method -> unknown */
417     break;
418
419   default:
420     assert(0 && "invalid opcode or opcode not implemented");
421     break;
422   }
423
424   set_irn_link(node, NULL);
425 }
426
427
428 static void callee_walker(ir_node * call, void * env) {
429   if (get_irn_op(call) == op_Call) {
430     eset * methods = eset_create();
431     entity * ent;
432     entity ** arr = NEW_ARR_F(entity *, 0);
433     callee_ana_node(skip_nop(get_Call_ptr(call)), methods);
434     if (eset_contains(methods, MARK)) { /* unknown method */
435       ARR_APP1(entity *, arr, NULL);
436     }
437     for (ent = eset_first(methods); ent; ent = eset_next(methods)) {
438       if (ent != MARK) {
439         ARR_APP1(entity *, arr, ent);
440       }
441     }
442     if (ARR_LEN(arr) == 0) {
443       /* Kann vorkommen, wenn der Vorgänger beispielsweise eine
444        * Sel-Operation war, die keine Methoden zurückgeben
445        * konnte. Wir ersetzen die Call-Operation ebenfalls durch
446        * eine Bad-Operation. Die Verlinkung muss wiederhergestellt
447        * werden! */
448       exchange(call, new_Bad());
449     } else {
450       set_Call_callee_arr(call, ARR_LEN(arr), arr);
451     }
452     DEL_ARR_F(arr);
453     eset_destroy(methods);
454   }
455 }
456
457
458 /* Bestimmt für jede Call-Operation die Menge der aufrufbaren Methode
459  * und speichert das Ergebnis in der Call-Operation. (siehe
460  * "set_Call_callee"). "sel_methods" wird für den Aufbau benötigt und
461  * muss bereits aufgebaut sein. */
462 static void callee_ana(void) {
463   int i;
464   /* Alle Graphen analysieren. */
465   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
466     irg_walk_graph(get_irp_irg(i), callee_walker, NULL, NULL);
467   }
468 }
469
470
471
472 /* --- free method analysis ------------------------------------------------- */
473
474
475 static void free_mark(ir_node * node, eset * set);
476
477 static void free_mark_proj(ir_node * node, long n, eset * set) {
478   assert(get_irn_mode(node) == mode_T);
479   if (get_irn_link(node) == MARK) {
480     /* already visited */
481     return;
482   }
483   set_irn_link(node, MARK);
484   switch (get_irn_opcode(node)) {
485   case iro_Proj: {
486     /* proj_proj: in einem "sinnvollen" Graphen kommt jetzt ein
487      * op_Tuple oder ein Knoten, der in "free_ana_walker" behandelt
488      * wird. */
489     ir_node * pred = get_Proj_pred(node);
490     if (get_irn_link(pred) != MARK && get_irn_op(pred) == op_Tuple) {
491       free_mark_proj(get_Tuple_pred(pred, get_Proj_proj(node)), n, set);
492     } else {
493       /* nothing: da in "free_ana_walker" behandelt. */
494     }
495     break;
496   }
497
498   case iro_Tuple:
499     free_mark(get_Tuple_pred(node, n), set);
500     break;
501
502   case iro_Id:
503     free_mark_proj(get_Id_pred(node), n, set);
504     break;
505
506   case iro_Start:
507   case iro_Alloc:
508   case iro_Load:
509     /* nothing: Die Operationen werden in "free_ana_walker" selbst
510      * behandelt. */
511     break;
512
513   default:
514     assert(0 && "unexpected opcode or opcode not implemented");
515     break;
516   }
517   set_irn_link(node, NULL);
518 }
519
520
521 static void free_mark(ir_node * node, eset * set) {
522   int i;
523   assert(get_irn_mode(node) == mode_p);
524   if (get_irn_link(node) == MARK) {
525     return; /* already visited */
526   }
527   set_irn_link(node, MARK);
528   switch (get_irn_opcode(node)) {
529   case iro_Sel: {
530     entity * ent = get_Sel_entity(node);
531     if (is_method_type(get_entity_type(ent))) {
532       for (i = get_Sel_n_methods(node) - 1; i >= 0; --i) {
533         eset_insert(set, get_Sel_method(node, i));
534       }
535     }
536     break;
537   }
538   case iro_SymConst:
539     /* nothing: SymConst points to extern method */
540     break;
541   case iro_Const: {
542     tarval * val = get_Const_tarval(node);
543     entity * ent = val->u.p.ent;
544     if (ent != NULL && is_method_type(get_entity_type(ent))) {
545       eset_insert(set, ent);
546     }
547     break;
548   }
549   case iro_Phi:
550     for (i = get_Phi_n_preds(node) - 1; i >= 0; --i) {
551       free_mark(get_Phi_pred(node, i), set);
552     }
553     break;
554   case iro_Id:
555     free_mark(get_Id_pred(node), set);
556     break;
557   case iro_Proj:
558     free_mark_proj(get_Proj_pred(node), get_Proj_proj(node), set);
559     break;
560   default:
561     /* nothing: Wird unten behandelt! */
562     break;
563   }
564   set_irn_link(node, NULL);
565 }
566
567
568 static void free_ana_walker(ir_node * node, eset * set) {
569   int i;
570   if (get_irn_link(node) == MARK) {
571     /* bereits in einem Zyklus besucht. */
572     return;
573   }
574   switch (get_irn_opcode(node)) {
575   /* special nodes */
576   case iro_Sel:
577   case iro_SymConst:
578   case iro_Const:
579   case iro_Phi:
580   case iro_Id:
581   case iro_Proj:
582   case iro_Tuple:
583     /* nothing */
584     break;
585   /* Sonderbehandlung, da der Funktionszeigereingang natürlich kein
586    * Verräter ist. */
587   case iro_Call:
588     set_irn_link(node, MARK);
589     for (i = get_Call_arity(node) - 1; i >= 0; --i) {
590       ir_node * pred = get_Call_param(node, i);
591       if (get_irn_mode(pred) == mode_p) {
592         free_mark(pred, set);
593       }
594     }
595     break;
596   /* other nodes: Alle anderen Knoten nehmen wir als Verräter an, bis
597    * jemand das Gegenteil implementiert. */
598   default:
599     set_irn_link(node, MARK);
600     for (i = get_irn_arity(node) - 1; i >= 0; --i) {
601       ir_node * pred = get_irn_n(node, i);
602       if (get_irn_mode(pred) == mode_p) {
603         free_mark(pred, set);
604       }
605     }
606     break;
607   }
608   set_irn_link(node, NULL);
609 }
610
611
612 /* Die Datenstrukturen für sel-Methoden (sel_methods) muß vor dem
613  * Aufruf von "get_free_methods" aufgebaut sein. Die (internen)
614  * SymConst-Operationen müssen in passende Const-Operationen
615  * umgewandelt worden sein, d.h. SymConst-Operationen verweisen immer
616  * auf eine echt externe Methode.  */
617 static entity ** get_free_methods(void) {
618   eset * set = eset_create();
619   int i;
620   entity ** arr = NEW_ARR_F(entity *, 0);
621   entity * ent;
622   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
623     ir_graph * irg = get_irp_irg(i);
624     entity * ent = get_irg_ent(irg);
625     /* insert "external visible" methods. */
626     if (get_entity_visibility(ent) != local) {
627       eset_insert(set, ent);
628     }
629     irg_walk_graph(irg, NULL, (irg_walk_func) free_ana_walker, set);
630   }
631   /* Hauptprogramm ist auch frei, auch wenn es nicht "external
632    * visible" ist. */
633   eset_insert(set, get_irg_ent(get_irp_main_irg()));
634   for (ent = eset_first(set); ent; ent = eset_next(set)) {
635     ARR_APP1(entity *, arr, ent);
636   }
637   eset_destroy(set);
638
639   return arr;
640 }
641
642 void cgana(int *length, entity ***free_methods) {
643   entity ** free_meths;
644   int i;
645
646   sel_methods_init();
647   free_meths = get_free_methods();
648   callee_ana();
649   sel_methods_dispose();
650
651   /* Convert the flexible array to an array that can be handled
652      by standard C. */
653   *length = ARR_LEN(free_meths);
654   *free_methods = (entity **)malloc(sizeof(entity *) * (*length));
655   for (i = 0; i < (*length); i++) (*free_methods)[i] = free_meths[i];
656   DEL_ARR_F(free_meths);
657 }