ac926db908865d930f609ca76dab2c8984f842c8
[libfirm] / ir / ana2 / 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:      $Id$
11  * Copyright:   (c) 1999-2004 Universität Karlsruhe
12  * Licence:     This file is protected by the 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 # ifndef TRUE
33 #  define TRUE 1
34 #  define FALSE 0
35 # endif /* not defined TRUE */
36
37 # define BUF_SIZE 1024
38
39 # include "ecg.h"
40 # include "typalise.h"
41 # include "lset.h"
42
43 /*
44   le flag
45 */
46 /* static int verbose     = 0; */
47 static int do_typalise = 0;
48
49 /*
50   globals
51 */
52
53 /* Ids for the ctxs */
54 static int ctx_id = 0;
55 ctx_info_t *main_ctx = NULL;
56
57 /* mapping from method graphs (callR) to method graphs (lset_ts of callEds) */
58 /* static pmap *calls; */
59 static pmap *graph_infos;
60
61 /* linked list of all graph_infos: */
62 static graph_info_t *graph_infos_list = NULL;
63
64 /* Counters for ecg_ecg and friends */
65 static long _graphs = 0;
66 static long _calls  = 0;
67 static long _allocs = 0;
68
69 static int _depth = 0;
70 static int _max_depth = 0;
71
72 static int _max_callEds = 0;
73 static entity* _max_callEds_callR = NULL;
74
75 /* Protos */
76 void set_main_ctx (ctx_info_t*);
77
78 /* ====================
79    Alloc stuff
80    ==================== */
81 static void append_alloc (graph_info_t *ginfo, ir_node *alloc, type *tp)
82 {
83   alloc_info_t *ainfo = (alloc_info_t*) xmalloc (sizeof (alloc_info_t));
84
85   ainfo->graph = ginfo->graph;
86   ainfo->alloc = alloc;
87   ainfo->tp    = tp;
88
89   ainfo->prev = ginfo->allocs;
90   ginfo->allocs = ainfo;
91 }
92
93
94 /* ====================
95    CallEd stuff
96    ==================== */
97 /**
98    Append the given callEd to the given callEd info.
99 */
100 static callEd_info_t *append_callEd_info (callEd_info_t *ced, ir_graph *callEd)
101 {
102   callEd_info_t *nced = (callEd_info_t*) xmalloc (sizeof (sizeof (callEd_info_t)));
103
104   nced->callEd = callEd;
105   nced->prev = ced;
106
107   return (nced);
108 }
109
110 /**
111    Append all callEd methods of the given (call) node to the given graph_info.
112 */
113 static void append_calls (graph_info_t *info, ir_node *call, lset_t *callEds)
114 {
115   call_info_t *cinfo = (call_info_t*) xmalloc (sizeof (call_info_t));
116
117   /* setup */
118   cinfo->call = call;
119   cinfo->prev = info->calls;
120   info->calls = cinfo;
121   cinfo->callEds = NULL;
122
123   /* enter */
124   ir_graph *callEd = lset_first (callEds);
125   while (callEd) {
126     cinfo->callEds = append_callEd_info (cinfo->callEds, callEd);
127
128     callEd = lset_next (callEds);
129   }
130 }
131
132 /**
133    Append the (single) callEd to the given (call) node of the given graph_info.
134 */
135 static void append_call (graph_info_t *info, ir_node *call, ir_graph *callEd)
136 {
137   call_info_t *cinfo = (call_info_t*) xmalloc (sizeof (call_info_t));
138
139   cinfo->call = call;
140   cinfo->prev = info->calls;
141   info->calls = cinfo;
142
143   cinfo->callEds = append_callEd_info (cinfo->callEds, callEd);
144 }
145
146 /**
147    Given a method, find the firm graph that implements that method.
148    Return NULL for abstract and native methods.
149 */
150 static ir_graph *_get_implementing_graph (entity *method)
151 {
152   ir_graph *graph = NULL;
153
154   /* What's up with the fenced out stuff in rta? */
155   if (peculiarity_existent == get_entity_peculiarity (method)) {
156     if (visibility_external_allocated == get_entity_visibility (method)) {
157       /* Todo: native implementation */
158
159       return (NULL);
160     } else {
161       graph = get_entity_irg (get_SymConst_entity (get_atomic_ent_value (method)));
162       assert (graph && "no graph");
163
164       return (graph);
165     }
166   } else if (0 && (peculiarity_description == get_entity_peculiarity (method))) {
167     /* abstract --- can't find an implementation */
168     graph = get_entity_irg (method);
169     assert (!graph && "graph in abstract method");
170
171     return (NULL);
172   } else if ((peculiarity_description == get_entity_peculiarity (method)) ||
173              (peculiarity_inherited == get_entity_peculiarity (method))) {
174     /* search UPWARDS */
175     int i;
176     int n_over = get_entity_n_overwrites (method);
177
178     assert (!graph);
179
180     for (i = 0; (NULL == graph) && (i < n_over); i ++) {
181       entity *over = get_entity_overwrites (method, i);
182
183       graph = _get_implementing_graph (over);
184     }
185   } else {
186     assert (0 && "invalid peculiarity");
187   }
188
189
190   return (graph);
191 }
192
193 /**
194    Collect all graphs of 'method' in the given set.
195 */
196 static void _collect_implementing_graphs (entity *method, lset_t *set)
197 {
198   /* search DOWN-wards in clazz hierarchy */
199   int i;
200   int n_over = get_entity_n_overwrittenby (method);
201   ir_graph *graph = get_entity_irg (method);
202
203   if (NULL == graph) {
204     graph = _get_implementing_graph (method);
205   }
206
207   if (graph) {
208     lset_insert (set, graph);
209   }
210
211   for (i = 0; i < n_over; i ++) {
212     entity *over = get_entity_overwrittenby (method, i);
213
214     _collect_implementing_graphs (over, set);
215   }
216 }
217
218
219 /**
220    Collect all graphs that could possibly be executed when 'method' is called.
221 */
222 static lset_t *get_implementing_graphs (entity *method, ir_node *select)
223 {
224   lset_t *set = lset_create ();
225   {
226     ir_graph *impl = _get_implementing_graph (method);
227
228     if (NULL != impl) {
229       lset_insert (set, impl);
230     } else {
231       /* actually, abstract OR native */
232     }
233   }
234
235   _collect_implementing_graphs (method, set);
236
237   if (lset_empty (set)) {
238     /* then it's a method which is only implemented natively, and we
239        don' bother to analyse anything */
240     return (set);
241   }
242
243   /* void *tmp = lset_first (set); */
244   int n_graphs = lset_n_entries (set);
245
246   /* typalise select_in */
247   if (do_typalise) {
248     ir_node *select_in = get_Sel_ptr (select);
249     typalise_t *ta = typalise (select_in);
250     assert (ta && "typalise failed (go figure)");
251
252     /* const char *res = ta_name (ta); */
253
254     /* fprintf (stdout, "typalyse res = %s\n", res); */
255
256     if (1 != n_graphs) {
257       set = filter_for_ta (set, ta);
258
259       int n_filtered_graphs = lset_n_entries (set);
260
261       /*
262         fprintf (stdout, "%s: %02d %02d\n",
263         __FUNCTION__,
264         n_graphs,
265         n_filtered_graphs,
266         n_graphs - n_filtered_graphs);
267       */
268       n_graphs = n_filtered_graphs;
269     }
270   }
271
272   if (n_graphs > _max_callEds) {
273     _max_callEds = n_graphs;
274     _max_callEds_callR = method;
275   }
276
277
278   if (visibility_external_allocated != get_entity_visibility (method)) {
279     if (0 == n_graphs) {
280       /* fprintf (stdout, "no graphs for method %s\n", get_entity_name (method)); */
281       assert (n_graphs && "no graphs for method");
282     }
283   }
284
285   return (set);
286 }
287
288 /**
289    Action for the graph.
290 */
291 static void ecg_calls_act (ir_node *node, void *env)
292 {
293   opcode op = get_irn_opcode (node);
294   graph_info_t *graph_info = (graph_info_t*) env;
295
296   if (iro_Call == op) {         /* CALL */
297     entity *ent = NULL;
298     ir_node *ptr = get_Call_ptr (node);
299
300     /* CALL SEL */
301     if (iro_Sel == get_irn_opcode (ptr)) {
302       ent = get_Sel_entity (ptr);
303       lset_t *graphs = get_implementing_graphs (ent, ptr);
304
305       append_calls (graph_info, node, graphs);
306     } else if (iro_SymConst == get_irn_opcode (ptr)) {
307       if (get_SymConst_kind (ptr) == symconst_addr_ent) {
308         ent = get_SymConst_entity (ptr);
309         ir_graph *graph = get_entity_irg (ent);
310
311         if (graph) {
312           append_call (graph_info, node, graph);
313         } else {
314           /* it's an externally allocated thingy */
315         }
316       } else if (get_SymConst_kind (ptr) == symconst_addr_name) {
317         /* If this SymConst refers to a method the method is external_visible
318            and therefore must be considered live anyways. */
319         if (get_SymConst_name (ptr) != new_id_from_str ("iro_Catch")) {
320           assert (ent && "couldn't determine entity of call to symConst");
321         }
322       } else {
323         /* other symconst. */
324         assert (0 && "This SymConst can not be an address for a method call.");
325       }
326
327       /* STRANGE, no less ... */
328     } else {
329       DDMN (ptr);
330       assert (0 && "Unexpected address expression");
331     }
332   } else if (iro_Alloc == op) {
333     type *tp = get_Alloc_type (node);
334     /* const char *name = get_type_name (tp); */
335
336     append_alloc (graph_info, node, tp);
337
338     /* fprintf (stdout, "NEW \"%s\"\n", name); */
339   }
340 }
341
342 /**
343    Collect called graphs for the given graph.
344 */
345 static void ecg_fill_graph_calls (ir_graph *graph)
346 {
347   graph_info_t *graph_info = (graph_info_t*) xmalloc (sizeof (graph_info_t));
348
349   graph_info->graph = graph;
350   graph_info->calls = NULL;
351   graph_info->ecg_seen = 0;
352   graph_info->ctxs = NULL;
353   graph_info->n_ctxs = 0;
354
355   /* link up into global list */
356   graph_info->prev = graph_infos_list;
357   graph_infos_list = graph_info;
358
359   irg_walk_graph (graph, ecg_calls_act, NULL, graph_info);
360
361   pmap_insert (graph_infos, graph, graph_info);
362 }
363
364 /**
365    For each graph, collect called graphs, and enter them into calls.
366 */
367 static void ecg_fill_calls (void)
368 {
369   int i;
370
371   for (i = 0; i < get_irp_n_irgs (); i++) {
372     ir_graph *graph = get_irp_irg (i);
373
374     ecg_fill_graph_calls (graph);
375   }
376 }
377
378 /**
379    Allocate a new ctx for the given graph and the given enclosing ctx.
380 */
381 static ctx_info_t *new_ctx (ir_graph *graph, ir_node *call, ctx_info_t *enc)
382 {
383   ctx_info_t *res = xmalloc (sizeof (ctx_info_t));
384
385   res->graph = graph;
386   res->call = call;
387   res->enc = enc;
388   res->id = ctx_id ++;
389
390   return (res);
391 }
392
393
394 /**
395    Fill in the ctxs parts of the graph_infos
396 */
397 static void ecg_fill_ctxs_count (ir_graph *graph)
398 {
399   graph_info_t *ginfo = ecg_get_info (graph);
400
401   /* count how many ctxs we have per graph */
402   if (0 == ginfo->ecg_seen) {
403
404     ginfo->ecg_seen = 1;
405     call_info_t *cinfo = ginfo->calls;
406
407     while (NULL != cinfo) {
408       callEd_info_t *ced = cinfo->callEds;
409
410       while (NULL != ced) {
411         ir_graph *callEd_graph = ced->callEd;
412
413         /* first step: we have a new ctx */
414         graph_info_t *callEd_info = ecg_get_info (callEd_graph);
415         callEd_info->n_ctxs ++;
416
417         /* Calling graph -> callEd_graph */
418         ecg_fill_ctxs_count (callEd_graph);
419
420         ced = ced->prev;
421       } /* end forall callEds (call) */
422
423       cinfo = cinfo->prev;
424     } /* end forall (calls(graph)) */
425
426     ginfo->ecg_seen = 0;
427   }
428 }
429
430 static void ecg_fill_ctxs_alloc (void)
431 {
432   /* allocate the memory needed for the ctxts: */
433   graph_info_t *ginfo = graph_infos_list;
434
435   while (NULL != ginfo) {
436     ginfo->ctxs = (ctx_info_t **) xmalloc (ginfo->n_ctxs * sizeof (ctx_info_t*));
437
438     /*
439       fprintf (stdout, "graph of \"%s\": n_ctxs = %i\n",
440       get_entity_name (get_irg_entity (ginfo->graph)), ginfo->n_ctxs);
441     */
442     ginfo->n_ctxs = 0;
443
444     ginfo = ginfo->prev;
445   }
446 }
447
448 /**
449    Fill in the ctxs parts of the graph_infos
450 */
451 static void ecg_fill_ctxs_write (ir_graph *graph, ctx_info_t *enc_ctx)
452 {
453   graph_info_t *ginfo = ecg_get_info (graph);
454
455   /* enter a new ctx for all callEds along the call edges of this graph */
456   if (0 == ginfo->ecg_seen) {
457     ginfo->ecg_seen = 1;
458     call_info_t *cinfo = ginfo->calls;
459
460     while (NULL != cinfo) {
461       callEd_info_t *ced = cinfo->callEds;
462
463       while (NULL != ced) {
464         ctx_info_t *ctx = new_ctx (graph, cinfo->call, enc_ctx);
465
466         ir_graph *callEd_graph = ced->callEd;
467
468         /* write the ctx of this call into the callEd graph */
469         graph_info_t *callEd_info = ecg_get_info (callEd_graph);
470
471         callEd_info->ctxs [callEd_info->n_ctxs] = ctx;
472         callEd_info->n_ctxs ++;
473
474         /* Calling graph -> callEd_graph */
475         ecg_fill_ctxs_write (callEd_graph, ctx);
476
477         ced = ced->prev;
478       } /* end forall callEds (call) */
479
480       cinfo = cinfo->prev;
481     } /* end forall (calls(graph)) */
482
483     ginfo->ecg_seen = 0;
484   }
485 }
486
487 /**
488    Fill in the ctxs parts of the graph_infos
489 */
490 static void ecg_fill_ctxs (void)
491 {
492   ecg_fill_ctxs_count (get_irp_main_irg ());
493   ecg_fill_ctxs_alloc ();
494
495   ctx_info_t *main_ctx = new_ctx (get_irp_main_irg (), NULL, NULL);
496   ir_graph *main_irg = get_irp_main_irg ();
497
498   set_main_ctx (main_ctx);
499
500   /* Grrr, have to add this ctx manually to main.ginfo ... */
501   graph_info_t *ginfo = ecg_get_info (main_irg);
502   ginfo->n_ctxs = 1;
503   ginfo->ctxs = (ctx_info_t **) xmalloc (1 * sizeof (ctx_info_t*));
504   ginfo->ctxs [0] = main_ctx;
505
506   ecg_fill_ctxs_write (main_irg, main_ctx);
507 }
508
509 /* ====================
510    CTX stuff
511    ==================== */
512 /*
513   Nicely print a ctx_info_t to the given output stream
514 */
515 void ecg_print_ctx (ctx_info_t *ctx, FILE *stream)
516 {
517   entity *ent = get_irg_ent (ctx->graph);
518   ir_node *call = ctx->call;
519   const char *ent_name = (char*) get_entity_name (ent);
520   const char *own_name = (char*) get_type_name (get_entity_owner (ent));
521
522   fprintf (stream, "CTX[%i](%s.%s->%s[%li])",
523            ctx->id, own_name, ent_name,
524            get_op_name (get_irn_op (call)),
525            get_irn_node_nr (call));
526
527   if (NULL != ctx->enc) {
528     fprintf (stream, "->%i", ctx->enc->id);
529   }
530
531   fprintf (stream, "\n");
532 }
533
534 /*
535   Get a ctx of the given graph info
536 */
537 ctx_info_t *get_ctx (graph_info_t *ginfo, int ctx_idx)
538 {
539   assert (ginfo->n_ctxs > ctx_idx);
540
541   return (ginfo->ctxs [ctx_idx]);
542 }
543
544 /*
545   Get the pseudo-ctx of 'main'
546 */
547 ctx_info_t *get_main_ctx ()
548 {
549   return (main_ctx);
550 }
551
552 /*
553   Set the pseudo-ctx of 'main'
554 */
555 void set_main_ctx (ctx_info_t *ctx)
556 {
557   main_ctx = ctx;
558 }
559
560
561 /* ====================
562    ECG stuff
563    ==================== */
564
565 /* ====================
566    Iterator stuff
567    ==================== */
568 /*
569    Iterate over all graphs
570 */
571 void ecg_iterate_graphs (graph_hnd_t *hnd, void *env)
572 {
573   graph_info_t *ginfo = graph_infos_list;
574
575   while (NULL != ginfo) {
576     /* do not visit graphs that have 0 == ginfo->n_ctxs, since they
577        are not called */
578     if (0 != ginfo->n_ctxs) {
579       hnd (ginfo, env);
580     }
581
582     ginfo = ginfo->prev;
583   }
584 }
585
586
587 /*
588    Iterate of all allocs of a given graph info
589 */
590 void ecg_iterate_allocs (graph_info_t *ginfo, alloc_hnd_t *hnd, void *env)
591 {
592   alloc_info_t *ainfo = ginfo->allocs;
593
594   while (NULL != ainfo) {
595     hnd (ainfo, env);
596
597     ainfo = ainfo->prev;
598   }
599 }
600
601
602 /*
603   Iterate over all calls of the given graph info
604 */
605 void ecg_iterate_calls  (graph_info_t *ginfo, call_hnd_t *hnd, void *env)
606 {
607   call_info_t *cinfo = ginfo->calls;
608
609   while (NULL != cinfo) {
610     hnd (cinfo, env);
611
612     cinfo = cinfo->prev;
613   }
614 }
615
616
617 /*
618   Iterate over all callEds of the given call info
619 */
620 void ecg_iterate_callEds  (call_info_t *cinfo, callEd_hnd_t *hnd, void *env)
621 {
622   callEd_info_t *ced = cinfo->callEds;
623
624   while (NULL != ced) {
625     hnd (ced, env);
626
627     ced = ced->prev;
628   }
629 }
630
631
632 /*
633   get the call infos for the given graph
634 */
635 graph_info_t *ecg_get_info (ir_graph *graph)
636 {
637   graph_info_t *ginfo = (graph_info_t*) pmap_get (graph_infos, graph);
638
639   assert (ginfo && "no info for graph");
640
641   return (ginfo);
642 }
643
644 /*
645   Get the Alloc Infos for the given graph
646 */
647 alloc_info_t *ecg_get_alloc_info (ir_graph *graph)
648 {
649   graph_info_t *ginfo = ecg_get_info (graph);
650
651   return (ginfo->allocs);
652 }
653
654 /*
655   Get the Call Info for the given call
656 */
657 callEd_info_t *ecg_get_callEd_info (ir_node *call)
658 {
659   ir_graph *graph = get_irn_irg (call);
660   graph_info_t *ginfo = ecg_get_info (graph);
661
662   call_info_t *call_info = ginfo->calls;
663
664   while (NULL != call_info) {
665     if (call == call_info->call) {
666       return (call_info->callEds);
667     }
668
669     call_info = call_info->prev;
670   }
671
672   return (NULL);
673 }
674
675
676 /**
677    Dump the given graph and it's calls and it's calls callEds to the given file.
678 */
679 static int ecg_ecg_graph (FILE *dot, ir_graph *graph)
680 {
681   const char *name = get_irg_entity (graph) ?
682     get_entity_name (get_irg_entity (graph)) : "noEntity";
683   const char *color =
684     (get_entity_stickyness
685      (get_irg_entity (graph)) == stickyness_sticky) ?
686     "red" : "lightyellow";
687
688   /* graph_info_t *ginfo = (graph_info_t*) pmap_get (graph_infos, graph); */
689   graph_info_t *ginfo = ecg_get_info (graph);
690
691   if (0 != ginfo->ecg_seen) {
692     fprintf (dot, "\t/* recursive call to \"%s\" (%d) */\n",
693              name, (int) ginfo->ecg_seen);
694 # if 0
695     fprintf (dot, "\t/* recursive call to \"%s\" (0x%08x) */\n",
696              name, (int) graph);
697 # endif /* 0 */
698     return (ginfo->ecg_seen);
699   }
700
701   assert (0L <= _graphs);
702
703   const int graph_no = _graphs ++;
704   ginfo->ecg_seen = graph_no;
705
706   fprintf (dot, "\t/* Graph of \"%s.%s\" */\n",
707            get_type_name (get_entity_owner (get_irg_entity (graph))),
708            name);
709   fprintf (dot, "\tgraph_%i [label=\"<HEAD>%s\\l%s\\l|<CTX>n_ctx = %i\\l\", color=\"%s\"];\n",
710            graph_no,
711            get_type_name (get_entity_owner (get_irg_entity (graph))),
712            name,
713            ginfo->n_ctxs,
714            color);
715   fprintf (dot, "\n");
716
717   if (visibility_external_allocated ==
718       get_entity_visibility (get_irg_entity (graph))) {
719     fprintf (dot, "\t/* graph \"%s\" is external */\n", name);
720
721     return (graph_no);
722   }
723
724   call_info_t *cinfo = ginfo->calls;
725   while (NULL != cinfo) {
726     ir_node *call = cinfo->call;
727     callEd_info_t *ced = cinfo->callEds;
728     const int call_no = _calls ++;
729     const char *call_color = (NULL == ced->prev) ? "lightblue" : "blue3";
730
731     fprintf (dot, "\t/* Call %li */\n", get_irn_node_nr (call));
732     fprintf (dot, "\tcall_%i [label=\"call\\[%li\\]\", color=\"%s\", shape=\"ellipse\"];\n",
733              call_no, get_irn_node_nr (call), call_color);
734     fprintf (dot, "\tgraph_%i -> call_%i [color=\"black\"];\n", graph_no, call_no);
735
736     while (NULL != ced) {
737       ir_graph *callEd_graph = ced->callEd;
738       const int callEd_no = ecg_ecg_graph (dot, callEd_graph);
739       const char *callEd_name = get_irg_entity (callEd_graph) ?
740         get_entity_name (get_irg_entity (callEd_graph)) : "noEntity";
741       const char *direction = (callEd_no <= graph_no) ? "forward" : "forward";
742       const char *callEd_color     = (callEd_no <= graph_no) ? "red" : "black";
743
744       fprintf (dot, "\t/* Call from graph \"%s\" to graph \"%s\" */\n",
745                name,
746                callEd_name);
747       /* Check for recursive calls */
748       /* if (callEd_no > graph_no) */ { /* do recursive calls (for now) */
749         fprintf (dot, "\tcall_%i -> graph_%i:HEAD [color=\"%s\", dir=\"%s\"];\n",
750                  call_no, callEd_no, callEd_color, direction);
751       }
752
753       ced = ced->prev;
754       /* ced = NULL; */
755     } /* done all calEds (call) */
756
757     cinfo = cinfo->prev;
758   } /* done all calls (graph) */
759
760   /* now the allocs */
761   alloc_info_t *ainfo = ecg_get_alloc_info (graph);
762   if (ainfo) {
763     fprintf (dot, "\t/* now the allocs */\n");
764   } else {
765     fprintf (dot, "\t/* no allocs */\n");
766   }
767
768   while (NULL != ainfo) {
769     ir_node *alloc = ainfo->alloc;
770     const char *name = get_type_name (ainfo->tp);
771     const char *color = "red1";
772
773     _allocs ++;
774     fprintf (dot, "\talloc_0x%08x_%i [label=\"%s\", color=\"%s\"];\n",
775              (int) alloc, graph_no, name, color);
776
777     fprintf (dot, "\tgraph_%i -> alloc_0x%08x_%i;\n",
778              graph_no, (int) alloc, graph_no);
779
780     ainfo = ainfo->prev;
781   }
782
783   if (0 == ginfo->allocs_seen) {
784     ginfo->allocs_seen = 1;
785   }
786
787   /* write table of ctxs */
788   {
789     fprintf (dot, "\tctx_%i [label=\"<HEAD>", graph_no);
790
791     int i;
792     const int max_ctxs = 30;
793     const int n_ctxs = (ginfo->n_ctxs > max_ctxs) ? max_ctxs : ginfo->n_ctxs;
794
795     assert (ginfo->ctxs && "no ctx");
796     for (i = 0; i < n_ctxs; i ++) {
797       ctx_info_t *ctx_info = ginfo->ctxs [i];
798
799       if (NULL != ctx_info->enc) {
800         fprintf (dot, "ctx_info \\[%i\\] = ctx\\[%i\\-\\>%i\\]\\l",
801                  i,
802                  ctx_info->id,
803                  ctx_info->enc->id);
804       } else {
805         fprintf (dot, "ctx_info \\[%i\\] = ctx\\[%i\\]\\l",
806                  i, ctx_info->id);
807       }
808
809       if (i+1 != n_ctxs) {
810         fprintf (dot, "|");
811       }
812     }
813
814     if (0 < ginfo->n_ctxs - max_ctxs) {
815       fprintf (dot, "(%i more)\\l", ginfo->n_ctxs - max_ctxs);
816     }
817
818     fprintf (dot, "\", color=\"green3\"];\n");
819
820     fprintf (dot,
821              "\tgraph_%i:CTX -> ctx_%i:HEAD [label=\"ctx\", dir=\"none\", style=\"dotted\"];\n",
822              graph_no, graph_no);
823   }
824
825   fprintf (dot, "\t/* done with graph of \"%s\" */\n\n", name);
826
827   fflush (dot);
828   ginfo->ecg_seen = 0;
829
830   return (graph_no);
831 }
832
833 /**
834    Count how many nodes the ECG will have
835 */
836 static char spaces [BUF_SIZE];
837
838 static void ecg_ecg_count (ir_graph *graph)
839 {
840   graph_info_t *ginfo = (graph_info_t*) pmap_get (graph_infos, graph);
841
842   if (0 != ginfo->ecg_seen) {
843     return;
844   }
845
846   _depth ++;
847   if (_depth > _max_depth) {
848     _max_depth = _depth;
849
850     /*
851       fprintf (stdout, "_max_depth = %i\n", _max_depth);
852       fprintf (stdout, "\tn_graphs: %i\n", _graphs);
853     */
854   }
855
856   assert (0L <= _graphs);
857
858   /*
859     if (0 == (_graphs % 1000000)) {
860     fprintf (stdout, "\tn_graphs: %i\n", _graphs);
861     fprintf (stdout, "_depth = %i\n", _depth);
862     }
863   */
864
865   const int graph_no = _graphs ++;
866   ginfo->ecg_seen = graph_no;
867
868   fprintf (stdout, "%sMethod \"%s.%s\"\n",
869            spaces + BUF_SIZE - _depth,
870            get_type_name (get_entity_owner (get_irg_entity (graph))),
871            get_entity_name (get_irg_entity (graph)));
872
873   call_info_t *cinfo = ginfo->calls;
874   while (NULL != cinfo) {
875
876     callEd_info_t *ced = cinfo->callEds;
877
878     fprintf (stdout, "%sCall \"0x%08x\"\n",
879              spaces + BUF_SIZE - _depth,
880              (int) cinfo->call);
881
882     while (NULL != ced) {
883       ir_graph *callEd_graph = ced->callEd;
884
885       fprintf (stdout, "%sCall Target \"%s.%s\"\n",
886                spaces + BUF_SIZE - _depth,
887                get_type_name (get_entity_owner (get_irg_entity (callEd_graph))),
888                get_entity_name (get_irg_entity (callEd_graph)));
889
890       ecg_ecg_count (callEd_graph);
891
892       ced = ced->prev;
893     } /* done all calEds (call) */
894     cinfo = cinfo->prev;
895   } /* done all calls (graph) */
896
897   ginfo->ecg_seen = 0;
898   _depth --;
899 }
900
901 /* ====================
902    Public Interface
903    ==================== */
904
905 /**
906    Initialise our data structures.
907 */
908 void ecg_init (int typalise)
909 {
910   do_typalise = typalise;
911
912   graph_infos = pmap_create ();
913
914   ecg_fill_calls ();
915   ecg_fill_ctxs ();
916
917   ecg_ecg ();
918 }
919
920 /**
921    Clean up our mess.
922 */
923 void ecg_cleanup ()
924 {
925   int i;
926
927   for (i = 0; i < get_irp_n_irgs (); i++) {
928     ir_graph *graph = get_irp_irg (i);
929
930     graph_info_t *info = pmap_get (graph_infos, graph);
931     call_info_t *cinfo = info->calls;
932
933     while (NULL != cinfo) {
934       cinfo->call = NULL;
935
936       callEd_info_t *ced = cinfo->callEds;
937
938       while (NULL != ced) {
939         callEd_info_t *nced = ced->prev;
940         free (ced);
941         ced->prev = NULL;
942         ced->callEd = NULL;
943         ced = nced;
944       }
945
946       cinfo->callEds = NULL;
947
948       free (cinfo);
949       cinfo = cinfo->prev;
950     }
951
952     free (info);
953     pmap_insert (graph_infos, graph, NULL);
954   }
955
956
957   pmap_destroy (graph_infos);
958
959   /*  paranoia mode */
960   graph_infos = NULL;
961 }
962
963 /**
964    Show what we have found.
965 */
966 void ecg_report ()
967 {
968   int i;
969
970   FILE *dot = fopen ("calls.dot", "w");
971
972   fprintf (dot, "digraph \"calls\" {\n");
973   fprintf (dot, "\tnode [shape = \"record\", style = \"filled\"];\n");
974   fprintf (dot, "\tedge [color = \"black\"];\n");
975   fprintf (dot, "\n");
976   fprintf (dot, "\tsize = \"11, 7\";\n");
977   fprintf (dot, "\trotate = \"90\";\n");
978   fprintf (dot, "\tratio = \"fill\";\n");
979   fprintf (dot, "\trankdir = \"LR\";\n");
980   fprintf (dot, "\n");
981
982   for (i = 0; i < get_irp_n_irgs (); i++) {
983     ir_graph *graph = get_irp_irg (i);
984     graph_info_t *info = (graph_info_t*) pmap_get (graph_infos, graph);
985
986     const char *name = get_irg_entity (graph) ?
987       get_entity_name (get_irg_entity (graph)) : "noEntity";
988
989     const char *oname = get_type_name
990       (get_entity_owner (get_irg_entity (graph)));
991
992     const char *color =
993       (get_entity_stickyness
994        (get_irg_entity (graph)) == stickyness_sticky) ?
995       "red3" : "lightyellow";
996
997     fprintf (dot, "\t/* graph_0x%08x (\"%s\") */\n", (int) graph, name);
998     fprintf (dot,
999              "\tgraph_0x%08x [label=\"%s\\l%s\", color=\"%s\"];\n",
1000              (int) graph, oname, name, color);
1001     fprintf (dot, "\n");
1002
1003     call_info_t *cinfo = info->calls;
1004     if (cinfo) {
1005       fprintf (dot, "\t/* now the calls */\n");
1006     } else {
1007       fprintf (dot, "\t/* no calls, nothing to see, move along! */\n");
1008     }
1009
1010     while (NULL != cinfo) {
1011       ir_node *call = cinfo->call;
1012
1013       fprintf (dot, "\t/* call_0x%08x */\n", (int) call);
1014       fprintf (dot, "\tcall_0x%08x [label=\"call\\[%li\\]\\l0x%08x\"];\n",
1015                (int) call, get_irn_node_nr (call), (int) call);
1016       fprintf (dot, "\tgraph_0x%08x -> call_0x%08x;\n",
1017                (int) graph, (int) call);
1018
1019       callEd_info_t *ced = cinfo->callEds;
1020       while (NULL != ced) {
1021         fprintf (dot, "\tcall_0x%08x -> graph_0x%08x;\n",
1022                  (int) call, (int) ced->callEd);
1023         ced = ced->prev;
1024       }
1025       fprintf (dot, "\n");
1026
1027       cinfo = cinfo->prev;
1028     }
1029     fprintf (dot, "\n");
1030
1031     alloc_info_t *ainfo = info->allocs;
1032     if (ainfo) {
1033       fprintf (dot, "\t/* now the allocs */\n");
1034     } else {
1035       fprintf (dot, "\t/* no allocs */\n");
1036     }
1037
1038
1039     while (NULL != ainfo) {
1040       ir_node *alloc = ainfo->alloc;
1041       const char *name = get_type_name (ainfo->tp);
1042       const char *color = "green3";
1043
1044       fprintf (dot, "\talloc_0x%08x [label=\"%s\", color=\"%s\"];\n",
1045                (int) alloc, name, color);
1046       fprintf (dot, "\tgraph_0x%08x -> alloc_0x%08x;\n",
1047                (int) graph, (int) alloc);
1048
1049       ainfo = ainfo->prev;
1050     }
1051   }
1052   fprintf (dot, "}\n");
1053
1054   /*
1055     fprintf (stdout, " max_callEds: %i\n", _max_callEds);
1056     fprintf (stdout, " max_callEds_callR: \"%s\"\n",
1057     get_entity_name (_max_callEds_callR));
1058   */
1059   fclose (dot);
1060 }
1061
1062 /**
1063    Experimental:  Print the ecg
1064 */
1065 void ecg_ecg ()
1066 {
1067   _graphs = 0;
1068   _calls  = 0;
1069
1070   ir_graph *main_graph = get_irp_main_irg ();
1071
1072   /*
1073     memset (spaces, '.', BUF_SIZE);
1074     spaces [BUF_SIZE-1] = '\0';
1075
1076     ecg_ecg_count (main_graph);
1077     fprintf (stdout, "n_graphs: %i\n", _graphs);
1078     fprintf (stdout, "max_depth = %i\n", _max_depth);
1079   */
1080
1081   /* return; */
1082
1083   _graphs = 0;
1084   _calls  = 0;
1085
1086   FILE *dot = fopen ("ecg.dot", "w");
1087
1088   fprintf (dot, "digraph \"ecg\" {\n");
1089   fprintf (dot, "\tnode [shape = \"record\", style = \"filled\"];\n");
1090   fprintf (dot, "\tedge [color = \"black\"];\n");
1091   fprintf (dot, "\n");
1092   fprintf (dot, "\tsize = \"11, 7\";\n");
1093   fprintf (dot, "\trotate = \"90\";\n");
1094   fprintf (dot, "\tratio = \"fill\";\n");
1095   fprintf (dot, "\trankdir = \"LR\";\n");
1096   fprintf (dot, "\n");
1097
1098   /* ir_graph *main_graph = get_irp_main_irg (); */
1099   ecg_ecg_graph (dot, main_graph);
1100
1101   fprintf (dot, "\t/* Grand Total: */\n");
1102   fprintf (dot, "\t/* calls:  %i */\n", (int) _calls);
1103   fprintf (dot, "\t/* graphs: %i */\n", (int) _graphs);
1104   fprintf (dot, "\t/* allocs: %i */\n", (int) _allocs);
1105   fprintf (dot, "\t/* (sales tax not included) */\n");
1106
1107   fprintf (dot, "}\n");
1108
1109   fclose (dot);
1110 }
1111
1112 \f
1113
1114 /*
1115   $Log$
1116   Revision 1.6  2004/11/24 14:53:55  liekweg
1117   Bugfixes
1118
1119   Revision 1.5  2004/11/20 21:20:29  liekweg
1120   Added iterator functions
1121
1122   Revision 1.4  2004/11/18 16:36:37  liekweg
1123   Added unique ids for debugging, added access functions
1124
1125   Revision 1.3  2004/11/04 14:54:44  liekweg
1126   Nicer Colors
1127
1128   Revision 1.2  2004/10/21 11:09:37  liekweg
1129   Moved memwalk stuf into irmemwalk
1130   Moved lset stuff into lset
1131   Moved typalise stuff into typalise
1132
1133   Revision 1.1  2004/10/20 14:59:41  liekweg
1134   Added ana2, added ecg and pto
1135
1136   Revision 1.6  2004/10/18 12:47:19  liekweg
1137   minor fix
1138
1139   Revision 1.5  2004/10/14 11:31:28  liekweg
1140   SHUTUP_GCC
1141
1142   Revision 1.4  2004/10/12 11:02:01  liekweg
1143   wtf?
1144
1145 */