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