typo
[libfirm] / ir / ana / ecg.c
1 /* -*- c -*- */
2
3 /*
4  * Project:     libFIRM
5  * File name:   ir/ana/ecg.c
6  * Purpose:     Extended Call Graph
7  * Author:      Florian
8  * Modified by:
9  * Created:     14.09.2004
10  * CVS-ID:      $$
11  * Copyright:   (c) 1999-2004 Universität Karlsruhe
12  * Licence:     This file is protected by GPL -  GNU GENERAL PUBLIC LICENSE.
13  */
14
15 #ifdef HAVE_CONFIG_H
16 # include <config.h>
17 #endif
18
19 /**
20    Erweiterter Aufrufgraph.
21  */
22
23 #include "irnode.h"
24 #include "pmap.h"
25 /* #include "eset.h" */
26 #include "irgwalk.h"
27 #include "irgmod.h"
28 #include "irvrfy.h"
29 #include "trvrfy.h"
30 #include "xmalloc.h"
31
32 # define TRUE 1
33 # define FALSE 0
34
35 # define BUF_SIZE 1024
36
37 # include "ecg.h"
38
39 /*
40   data structures
41 */
42
43 /* Lists, err, Sets */
44 typedef struct lset_entry
45 {
46   void *data;
47   struct lset_entry *next;
48 } lset_entry_t;
49
50 typedef struct lset
51 {
52   lset_entry_t *first;
53   lset_entry_t *last;           /* useful for lset_append */
54   lset_entry_t *curs;           /* for lset_first/lset_next */
55   int n_entries;
56 } lset_t;
57
58
59 typedef enum typalise_kind_enum {
60   type_invalid = 0,             /* invalid (only set at deletion time) */
61   type_exact = 1,               /* this and only this type (res.type) */
62   type_types = 2,               /* these types (res.types) */
63   type_type  = 3                /* this type and sub types (res.type) */
64 } typalise_kind;
65
66 typedef struct typalise
67 {
68   typalise_kind kind;
69   union
70   {
71     type *type;                 /* for kind == kind_exact and kind == kind_type */
72     lset_t *types;              /* for kind == kind_types */
73   } res;
74   int id;
75 } typalise_t;
76
77 /*
78    le flag
79 */
80 static int verbose     = 0;
81 static int do_typalise = 0;
82
83 /*
84    globals
85 */
86
87 /* mapping from method graphs (callR) to method graphs (lset_ts of callEds) */
88 /* static pmap *calls; */
89 static pmap *graph_infos;
90
91 /** Counters for ecg_ecg and friends */
92 static long _graphs = 0;
93 static long _calls  = 0;
94 static long _allocs = 0;
95
96 static int _depth = 0;
97 static int _max_depth = 0;
98
99 static int _max_callEds = 0;
100 static entity* _max_callEds_callR = NULL;
101
102 static long ta_id = 0;
103
104 /*
105   Lists, err, Sets
106  */
107
108
109 /* create a new lset */
110 static lset_t *lset_create ()
111 {
112   lset_t *lset = xmalloc (sizeof (lset_t));
113
114   return (lset);
115 }
116
117 /* check whether the lset contains an entry for the given data */
118 static int lset_contains (lset_t *lset, void *data)
119 {
120   lset_entry_t *entry = lset->first;
121
122   while (NULL != entry) {
123     if (data == entry->data) {
124       return (TRUE);
125     }
126
127     entry = entry->next;
128   }
129
130   return (FALSE);
131 }
132
133 /* check whether the given lset is empty */
134 static int lset_empty (lset_t *lset)
135 {
136   return (NULL == lset->first);
137 }
138
139
140 /* insert the data into the lset (unless there's an entry for it
141    already) */
142 static void lset_insert (lset_t *lset, void *data)
143 {
144   if (! lset_contains (lset, data)) {
145     lset_entry_t *entry = xmalloc (sizeof (lset_entry_t));
146     entry->data = data;
147     entry->next = lset->first;
148     lset->first = entry;
149
150     if (NULL == lset->last) {
151       lset->last = entry;
152     }
153
154     lset->n_entries ++;
155   }
156 }
157
158 /* insert all entries from src into tgt */
159 static void lset_insert_all (lset_t *tgt, lset_t *src)
160 {
161   lset_entry_t *curs = src->first;
162
163   while (NULL != curs) {
164     lset_insert (tgt, curs->data);
165
166     curs = curs->next;
167   }
168 }
169
170 /* append src to tgt. src is deallocated. */
171 static void lset_append (lset_t *tgt, lset_t *src)
172 {
173   assert (! tgt->last->next);
174
175   tgt->last->next = src->first;
176   tgt->last = src->last;
177   tgt->n_entries += src->n_entries;
178
179   memset (src, 0x00, sizeof (lset_t));
180   free (src);
181 }
182
183 /* remove the entry for the given data element from the lset. return
184    TRUE iff it was on the list in the first place, FALSE else */
185 static int lset_remove (lset_t *lset, void *data)
186 {
187   lset_entry_t *entry = lset->first;
188   lset_entry_t *prev = NULL;
189
190   while (NULL != entry) {
191     if (data == entry->data) {
192       /* ok, dike it out */
193
194       if (NULL == prev) { /* ok, it's lset->first that needs diking */
195         lset->first = entry->next;
196       } else {
197         prev->next = entry->next;
198       }
199
200       memset (entry, 0x00, sizeof (lset_entry_t));
201       free (entry);
202
203       lset->n_entries --;
204
205       return (TRUE);
206     }
207
208     prev = entry;
209     entry = entry->next;
210   }
211
212   return (FALSE);
213 }
214
215 /* prepare the given lset for an iteration. return the first element. */
216 static void *lset_first (lset_t *lset)
217 {
218   lset->curs = lset->first;
219
220   if (lset->first) {
221     return (lset->first->data);
222   } else {
223     return (NULL);
224   }
225 }
226
227 /* after calling lset_first, get the next element, if applicable, or
228    NULL */
229 static void *lset_next (lset_t *lset)
230 {
231   lset->curs = lset->curs->next;
232
233   if (lset->curs) {
234     return (lset->curs->data);
235   } else {
236     return (NULL);
237   }
238 }
239
240 /* say how many entries there are in the given lset */
241 static int lset_n_entries (lset_t *lset)
242 {
243   return (lset->n_entries);
244 }
245
246 /* deallocate the lset and all of its entries */
247 static void lset_destroy (lset_t *lset)
248 {
249   lset_entry_t *curs = lset->first;
250
251   while (NULL != curs) {
252     lset_entry_t *tmp = curs->next;
253
254     memset (curs, 0x00, sizeof (lset_entry_t));
255     free (curs);
256
257     curs = tmp;
258   }
259
260   memset (lset, 0x00, sizeof (lset_t));
261   free (lset);
262 }
263
264 /* ====================
265   Typalize Ptr
266  ==================== */
267 /**
268    Find out whether the given clazz uses the given implementation of a
269    method.  Presumably, this is because clazz inherits the graph as
270    the implementation for a method.
271 */
272 static int uses_graph (type *clazz, entity *meth, ir_graph *graph)
273 {
274   type *g_clazz = get_entity_owner (meth);
275
276   if (g_clazz == clazz) {
277     return (TRUE);
278   }
279
280   if (peculiarity_existent == get_entity_peculiarity (meth)) {
281     ir_graph *g_graph = get_entity_irg (meth);
282
283     if (g_graph != graph) {
284       return (FALSE);
285     }
286   }
287
288   /* else inherited or description */
289   int use = FALSE;
290   int i;
291   int n_over = get_entity_n_overwrittenby (meth); /* DOWN-wards */
292
293   for (i = 0; (i < n_over) && (!use); i ++) {
294     entity *over = get_entity_overwrittenby (meth, i);
295
296     use |= uses_graph (clazz, over, graph);
297   }
298
299   return (use);
300 }
301
302
303 /**
304    Find out whether otype is a subtype of stype.
305    Return non-zero iff otype is a subtype of stype.
306 */
307 static int is_subtype (type *otype, type *stype)
308 {
309   int n_sub = get_class_n_subtypes (stype);
310   int is_sub = FALSE;
311   int i;
312
313   if (otype == stype) {
314     return (TRUE);
315   }
316
317   for (i = 0; (!is_sub) && (i < n_sub); i ++) {
318     type *sub = get_class_subtype (stype, i);
319
320     is_sub |= is_subtype (otype, sub);
321   }
322
323
324   return (is_sub);
325 }
326
327 /**
328     Compute the closure of all subtypes of otype (including otype
329     itself)
330 */
331 static void _collect_subtypes (type *otype, lset_t *set)
332 {
333   lset_insert (set, otype);
334
335   int n_sub = get_class_n_subtypes (otype);
336   int i;
337
338   for (i = 0; i < n_sub; i ++) {
339     type *sub = get_class_subtype (otype, i);
340
341     _collect_subtypes (sub, set);
342   }
343 }
344
345 static lset_t *subtype_closure (type *otype)
346 {
347   lset_t *set = lset_create ();
348
349   _collect_subtypes (otype, set);
350
351   return (set);
352 }
353
354 /**
355    Helper method for get_owner_types
356 */
357 static void _collect_owner_types (entity *method, ir_graph *graph, lset_t *tps)
358 {
359   /* search DOWNwards in clazz hierarchy */
360
361   if ((peculiarity_description == get_entity_peculiarity (method)) ||
362       (peculiarity_inherited   == get_entity_peculiarity (method))) {
363     lset_insert (tps, get_entity_owner (method));
364   } else if (peculiarity_existent == get_entity_peculiarity (method)) {
365     ir_graph *ex_graph = get_entity_irg (method);
366
367     if ((NULL == ex_graph) || (ex_graph == graph)) {
368       /* wtf? they define the same graph again? well, whatever: */
369       lset_insert (tps, get_entity_owner (method));
370     } else {
371       /* aha: they define a new graph. can't have that, so bail out */
372       return;
373     }
374   }
375
376   int n_over = get_entity_n_overwrittenby (method);
377   int i;
378
379   for (i = 0; i < n_over; i ++) {
380     entity *ometh = get_entity_overwrittenby (method, i);
381
382     _collect_owner_types (ometh, graph, tps);
383   }
384 }
385
386
387 /**
388    Collect all classes that use the given implementation of a method.
389 */
390 static lset_t *get_owner_types (ir_graph *graph)
391 {
392   lset_t *tps = lset_create ();
393   entity *meth = get_irg_entity (graph);
394
395   _collect_owner_types (meth, graph, tps);
396
397   return (tps);
398 }
399
400
401 /**
402    Convenience funcs to create a typalise_t
403 */
404 static typalise_t *ta_exact (type *tp)
405 {
406   typalise_t *ta = (typalise_t*) xmalloc (sizeof (typalise_t));
407   ta->kind = type_exact;
408   ta->res.type = tp;
409   ta->id = ta_id ++;
410
411   assert (is_class_type (tp));
412
413   return (ta);
414 }
415
416 static typalise_t *ta_types (lset_t *set)
417 {
418   typalise_t *ta = (typalise_t*) xmalloc (sizeof (typalise_t));
419   ta->kind = type_types;
420   ta->res.types = set;
421   ta->id = ta_id ++;
422
423   return (ta);
424 }
425
426 static typalise_t *ta_type (type *tp)
427 {
428   typalise_t *ta = (typalise_t*) xmalloc (sizeof (typalise_t));
429   ta->kind = type_type;
430   ta->res.type = tp;
431   ta->id = ta_id ++;
432
433   assert (is_class_type (tp));
434
435   return (ta);
436 }
437
438 static void ta_delete (typalise_t *ta)
439 {
440   if (type_types == ta->kind) {
441     lset_destroy (ta->res.types);
442     ta->res.types = NULL;
443   } else {
444     ta->res.type = NULL;
445   }
446
447   ta->kind = type_invalid;
448
449   free (ta);
450 }
451
452 /**
453     Join 'one' and 'two'; both args are deallocated, result is freshly
454     allocated.
455 */
456 static typalise_t *ta_join (typalise_t *one, typalise_t *two)
457 {
458   typalise_t *res = NULL;
459
460   switch (one->kind) {
461   case (type_exact): {
462     switch (two->kind) {
463     case (type_exact): {
464       if (one->res.type == two->res.type) {
465         res = one;
466       } else {
467         lset_t *set = lset_create ();
468         lset_insert (set, one->res.type);
469         lset_insert (set, two->res.type);
470         res = ta_types (set);
471
472         ta_delete (one);
473       }
474
475       ta_delete (two);
476     } break;
477     case (type_types): {
478       lset_insert (two->res.types, one->res.type);
479       ta_delete (one);
480
481       res = two;
482     } break;
483     case (type_type): {
484       if (is_subtype (one->res.type, two->res.type)) {
485         ta_delete (one);
486         res = two;
487       } else {
488         lset_t *closure = subtype_closure (two->res.type);
489         lset_insert (closure, one->res.type);
490
491         ta_delete (two);
492
493         res = one;
494       }
495     } break;
496     }
497   } break;
498   case (type_types): {
499     switch (two->kind) {
500     case (type_exact): {
501       res = ta_join (two, one);
502     } break;
503     case (type_types): {
504       lset_insert_all (one->res.types, two->res.types);
505       ta_delete (two);
506
507       res = one;
508     } break;
509     case (type_type): {
510       lset_t *closure = subtype_closure (two->res.type);
511       lset_append (one->res.types, closure);
512
513       ta_delete (two);
514
515       res = one;
516     } break;
517     }
518   } break;
519   case (type_type): {
520     switch (two->kind) {
521     case (type_exact): {
522       res = ta_join (two, one);
523     } break;
524     case (type_types): {
525       res = ta_join (two, one);
526     } break;
527     case (type_type): {
528       type *one_type = one->res.type;
529       type *two_type = two->res.type;
530
531       if (is_subtype (one_type, two_type)) {
532         ta_delete (one);
533         res = two;
534       } else if (is_subtype (two_type, one_type)) {
535         ta_delete (two);
536         res = one;
537       } else {
538         lset_t *one_closure = subtype_closure (one->res.type);
539         lset_t *two_closure = subtype_closure (two->res.type);
540
541         lset_append (one_closure, two_closure);
542
543         ta_delete (two);
544         ta_delete (one);
545
546         res = ta_types (one_closure);
547       }
548     } break;
549     }
550   } break;
551   }
552
553   assert (res && "no result");
554
555   return (res);
556 }
557
558
559 static const char *ta_name (typalise_t *ta)
560 {
561 /* # define BUF_SIZE 1024 */
562   static char buf [BUF_SIZE];
563
564   int len = sprintf (buf, "[%d] ", ta->id);
565
566   switch (ta->kind) {
567   case (type_exact): {
568     len += sprintf (buf+len, "only ");
569     strncat (buf, get_type_name (ta->res.type), BUF_SIZE);
570   } break;
571   case (type_types): {
572     len += sprintf (buf+len, "one_of ");
573
574     type *iter = lset_first (ta->res.types);
575
576     int size = BUF_SIZE - len - 1;
577     while ((NULL != iter) && (0 < size)) {
578       char *dest = strncat (buf, get_type_name (iter), size);
579       size = (dest - buf);
580
581       iter = lset_next (ta->res.types);
582     }
583   } break;
584   case (type_type): {
585     len += sprintf (buf+len, "poly ");
586     strncat (buf, get_type_name (ta->res.type), BUF_SIZE);
587   } break;
588   }
589
590   return (buf);
591 /* # undef BUF_SIZE */
592 }
593
594 /**
595    Check whether the given typalise_t includes the given type.
596 */
597 static int ta_supports (typalise_t *ta, ir_graph *graph)
598 {
599   switch (ta->kind) {
600   case (type_exact): {
601     int res = FALSE;
602     lset_t *tps = get_owner_types (graph);
603
604     if (lset_contains (tps, ta->res.type)) {
605       res = TRUE;
606     }
607
608     lset_destroy (tps);
609
610     return (res);
611   }
612   case (type_type): {
613     entity *meth = get_irg_entity (graph);
614     type *tp = get_entity_owner (meth);
615     int res = is_subtype (tp, ta->res.type);
616
617     if (res) {
618       return (TRUE);
619     } else {
620       res = uses_graph (ta->res.type, meth, graph);
621     }
622
623     return (res);
624   }
625   case (type_types): {
626     type *tp = get_entity_owner (get_irg_entity (graph));
627
628     return (lset_contains (ta->res.types, tp));
629   }
630   }
631
632   assert (0 && "invalid ta");
633 }
634
635
636 /**
637    Given a set of graphs and a typalise_t,  return the method(s) in
638    the set that are supported by the typalise_t.  Also, deallocates
639    the given set.
640 */
641 static lset_t *filter_for_ta (lset_t *set, typalise_t *ta)
642 {
643   lset_t *res = lset_create ();
644   ir_graph *curs = (ir_graph*) lset_first (set);
645
646   while (NULL != curs) {
647     if (ta_supports (ta, curs)) {
648       lset_insert (res, curs);
649     }
650
651     curs = lset_next (set);
652   }
653
654   lset_destroy (set);
655
656   return (res);
657 }
658
659
660 /**
661    Return a list containing all types of 'set' which are a subtype of 'type'.
662 */
663 static lset_t *filter_for_type (lset_t *set, type *stype)
664 {
665   type *curs = (type*) lset_first (set);
666   lset_t *lset = lset_create ();
667
668   while (NULL != curs) {
669     if (is_subtype (curs, stype)) {
670       lset_insert (lset, curs);
671     }
672
673     curs = lset_next (set);
674   }
675
676   return (lset);
677 }
678
679 /**
680     Find an approximation to the given node's value's types
681 */
682 static typalise_t *typalise (ir_node*);
683
684 /**
685     Find an approximation to the given proj node's value's types
686 */
687 static typalise_t *typalise_proj (ir_node *proj)
688 {
689   typalise_t *res = NULL;
690   ir_node *proj_in = get_Proj_pred (proj);
691
692   if (iro_Proj  == get_irn_opcode (proj_in)) {
693     /* fprintf (stdout, "\tProj (Proj)\n"); */
694
695     proj_in = get_Proj_pred (proj_in);
696     if (iro_Start == get_irn_opcode (proj_in)) {
697       long n = get_Proj_proj (proj);
698       if (1 == n) {
699         /* yay proj this */
700         ir_graph *graph = get_irn_irg (proj);
701         entity   *meth  = get_irg_entity (graph);
702         type     *tp    = get_entity_owner (meth);
703
704         /* res = ta_exact (tp); */
705         res = ta_type (tp);     /* TODO */
706       } else {
707         /* ugh proj arg */
708         /* hey, even 'filtering' this NULL by the select of the actual
709            call is probably as "precise" as anything: */
710         return (NULL);
711       }
712     } else if (iro_Call == get_irn_opcode (proj_in)) {
713       /* call result ... 'whatever' */
714       ir_node *call_ptr = get_Call_ptr (proj_in);
715
716       res = typalise (call_ptr);
717     } else {
718       fprintf (stdout, "\n Proj(Proj(%s)) not handled\n",
719                get_op_name (get_irn_op (proj_in)));
720       assert (0);
721     }
722   } else {
723     opcode op = get_irn_opcode (proj_in);
724     if ((iro_Load != op) && (iro_Alloc != op) && (iro_Call != op)) {
725       fprintf (stdout, "\n Proj(%s) not handled\n",
726                get_op_name (get_irn_op (proj_in)));
727       assert (0);
728     }
729     res = typalise (proj_in);      /* everything else */
730     /* Proj(Load), Proj(New), Proj(Call) */
731   }
732
733   return (res);
734 }
735
736
737 /**
738    For the given ptr, do a quick check about what (class) types may be
739    brought along on it.
740 */
741 static typalise_t *typalise (ir_node *node)
742 {
743   opcode op = get_irn_opcode (node);
744   typalise_t *res = NULL;
745
746   switch (op) {
747   case (iro_Cast): {
748     typalise_t *ta = NULL;
749     type *tp = get_Cast_type (node);
750
751     if (is_pointer_type (tp)) {
752       tp = get_pointer_points_to_type (tp);
753     }
754     assert (is_class_type (tp));
755
756     ta = typalise (get_Cast_op (node));
757
758     if (NULL == ta) {           /* no type found */
759       ta = ta_type (tp);
760     } else if (type_exact == ta->kind) { /* one type found */
761       /* nothing (maybe check cast? */
762     } else if (type_type == ta->kind) { /* some types found */
763       if (is_subtype (tp, ta->res.type)) {
764         ta->res.type = tp;     /* assume cast is correct */
765       } else {
766         /* should assert (is_subtype (ta->res.type, tp)) */
767       }
768     } else if (type_types == ta->kind) {
769       lset_t *ftp = filter_for_type (ta->res.types, tp);
770       lset_destroy (ta->res.types);
771       ta->res.types = ftp;
772     }
773
774     res = ta;
775   } break;
776
777   case (iro_Proj): {
778     res = typalise_proj (node);
779   } break;
780
781   case (iro_Load): {
782     /* presumably it's call(load(ptr)) we're analyzing. */
783     ir_node *load_ptr = get_Load_ptr (node);
784
785     res = typalise (load_ptr);
786   } break;
787
788   case (iro_Sel): {
789     /* FILTER */
790     /* it's call(sel(ptr)) or load(sel(ptr)) */
791     entity *ent = get_Sel_entity (node);
792     type *tp = get_entity_type (ent);
793
794     if (is_method_type (tp)) {
795       tp = get_entity_type (ent);
796       tp = get_method_res_type (tp, 0);
797
798       if (is_pointer_type (tp)) {
799         tp = get_pointer_points_to_type (tp);
800       }
801
802       res = ta_type (tp);
803     } else if (is_class_type (tp)) {
804       tp = get_entity_type (ent);
805
806       if (is_pointer_type (tp)) {
807         tp = get_pointer_points_to_type (tp);
808       }
809
810       res = ta_type (tp);
811     } else if (is_pointer_type (tp)) {
812       tp = get_pointer_points_to_type (tp);
813       res = ta_type (tp);
814     } else {
815       assert (0 && "select not handled");
816     }
817   } break;
818
819   case (iro_Phi): {
820     int n_ins = get_irn_arity (node);
821     int i;
822     ir_node *phi_in = NULL;
823     typalise_t *ta = NULL;
824     /* assert (0 && "Do we ever get here?"); */ /* apparently, we do. */
825
826     for (i = 0; i < n_ins; i ++) {
827       phi_in = get_irn_n (node, i);
828       ta = (NULL == ta) ? typalise (phi_in) : ta_join (ta, typalise (phi_in));
829     }
830
831     res = ta;
832   } break;
833
834   case (iro_Alloc): {
835     type *type = get_Alloc_type (node);
836     res = ta_exact (type);
837   } break;
838
839   case (iro_Call): {
840     /* presumably call(sel(proj(call))) */
841     ir_node *ptr = get_Call_ptr (node);
842     entity *meth = NULL;
843     if (iro_Sel == get_irn_opcode (ptr)) {
844       meth = get_Sel_entity (ptr);
845     } else if (iro_SymConst == get_irn_opcode (ptr)) {
846       if (get_SymConst_kind(ptr) == symconst_addr_ent) {
847         meth = get_SymConst_entity (ptr);
848       } else {
849         meth = NULL;            /* WTF? */
850       }
851     }
852
853     if (NULL != meth) {
854       type *tp = get_method_res_type ((type*) meth, 0);
855       res = ta_type (tp);
856     } else {
857       /* could be anything */
858       /* fprintf (stdout, "meth=(null)"); */
859       res = NULL;
860     }
861
862     fprintf (stdout, "]\n");
863
864   } break;
865
866   case (iro_SymConst): {
867     if (get_SymConst_kind(node) == symconst_type_tag) {
868       type *tp = get_SymConst_type (node);
869
870       res = ta_type (tp);
871     } else if (get_SymConst_kind (node) == symconst_addr_ent) {
872       entity *ent = get_SymConst_entity (node);
873       type *tp = get_entity_type (ent);
874       tp = get_pointer_points_to_type (tp);
875       assert (is_class_type (tp));
876
877       res = ta_type (tp);       /* can't use ta_exact */
878     } else {
879       fprintf (stdout, "can't handle SymConst %s?\n",
880                get_op_name (get_irn_op (node)));
881       res = NULL;
882     }
883   } break;
884
885   /* template:
886      case (iro_Cast): {}
887      break;
888   */
889
890   default: {
891     fprintf (stdout, "what's with %s?\n", get_op_name (get_irn_op (node)));
892     assert (0);
893   } break;
894   }
895
896   return (res);
897 }
898
899
900 /* ====================
901   Alloc stuff
902   ==================== */
903 static void append_alloc (graph_info_t *ginfo, ir_node *alloc, type *tp)
904 {
905   alloc_info_t *ainfo = (alloc_info_t*) xmalloc (sizeof (alloc_info_t));
906
907   ainfo->graph = ginfo->graph;
908   ainfo->alloc = alloc;
909   ainfo->tp    = tp;
910
911   ainfo->prev = ginfo->allocs;
912   ginfo->allocs = ainfo;
913 }
914
915
916 /* ====================
917   CallEd stuff
918   ==================== */
919 /**
920    Append the given callEd to the given callEd info.
921 */
922 static callEd_info_t *append_callEd_info (callEd_info_t *ced, ir_graph *callEd)
923 {
924   callEd_info_t *nced = (callEd_info_t*) xmalloc (sizeof (sizeof (callEd_info_t)));
925
926   nced->callEd = callEd;
927   nced->prev = ced;
928
929   return (nced);
930 }
931
932 /**
933    Append all callEd methods of the given (call) node to the given graph_info.
934 */
935 static void append_calls (graph_info_t *info, ir_node *call, lset_t *callEds)
936 {
937   int n_callEds = 0;
938
939   call_info_t *cinfo = (call_info_t*) xmalloc (sizeof (call_info_t));
940
941   /* setup */
942   cinfo->call = call;
943   cinfo->prev = info->calls;
944   info->calls = cinfo;
945   cinfo->callEds = NULL;
946
947   /* enter */
948   ir_graph *callEd = lset_first (callEds);
949   while (callEd) {
950     cinfo->callEds = append_callEd_info (cinfo->callEds, callEd);
951
952     callEd = lset_next (callEds);
953   }
954 }
955
956 /**
957    Append the (single) callEd to the given (call) node of the given graph_info.
958 */
959 static void append_call (graph_info_t *info, ir_node *call, ir_graph *callEd)
960 {
961   call_info_t *cinfo = (call_info_t*) xmalloc (sizeof (call_info_t));
962
963   cinfo->call = call;
964   cinfo->prev = info->calls;
965   info->calls = cinfo;
966
967   cinfo->callEds = append_callEd_info (cinfo->callEds, callEd);
968 }
969
970 /**
971    Given a method, find the firm graph that implements that method.
972    Return NULL for abstract and native methods.
973 */
974 static ir_graph *_get_implementing_graph (entity *method)
975 {
976   ir_graph *graph = NULL;
977
978   /* What's up with the fenced out stuff in rta? */
979   if (peculiarity_existent == get_entity_peculiarity (method)) {
980     if (visibility_external_allocated == get_entity_visibility (method)) {
981       /* Todo: native implementation */
982
983       return (NULL);
984     } else {
985       graph = get_entity_irg (get_SymConst_entity (get_atomic_ent_value (method)));
986       assert (graph && "no graph");
987
988       return (graph);
989     }
990   } else if (0 && (peculiarity_description == get_entity_peculiarity (method))) {
991     /* abstract --- can't find an implementation */
992     graph = get_entity_irg (method);
993     assert (!graph && "graph in abstract method");
994
995     return (NULL);
996   } else if ((peculiarity_description == get_entity_peculiarity (method)) ||
997              (peculiarity_inherited == get_entity_peculiarity (method))) {
998     /* search UPWARDS */
999     int i;
1000     int n_over = get_entity_n_overwrites (method);
1001
1002     assert (!graph);
1003
1004     for (i = 0; (NULL == graph) && (i < n_over); i ++) {
1005       entity *over = get_entity_overwrites (method, i);
1006
1007       graph = _get_implementing_graph (over);
1008     }
1009   } else {
1010     assert (0 && "invalid peculiarity");
1011   }
1012
1013
1014   return (graph);
1015 }
1016
1017 /**
1018    Collect all graphs of 'method' in the given set.
1019 */
1020 static void _collect_implementing_graphs (entity *method, lset_t *set)
1021 {
1022   /* search DOWN-wards in clazz hierarchy */
1023   int i;
1024   int n_over = get_entity_n_overwrittenby (method);
1025   ir_graph *graph = get_entity_irg (method);
1026
1027   if (NULL == graph) {
1028     graph = _get_implementing_graph (method);
1029   }
1030
1031   if (graph) {
1032     lset_insert (set, graph);
1033   }
1034
1035   for (i = 0; i < n_over; i ++) {
1036     entity *over = get_entity_overwrittenby (method, i);
1037
1038     _collect_implementing_graphs (over, set);
1039   }
1040 }
1041
1042
1043 /**
1044    Collect all graphs that could possibly be executed when 'method' is called.
1045 */
1046 static lset_t *get_implementing_graphs (entity *method, ir_node *select)
1047 {
1048   lset_t *set = lset_create ();
1049   {
1050     ir_graph *impl = _get_implementing_graph (method);
1051
1052     if (NULL != impl) {
1053       lset_insert (set, impl);
1054     } else {
1055       /* actually, abstract OR native */
1056     }
1057   }
1058
1059   _collect_implementing_graphs (method, set);
1060
1061   if (lset_empty (set)) {
1062     /* then it's a method which is only implemented natively, and we
1063        don' bother to analyse anything */
1064     return (set);
1065   }
1066
1067   void *tmp = lset_first (set);
1068   int n_graphs = lset_n_entries (set);
1069
1070   /* typalise select_in */
1071   if (do_typalise) {
1072     ir_node *select_in = get_Sel_ptr (select);
1073     typalise_t *ta = typalise (select_in);
1074     assert (ta && "typalise failed (go figure)");
1075
1076     const char *res = ta_name (ta);
1077
1078     /* fprintf (stdout, "typalyse res = %s\n", res); */
1079
1080     if (1 != n_graphs) {
1081       set = filter_for_ta (set, ta);
1082
1083       int n_filtered_graphs = lset_n_entries (set);
1084
1085       /*
1086       fprintf (stdout, "%s: %02d %02d\n",
1087                __FUNCTION__,
1088                n_graphs,
1089                n_filtered_graphs,
1090                n_graphs - n_filtered_graphs);
1091       */
1092       n_graphs = n_filtered_graphs;
1093     }
1094   }
1095
1096   if (n_graphs > _max_callEds) {
1097     _max_callEds = n_graphs;
1098     _max_callEds_callR = method;
1099   }
1100
1101
1102   if (visibility_external_allocated != get_entity_visibility (method)) {
1103     if (0 == n_graphs) {
1104       /* fprintf (stdout, "no graphs for method %s\n", get_entity_name (method)); */
1105       assert (n_graphs && "no graphs for method");
1106     }
1107   }
1108
1109   return (set);
1110 }
1111
1112 /**
1113    Action for the graph.
1114 */
1115 static void ecg_calls_act (ir_node *node, void *env)
1116 {
1117   opcode op = get_irn_opcode (node);
1118   graph_info_t *graph_info = (graph_info_t*) env;
1119
1120   if (iro_Call == op) {         /* CALL */
1121     entity *ent = NULL;
1122     ir_node *ptr = get_Call_ptr (node);
1123
1124     /* CALL SEL */
1125     if (iro_Sel == get_irn_opcode (ptr)) {
1126       ent = get_Sel_entity (ptr);
1127       lset_t *graphs = get_implementing_graphs (ent, ptr);
1128
1129       append_calls (graph_info, node, graphs);
1130     } else if (iro_SymConst == get_irn_opcode (ptr)) {
1131       if (get_SymConst_kind(ptr) == symconst_addr_ent) {
1132         ent = get_SymConst_entity (ptr);
1133         ir_graph *graph = get_entity_irg (ent);
1134
1135         if (graph) {
1136           append_call (graph_info, node, graph);
1137         } else {
1138           /* it's an externally allocated thingy */
1139         }
1140       } else if (get_SymConst_kind(ptr) == symconst_addr_name) {
1141         /* If this SymConst refers to a method the method is external_visible
1142            and therefore must be considered live anyways. */
1143         if (get_SymConst_name(ptr) != new_id_from_str("iro_Catch")) {
1144           assert (ent && "couldn't determine entity of call to symConst");
1145         }
1146       } else {
1147         /* other symconst. */
1148         assert (0 && "This SymConst can not be an address for a method call.");
1149       }
1150
1151       /* STRANGE, no less ... */
1152     } else {
1153       DDMN(ptr);
1154       assert(0 && "Unexpected address expression");
1155     }
1156   } else if (iro_Alloc == op) {
1157     type *tp = get_Alloc_type (node);
1158     const char *name = get_type_name (tp);
1159
1160     append_alloc (graph_info, node, tp);
1161
1162     fprintf (stdout, "NEW \"%s\"\n", name);
1163   }
1164 }
1165
1166 /**
1167    Collect called graphs for the given graph.
1168 */
1169 static void ecg_fill_graph_calls (ir_graph *graph)
1170 {
1171   graph_info_t *graph_info = (graph_info_t*) xmalloc (sizeof (graph_info_t));
1172
1173   graph_info->graph = graph;
1174   graph_info->calls = NULL;
1175   graph_info->ecg_seen = 0;
1176
1177   entity *method  = get_irg_entity (graph);
1178   type   *clazz   = get_entity_owner (method);
1179
1180   irg_walk_graph (graph, ecg_calls_act, NULL, graph_info);
1181
1182   pmap_insert (graph_infos, graph, graph_info);
1183 }
1184
1185 /**
1186    For each graph, collect called graphs, and enter them into calls.
1187 */
1188 static void ecg_fill_calls ()
1189 {
1190   int i;
1191
1192   for (i = 0; i < get_irp_n_irgs (); i++) {
1193     ir_graph *graph = get_irp_irg (i);
1194
1195     ecg_fill_graph_calls (graph);
1196   }
1197 }
1198
1199 /* ====================
1200   ECG stuff
1201   ==================== */
1202
1203 /*
1204   get the call infos for the given graph
1205 */
1206 graph_info_t *ecg_get_info (ir_graph *graph)
1207 {
1208   graph_info_t *ginfo = (graph_info_t*) pmap_get (graph_infos, graph);
1209
1210   assert (ginfo && "no info for graph");
1211
1212   return (ginfo);
1213 }
1214
1215
1216
1217 /**
1218    Dump the given graph and it's calls and it's calls callEds to the given file.
1219 */
1220 static int ecg_ecg_graph (FILE *dot, ir_graph *graph)
1221 {
1222   const char *name = get_irg_entity (graph) ?
1223     get_entity_name (get_irg_entity (graph)) : "noEntity";
1224   const char *color =
1225     (get_entity_stickyness
1226      (get_irg_entity (graph)) == stickyness_sticky) ?
1227     "red" : "lightyellow";
1228
1229   graph_info_t *ginfo = (graph_info_t*) pmap_get (graph_infos, graph);
1230
1231   if (0 != ginfo->ecg_seen) {
1232     fprintf (dot, "\t/* recursive call to \"%s\" (%d) */\n", name, ginfo->ecg_seen);
1233 # if 0
1234     fprintf (dot, "\t/* recursive call to \"%s\" (0x%08x) */\n", name, graph);
1235 # endif /* 0 */
1236     return (ginfo->ecg_seen);
1237   }
1238
1239   assert (0L <= _graphs);
1240
1241   const int graph_no = _graphs ++;
1242   ginfo->ecg_seen = graph_no;
1243
1244   fprintf (dot, "\t/* Graph of \"%s.%s\" */\n",
1245            get_type_name (get_entity_owner (get_irg_entity (graph))),
1246            name);
1247   fprintf (dot, "\tgraph_%i [label=\"%s\\l%s\", color=\"%s\"];\n",
1248            graph_no,
1249            get_type_name (get_entity_owner (get_irg_entity (graph))),
1250            name,
1251            color);
1252   fprintf (dot, "\n");
1253
1254   if (visibility_external_allocated ==
1255       get_entity_visibility (get_irg_entity (graph))) {
1256     fprintf (dot, "\t/* graph \"%s\" is external */\n", name);
1257
1258     return (graph_no);
1259   }
1260
1261   call_info_t *cinfo = ginfo->calls;
1262   while (NULL != cinfo) {
1263     ir_node *call = cinfo->call;
1264     callEd_info_t *ced = cinfo->callEds;
1265     const int call_no = _calls ++;
1266
1267     fprintf (dot, "\t/* Call 0x%08x */\n", call);
1268     fprintf (dot, "\tcall_%i [label=\"call\\l0x%08x\"];\n",
1269              call_no, call);
1270     fprintf (dot, "\tgraph_%i -> call_%i [color=\"black\"];\n", graph_no, call_no);
1271
1272     while (NULL != ced) {
1273       ir_graph *callEd_graph = ced->callEd;
1274       const int callEd_no = ecg_ecg_graph (dot, callEd_graph);
1275       const char *callEd_name = get_irg_entity (callEd_graph) ?
1276         get_entity_name (get_irg_entity (callEd_graph)) : "noEntity";
1277       const char *direction = (callEd_no <= graph_no) ? "forward" : "forward";
1278       const char *callEd_color     = (callEd_no <= graph_no) ? "red" : "black";
1279
1280       fprintf (dot, "\t/* Call from graph \"%s\" to graph \"%s\" */\n",
1281                name,
1282                callEd_name);
1283       /* Check for recursive calls */
1284       /* if (callEd_no > graph_no) */ { /* do recursive calls (for now) */
1285         fprintf (dot, "\tcall_%i -> graph_%i [color=\"%s\", dir=\"%s\"];\n",
1286                  call_no, callEd_no, callEd_color, direction);
1287       }
1288
1289       ced = ced->prev;
1290       /* ced = NULL; */
1291     } /* done all calEds(call) */
1292
1293     cinfo = cinfo->prev;
1294   } /* done all calls(graph) */
1295
1296   /* now the allocs */
1297   alloc_info_t *ainfo = ginfo->allocs;
1298   if (ainfo) {
1299     fprintf (dot, "\t/* now the allocs */\n");
1300   } else {
1301     fprintf (dot, "\t/* no allocs */\n");
1302   }
1303
1304   while (NULL != ainfo) {
1305     ir_node *alloc = ainfo->alloc;
1306     const char *name = get_type_name (ainfo->tp);
1307     const char *color = "red1";
1308
1309     /* if (0 == ginfo->allocs_seen) { */
1310     _allocs ++;
1311       fprintf (dot, "\talloc_0x%08x_%i [label=\"%s\", color=\"%s\"]\n",
1312                alloc, graph_no, name, color);
1313     /* } */
1314
1315     fprintf (dot, "\tgraph_%i -> alloc_0x%08x_%i\n", graph_no, alloc, graph_no);
1316
1317     ainfo = ainfo->prev;
1318   }
1319
1320   if (0 == ginfo->allocs_seen) {
1321     ginfo->allocs_seen = 1;
1322   }
1323
1324   fprintf (dot, "\t/* done with graph of \"%s\" */\n\n", name);
1325
1326   fflush (dot);
1327   ginfo->ecg_seen = 0;
1328
1329   return (graph_no);
1330 }
1331
1332 /**
1333    Count how many nodes the ECG will have
1334 */
1335 static char spaces [BUF_SIZE];
1336
1337 static void ecg_ecg_count (ir_graph *graph)
1338 {
1339   graph_info_t *ginfo = (graph_info_t*) pmap_get (graph_infos, graph);
1340
1341   if (0 != ginfo->ecg_seen) {
1342     return;
1343   }
1344
1345   _depth ++;
1346   if (_depth > _max_depth) {
1347     _max_depth = _depth;
1348
1349     /*
1350       fprintf (stdout, "_max_depth = %i\n", _max_depth);
1351       fprintf (stdout, "\tn_graphs: %i\n", _graphs);
1352     */
1353   }
1354
1355   assert (0L <= _graphs);
1356
1357   /*
1358     if (0 == (_graphs % 1000000)) {
1359     fprintf (stdout, "\tn_graphs: %i\n", _graphs);
1360     fprintf (stdout, "_depth = %i\n", _depth);
1361     }
1362   */
1363
1364   const int graph_no = _graphs ++;
1365   ginfo->ecg_seen = graph_no;
1366
1367   fprintf (stdout, "%sMethod \"%s.%s\"\n",
1368            spaces + BUF_SIZE - _depth,
1369            get_type_name (get_entity_owner (get_irg_entity (graph))),
1370            get_entity_name (get_irg_entity (graph)));
1371
1372   call_info_t *cinfo = ginfo->calls;
1373   while (NULL != cinfo) {
1374
1375     callEd_info_t *ced = cinfo->callEds;
1376
1377     fprintf (stdout, "%sCall \"0x%08x\"\n",
1378              spaces + BUF_SIZE - _depth,
1379              cinfo->call);
1380
1381     while (NULL != ced) {
1382       ir_graph *callEd_graph = ced->callEd;
1383
1384       fprintf (stdout, "%sCall Target \"%s.%s\"\n",
1385                spaces + BUF_SIZE - _depth,
1386                get_type_name (get_entity_owner (get_irg_entity (callEd_graph))),
1387                get_entity_name (get_irg_entity (callEd_graph)));
1388
1389       ecg_ecg_count (callEd_graph);
1390
1391       ced = ced->prev;
1392     } /* done all calEds(call) */
1393     cinfo = cinfo->prev;
1394   } /* done all calls(graph) */
1395
1396   ginfo->ecg_seen = 0;
1397   _depth --;
1398 }
1399
1400 /* ====================
1401   Public Interface
1402   ==================== */
1403
1404 /**
1405    Initialise our data structures.
1406 */
1407 void ecg_init (int typalise)
1408 {
1409   do_typalise = typalise;
1410
1411   graph_infos = pmap_create ();
1412
1413   ecg_fill_calls ();
1414 }
1415
1416 /**
1417    Clean up our mess.
1418 */
1419 void ecg_cleanup ()
1420 {
1421   int i;
1422
1423   for (i = 0; i < get_irp_n_irgs (); i++) {
1424     ir_graph *graph = get_irp_irg (i);
1425
1426     graph_info_t *info = pmap_get (graph_infos, graph);
1427     call_info_t *cinfo = info->calls;
1428
1429     while (NULL != cinfo) {
1430       free (cinfo->callEds);
1431       cinfo->call = NULL;
1432
1433       callEd_info_t *ced = cinfo->callEds;
1434
1435       while (NULL != ced) {
1436         callEd_info_t *nced = ced->prev;
1437         free (ced);
1438         ced->prev = NULL;
1439         ced->callEd = NULL;
1440         ced = nced;
1441       }
1442
1443       /* Todo: delete callEds */
1444       cinfo->callEds = NULL;
1445
1446       free (cinfo);
1447       cinfo = cinfo->prev;
1448     }
1449
1450     free (info);
1451     pmap_insert (graph_infos, graph, NULL);
1452   }
1453
1454
1455   pmap_destroy (graph_infos);
1456
1457   /* BEGIN mild paranoia mode */
1458   graph_infos = NULL;
1459   /* END mild paranoia mode */
1460 }
1461
1462 /**
1463    Show what we have found.
1464 */
1465 void ecg_report ()
1466 {
1467   int i;
1468
1469   FILE *dot = fopen ("calls.dot", "w");
1470
1471   fprintf (dot, "digraph \"calls\" {\n");
1472   fprintf (dot, "\tnode [shape = \"record\", style = \"filled\"];\n");
1473   fprintf (dot, "\tedge [color = \"black\"];\n");
1474   fprintf (dot, "\n");
1475   fprintf (dot, "\tsize = \"11, 7\";\n");
1476   fprintf (dot, "\trotate = \"90\";\n");
1477   fprintf (dot, "\tratio = \"fill\";\n");
1478   fprintf (dot, "\trankdir = \"LR\";\n");
1479   fprintf (dot, "\n");
1480
1481   for (i = 0; i < get_irp_n_irgs (); i++) {
1482     ir_graph *graph = get_irp_irg (i);
1483     graph_info_t *info = (graph_info_t*) pmap_get (graph_infos, graph);
1484
1485     const char *name = get_irg_entity (graph) ?
1486       get_entity_name (get_irg_entity (graph)) : "noEntity";
1487
1488     const char *oname = get_type_name
1489       (get_entity_owner (get_irg_entity (graph)));
1490
1491     const char *color =
1492       (get_entity_stickyness
1493        (get_irg_entity (graph)) == stickyness_sticky) ?
1494       "red3" : "lightyellow";
1495
1496     fprintf (dot, "\t/* graph_0x%08x (\"%s\") */\n", graph, name);
1497     fprintf (dot,
1498              "\tgraph_0x%08x [label=\"%s\\l%s\", color=\"%s\"];\n",
1499              graph, oname, name, color);
1500     fprintf (dot, "\n");
1501
1502     call_info_t *cinfo = info->calls;
1503     if (cinfo) {
1504       fprintf (dot, "\t/* now the calls */\n");
1505     } else {
1506       fprintf (dot, "\t/* no calls */\n");
1507     }
1508
1509     while (NULL != cinfo) {
1510       ir_node *call = cinfo->call;
1511       int i;
1512
1513       fprintf (dot, "\t/* call_0x%08x */\n", call);
1514       fprintf (dot, "\tcall_0x%08x [label=\"call\\l0x%08x\"];\n", call, call);
1515       fprintf (dot, "\tgraph_0x%08x -> call_0x%08x;\n", graph, call);
1516
1517       callEd_info_t *ced = cinfo->callEds;
1518       while (NULL != ced) {
1519         fprintf (dot, "\tcall_0x%08x -> graph_0x%08x;\n", call, ced->callEd);
1520         ced = ced->prev;
1521       }
1522       fprintf (dot, "\n");
1523
1524       cinfo = cinfo->prev;
1525     }
1526     fprintf (dot, "\n");
1527
1528     alloc_info_t *ainfo = info->allocs;
1529     if (ainfo) {
1530       fprintf (dot, "\t/* now the allocs */\n");
1531     } else {
1532       fprintf (dot, "\t/* no allocs */\n");
1533     }
1534
1535
1536     while (NULL != ainfo) {
1537       ir_node *alloc = ainfo->alloc;
1538       const char *name = get_type_name (ainfo->tp);
1539       const char *color = "red1";
1540
1541       fprintf (dot, "\talloc_0x%08x [label=\"%s\", color=\"%s\"]\n",
1542                alloc, name, color);
1543       fprintf (dot, "\tgraph_0x%08x -> alloc_0x%08x\n", graph, alloc);
1544
1545       ainfo = ainfo->prev;
1546     }
1547   }
1548   fprintf (dot, "}\n");
1549
1550   /*
1551     fprintf (stdout, " max_callEds: %i\n", _max_callEds);
1552     fprintf (stdout, " max_callEds_callR: \"%s\"\n",
1553     get_entity_name (_max_callEds_callR));
1554   */
1555   fclose (dot);
1556
1557   ecg_ecg ();
1558 }
1559
1560 /**
1561    Experimental:  Print the ecg
1562 */
1563 void ecg_ecg ()
1564 {
1565   _graphs = 0;
1566   _calls  = 0;
1567
1568   ir_graph *main_graph = get_irp_main_irg ();
1569
1570   /*
1571   memset (spaces, '.', BUF_SIZE);
1572   spaces [BUF_SIZE-1] = '\0';
1573
1574   ecg_ecg_count (main_graph);
1575   fprintf (stdout, "n_graphs: %i\n", _graphs);
1576   fprintf (stdout, "max_depth = %i\n", _max_depth);
1577   */
1578
1579   /* return; */
1580
1581   _graphs = 0;
1582   _calls  = 0;
1583
1584   FILE *dot = fopen ("ecg.dot", "w");
1585
1586   fprintf (dot, "digraph \"ecg\" {\n");
1587   fprintf (dot, "\tnode [shape = \"record\", style = \"filled\"];\n");
1588   fprintf (dot, "\tedge [color = \"black\"];\n");
1589   fprintf (dot, "\n");
1590   fprintf (dot, "\tsize = \"11, 7\";\n");
1591   fprintf (dot, "\trotate = \"90\";\n");
1592   fprintf (dot, "\tratio = \"fill\";\n");
1593   fprintf (dot, "\trankdir = \"LR\";\n");
1594   fprintf (dot, "\n");
1595
1596   /* ir_graph *main_graph = get_irp_main_irg (); */
1597   ecg_ecg_graph (dot, main_graph);
1598
1599   fprintf (dot, "\t/* Grand Total: */\n");
1600   fprintf (dot, "\t/* calls:  %i */\n", _calls);
1601   fprintf (dot, "\t/* graphs: %i */\n", _graphs);
1602   fprintf (dot, "\t/* allocs: %i */\n", _allocs);
1603   fprintf (dot, "\t/* (sales tax not included) */\n");
1604
1605   fprintf (dot, "}\n");
1606
1607   fclose (dot);
1608 }
1609
1610 \f
1611
1612 /*
1613   $Log$
1614   Revision 1.4  2004/10/12 11:02:01  liekweg
1615   wtf?
1616
1617 */