added edge OVERWRITES in vcg output
[libfirm] / ir / ir / irdump.c
1 /* Copyright (C) 1998 - 2000 by Universitaet Karlsruhe
2 ** All rights reserved.
3 **
4 ** Authors: Martin Trapp, Christian Schaefer
5 **
6 ** irdump.h: dumping of an intermediate representation graph
7 */
8
9 #ifdef HAVE_CONFIG_H
10 # include <config.h>
11 #endif
12
13 # include "irnode_t.h"
14 # include "irgraph_t.h"
15 # include "irprog.h"
16 # include "irdump.h"
17 # include "panic.h"
18 # include <string.h>
19 # include "entity.h"
20 # include <stdlib.h>
21 # include "array.h"
22 # include "irop_t.h"
23 # include "tv.h"
24 # include "type_or_entity.h"
25 # include "irgwalk.h"
26 # include "typewalk.h"
27
28 /* Attributes of nodes */
29 #define DEFAULT_NODE_ATTR ""
30 #define DEFAULT_TYPE_ATTRIBUTE ""
31
32 /* Attributes of edges between Firm nodes */
33 #define BLOCK_EDGE_ATTR "class: 2 priority: 2 linestyle: dotted"
34 #define CF_EDGE_ATTR    "color: red"
35 #define MEM_EDGE_ATTR   "color: blue"
36
37 /* Attributes of edges between Firm nodes and type/entity nodes */
38 #define NODE2TYPE_EDGE_ATTR ""
39
40 /* Attributes of edges in type/entity graphs. */
41 #define TYPE_METH_NODE_ATTR  "color: lightyellow"
42 #define TYPE_CLASS_NODE_ATTR "color: green"
43 #define ENTITY_NODE_ATTR     "color: yellow"
44 #define ENT_TYPE_EDGE_ATTR   "class: 3 label: \"type\" color: red"
45 #define ENT_OWN_EDGE_ATTR    "class: 4 label: \"owner\" color: black"
46 #define METH_PAR_EDGE_ATTR   "class: 5 label: \"param %d\" color: green"
47 #define METH_RES_EDGE_ATTR   "class: 6 label: \"res %d\" color: green"
48 #define TYPE_SUPER_EDGE_ATTR "class: 7 label: \"supertype\" color: blue"
49 #define UNION_EDGE_ATTR      "class: 8 label: \"component\" color: blue"
50 #define PTR_PTS_TO_EDGE_ATTR "class: 9 label: \"points to\" color:green"
51 #define ARR_ELT_TYPE_EDGE_ATTR "class: 10 label: \"arr elt\" color:green"
52 #define ENT_OVERWRITES_EDGE_ATTR "class: 11 label: \"overwrites\" color:red"
53
54 #define PRINT_NODEID(X) fprintf(F, "%p", X)
55
56 /* file to dump to */
57 static FILE *F;
58
59 int edge_label = 1;
60
61 /*******************************************************************/
62 /* routines to dump information about a single node                */
63 /*******************************************************************/
64
65
66
67 inline void
68 dump_node_opcode (ir_node *n)
69 {
70
71   /* Const */
72   if (n->op->code == iro_Const) {
73     xfprintf (F, "%v", n->attr.con);
74
75   /* SymConst */
76   } else if (n->op->code == iro_SymConst) {
77     if (get_SymConst_kind(n) == linkage_ptr_info) {
78       xfprintf (F, "%I", get_SymConst_ptrinfo(n));
79     } else {
80       assert(get_kind(get_SymConst_type(n)) == k_type);
81       assert(get_type_nameid(get_SymConst_type(n)));
82       xfprintf (F, "%s ", id_to_str(get_type_nameid(get_SymConst_type(n))));
83       if (get_SymConst_kind == type_tag)
84         xfprintf (F, "tag");
85       else
86         xfprintf (F, "size");
87     }
88   /* all others */
89   } else {
90     xfprintf (F, "%I", get_irn_opident(n));
91   }
92 }
93
94 inline void
95 dump_node_mode (ir_node *n)
96 {
97   switch (n->op->code) {
98   case iro_Phi:
99   case iro_Const:
100   case iro_Id:
101   case iro_Proj:
102   case iro_Conv:
103   case iro_Tuple:
104   case iro_Add:
105   case iro_Sub:
106   case iro_Mul:
107   case iro_And:
108   case iro_Or:
109   case iro_Eor:
110   case iro_Shl:
111   case iro_Shr:
112   case iro_Abs:
113   case iro_Cmp:
114     xfprintf (F, "%I", get_mode_ident(n->mode));
115     break;
116   default:
117   }
118 }
119
120 inline void
121 dump_node_nodeattr (ir_node *n)
122 {
123   switch (n->op->code) {
124   case iro_Proj:
125     if (n->in[1]->op->code == iro_Cmp) {
126       xfprintf (F, "%s", get_pnc_string(n->attr.proj));
127     } else {
128       xfprintf (F, "%ld", n->attr.proj);
129     }
130     break;
131   case iro_Sel: {
132     assert(get_kind(get_Sel_entity(n)) == k_entity);
133     xfprintf (F, "%s", id_to_str(get_entity_ident(get_Sel_entity(n))));
134     } break;
135   default:
136   } /* end switch */
137 }
138
139 inline void
140 dump_node_vcgattr (ir_node *n)
141 {
142   switch (n->op->code) {
143   case iro_Start:
144   case iro_End:
145     xfprintf (F, "color: blue");
146     break;
147   case iro_Block:
148     xfprintf (F, "color: lightyellow");
149     break;
150   case iro_Phi:
151     xfprintf (F, "color: green");
152     break;
153   case iro_Const:
154   case iro_Proj:
155   case iro_Tuple:
156     xfprintf (F, "color: yellow");
157     break;
158   default:
159     xfprintf (F, DEFAULT_NODE_ATTR);
160   }
161 }
162
163 void
164 dump_node (ir_node *n) {
165
166   /* dump this node */
167   xfprintf (F, "node: {title: \""); PRINT_NODEID(n); fprintf(F, "\" label: \"");
168
169   dump_node_opcode(n);
170   dump_node_mode (n);
171   xfprintf (F, " ");
172   dump_node_nodeattr(n);
173 #ifdef DEBUG_libfirm
174   xfprintf (F, " %ld", get_irn_node_nr(n));
175 #endif
176   xfprintf (F, "\" ");
177   dump_node_vcgattr(n);
178   xfprintf (F, "}\n");
179 }
180
181 void
182 dump_ir_node (ir_node *n)
183 {
184   /* dump this node */
185   fprintf (F, "node: {title: \""); PRINT_NODEID(n); fprintf(F, "\" label: ");
186
187   switch (n->op->code) {  /* node label */
188   case iro_Start:
189     xfprintf (F, "\"%I\" color: blue ", get_irn_opident(n));
190     xfprintf (F, DEFAULT_NODE_ATTR);
191      break;
192   case iro_End:
193     xfprintf (F, "\"%I\" color: blue ", get_irn_opident(n));
194     xfprintf (F, DEFAULT_NODE_ATTR);
195     break;
196   case iro_Block:
197     xfprintf (F, "\"%I\" color: lightyellow ", get_irn_opident(n));
198     xfprintf (F, DEFAULT_NODE_ATTR);
199     break;
200   case iro_Phi:
201     xfprintf (F, "\"%I%I\" color: green", get_irn_opident(n), get_irn_modeident(n));
202     if (get_irn_modecode(n) == irm_M)
203       xfprintf (F, DEFAULT_NODE_ATTR " color: green");
204     else
205       xfprintf (F, DEFAULT_NODE_ATTR);
206     break;
207   case iro_Const:
208     xfprintf (F, "\"%v%I\" color: yellow ", n->attr.con, get_irn_modeident(n));
209     xfprintf (F, DEFAULT_NODE_ATTR);
210     break;
211   case iro_Id:
212     xfprintf (F, "\"%I%I\" ", get_irn_opident(n), get_irn_modeident(n));
213     xfprintf (F, DEFAULT_NODE_ATTR);
214     break;
215   case iro_Proj:
216     if (n->in[1]->op->code == iro_Cmp) {
217       xfprintf (F, "\"%I%I %s\" color: yellow", get_irn_opident(n), get_irn_modeident(n),
218                 get_pnc_string(n->attr.proj));
219     } else {
220       xfprintf (F, "\"%I%I %ld\"", get_irn_opident(n), get_irn_modeident(n), n->attr.proj);
221     }
222     xfprintf (F, DEFAULT_NODE_ATTR);
223     break;
224   case iro_Conv:
225     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
226     xfprintf (F, DEFAULT_NODE_ATTR);
227     break;
228   case iro_Tuple:
229     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
230     xfprintf (F, DEFAULT_NODE_ATTR);
231     break;
232   case iro_Add:
233     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
234     xfprintf (F, DEFAULT_NODE_ATTR);
235     break;
236   case iro_Sub:
237     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
238     xfprintf (F, DEFAULT_NODE_ATTR);
239     break;
240   case iro_Mul:
241     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
242     xfprintf (F, DEFAULT_NODE_ATTR);
243     break;
244   case iro_Quot:
245     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
246     xfprintf (F, DEFAULT_NODE_ATTR);
247     break;
248   case iro_DivMod:
249     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
250     xfprintf (F, DEFAULT_NODE_ATTR);
251     break;
252   case iro_Div:
253     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
254     xfprintf (F, DEFAULT_NODE_ATTR);
255     break;
256   case iro_Mod:
257     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
258     xfprintf (F, DEFAULT_NODE_ATTR);
259     break;
260   case iro_And:
261     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
262     xfprintf (F, DEFAULT_NODE_ATTR);
263     break;
264   case iro_Or:
265     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
266     xfprintf (F, DEFAULT_NODE_ATTR);
267     break;
268   case iro_Eor:
269     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
270     xfprintf (F, DEFAULT_NODE_ATTR);
271     break;
272   case iro_Shl:
273     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
274     xfprintf (F, DEFAULT_NODE_ATTR);
275     break;
276   case iro_Shr:
277     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
278     xfprintf (F, DEFAULT_NODE_ATTR);
279     break;
280   case iro_Abs:
281     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
282     xfprintf (F, DEFAULT_NODE_ATTR);
283     break;
284   case iro_Cmp:
285     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
286     xfprintf (F, DEFAULT_NODE_ATTR);
287     break;
288   case iro_Jmp:
289     xfprintf (F, "\"%I\"", get_irn_opident(n));
290     xfprintf (F, DEFAULT_NODE_ATTR);
291     break;
292   case iro_Cond:
293     xfprintf (F, "\"%I\"", get_irn_opident(n));
294     xfprintf (F, DEFAULT_NODE_ATTR);
295     break;
296   case iro_Call:
297     xfprintf (F, "\"%I\"", get_irn_opident(n));
298     xfprintf (F, DEFAULT_NODE_ATTR);
299     break;
300   case iro_Return:
301     xfprintf (F, "\"%I\"", get_irn_opident(n));
302     xfprintf (F, DEFAULT_NODE_ATTR);
303     break;
304   case iro_Raise:
305     xfprintf (F, "\"%I%I\"", get_irn_opident(n), get_irn_modeident(n));
306     xfprintf (F, DEFAULT_NODE_ATTR);
307     break;
308   case iro_Load:
309   case iro_Store:
310     xfprintf (F, "\"%R\"", n);
311     xfprintf (F, DEFAULT_NODE_ATTR);
312     break;
313   case iro_Alloc:
314     xfprintf (F, "\"%I\" ", get_irn_opident(n));
315     xfprintf (F, DEFAULT_NODE_ATTR);
316     break;
317   case iro_Sel:
318     assert(get_kind(get_Sel_entity(n)) == k_entity);
319     xfprintf (F, "\"%I ", get_irn_opident(n));
320     xfprintf (F, "%s", id_to_str(get_entity_ident(get_Sel_entity(n))));
321     xfprintf (F, DEFAULT_NODE_ATTR);
322     break;
323   case iro_SymConst:
324     assert(get_kind(get_SymConst_type(n)) == k_type);
325     assert(get_type_nameid(get_SymConst_type(n)));
326     xfprintf (F, "\"%s ", get_type_name(get_SymConst_type(n)));
327     switch (n->attr.i.num){
328     case type_tag:
329       xfprintf (F, "tag\" ");
330       break;
331     case size:
332       xfprintf (F, "size\" ");
333       break;
334     default:
335       assert(0);
336       break;
337     }
338     xfprintf (F, DEFAULT_NODE_ATTR);
339     break;
340   case iro_Sync:
341     xfprintf (F, "\"%I\" ", get_irn_opident(n));
342     xfprintf (F, DEFAULT_NODE_ATTR " color: green");
343     break;
344   case iro_Bad:
345     xfprintf (F, "\"%I%I\" ", get_irn_opident(n), get_irn_modeident(n));
346     xfprintf (F, DEFAULT_NODE_ATTR);
347     break;
348   default:
349     xfprintf (F, "\"%I%I\" ", get_irn_opident(n), get_irn_modeident(n));
350   }
351   xfprintf (F, "}\n");          /* footer */
352 }
353
354
355 /* dump the edge to the block this node belongs to */
356 void
357 dump_ir_block_edge(ir_node *n)  {
358   if (is_no_Block(n))
359     xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
360                 BLOCK_EDGE_ATTR "}\n", n, get_nodes_Block(n));
361 }
362
363 void print_edge_vcgattr(ir_node *from, int to) {
364   assert(from);
365
366   switch (get_irn_opcode(from)) {
367   case iro_Block:
368     xfprintf (F, CF_EDGE_ATTR);
369     break;
370   case iro_Start:   break;
371   case iro_End:     break;
372   case iro_Jmp:     break;
373   case iro_Cond:    break;
374   case iro_Return:
375   case iro_Raise:
376     if (to == 0) xfprintf (F, MEM_EDGE_ATTR);
377     break;
378   case iro_Const:   break;
379   case iro_SymConst:break;
380   case iro_Sel:
381   case iro_Call:
382     if (to == 0) xfprintf (F, MEM_EDGE_ATTR);
383     break;
384   case iro_Add:     break;
385   case iro_Sub:     break;
386   case iro_Minus:   break;
387   case iro_Mul:     break;
388   case iro_Quot:
389   case iro_DivMod:
390   case iro_Div:
391   case iro_Mod:
392     if (to == 0) xfprintf (F, MEM_EDGE_ATTR);
393     break;
394   case iro_Abs:    break;
395   case iro_And:    break;
396   case iro_Or:     break;
397   case iro_Eor:    break;
398   case iro_Shl:    break;
399   case iro_Shr:    break;
400   case iro_Shrs:   break;
401   case iro_Rot:    break;
402   case iro_Cmp:    break;
403   case iro_Conv:   break;
404   case iro_Phi:
405     if (get_irn_modecode(from) == irm_M) xfprintf (F, MEM_EDGE_ATTR);
406     break;
407   case iro_Load:
408   case iro_Store:
409   case iro_Alloc:
410   case iro_Free:
411     if (to == 0) xfprintf (F, MEM_EDGE_ATTR);
412     break;
413   case iro_Sync:
414     xfprintf (F, MEM_EDGE_ATTR);
415     break;
416   case iro_Tuple:  break;
417   case iro_Proj:
418     switch (get_irn_modecode(from)) {
419     case irm_X:
420       xfprintf (F, CF_EDGE_ATTR);
421       break;
422     case irm_M:
423       xfprintf (F, MEM_EDGE_ATTR);
424       break;
425     default: break;
426     }
427     break;
428   case iro_Bad:    break;
429   case iro_Id:     break;
430   default:
431   }
432 }
433
434 /* dump edges to our inputs */
435 void
436 dump_ir_data_edges(ir_node *n)  {
437   int i;
438
439   for (i = 0; i < get_irn_arity(n); i++) {
440     assert(get_irn_n(n, i));
441     xfprintf (F, "edge: {sourcename: \"%p\" targetname: \"%p\"",
442               n, get_irn_n(n, i));
443     fprintf (F, " label: \"%d\" ", i+1);
444     print_edge_vcgattr(n, i);
445     fprintf (F, "}\n");
446   }
447 }
448
449 /* dumps the edges between nodes and their type or entity attributes. */
450 void dump_node2type_edges (ir_node *n, void *env)
451 {
452   assert(n);
453
454   switch (get_irn_opcode(n)) {
455   case iro_SymConst:
456     if (   (get_SymConst_kind(n) == type_tag)
457         || (get_SymConst_kind(n) == size))
458       xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
459                 NODE2TYPE_EDGE_ATTR "}\n", n, get_SymConst_type(n));
460     break;
461   case iro_Sel:
462     xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
463               NODE2TYPE_EDGE_ATTR "}\n", n, get_Sel_entity(n));
464     break;
465   case iro_Call:
466     xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
467               NODE2TYPE_EDGE_ATTR "}\n", n, get_Call_type(n));
468     break;
469   case iro_Alloc:
470     xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
471               NODE2TYPE_EDGE_ATTR "}\n", n, get_Alloc_type(n));
472     break;
473   case iro_Free:
474     xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
475               NODE2TYPE_EDGE_ATTR "}\n", n, get_Free_type(n));
476     break;
477   default:
478     break;
479   }
480 }
481
482
483 /* dumps a type or entity and it's edges. */
484 void
485 dump_type_info (type_or_ent *tore, void *env) {
486   int i = 0;  /* to shutup gcc */
487
488   /* dump this type or entity */
489   xfprintf (F, "node: {title: \"%p\" ", tore);
490   xfprintf (F, DEFAULT_TYPE_ATTRIBUTE);
491   xfprintf (F, "label: ");
492
493   switch (get_kind(tore)) {
494   case k_entity:
495     {
496       entity *ent = (entity *)tore;
497       xfprintf (F, "\"ent %I\" " ENTITY_NODE_ATTR "}\n", get_entity_ident(ent));
498       xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
499                 ENT_OWN_EDGE_ATTR "}\n", tore, get_entity_owner(ent));
500       xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
501                 ENT_TYPE_EDGE_ATTR "}\n", tore, get_entity_type(ent));
502       for(i = 0; i < get_entity_n_overwrites(ent); i++)
503         xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
504                   ENT_OVERWRITES_EDGE_ATTR "}\n", tore, get_entity_overwrites(ent, i));
505     } break;
506   case k_type:
507     {
508       /* why can't I cast here??? @@@ */
509       type *type = tore;
510       xfprintf (F, "\"%I %I", get_type_tpop_nameid(type), get_type_nameid(type));
511
512       switch (get_type_tpop_code(type)) {
513       case tpo_class:
514         {
515           xfprintf (F, "\" " TYPE_CLASS_NODE_ATTR "}\n");
516           for (i=0; i < get_class_n_supertype(type); i++)
517             xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
518                       TYPE_SUPER_EDGE_ATTR "}\n",
519                       type, get_class_supertype(type, i));
520         } break;
521       case tpo_struct:
522         {
523           xfprintf (F, "\"}\n");
524         } break;
525       case tpo_method:
526         {
527           xfprintf (F, "\" " TYPE_METH_NODE_ATTR "}\n");
528           for (i = 0; i < get_method_n_params(type); i++)
529             xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
530                       METH_PAR_EDGE_ATTR "}\n",
531                       type, get_method_param_type(type, i), i);
532           for (i = 0; i < get_method_n_res(type); i++)
533             xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
534                       METH_RES_EDGE_ATTR "}\n",
535                       type, get_method_res_type(type, i), i);
536         } break;
537       case tpo_union:
538         {
539           xfprintf (F, "\"}\n");
540           for (i = 0; i < get_union_n_members(type); i++)
541             xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
542                       "label: \"\"f" UNION_EDGE_ATTR "}\n",
543                       type, get_union_member(type, i));
544         } break;
545       case tpo_array:
546         {
547           xfprintf (F, "\"}\n");
548           xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
549                     ARR_ELT_TYPE_EDGE_ATTR "}\n", type, get_array_element_type(type), i);
550         } break;
551       case tpo_enumeration:
552         {
553           xfprintf (F, "\"}\n");
554         } break;
555       case tpo_pointer:
556         {
557           xfprintf (F, "\"}\n");
558           xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
559                     PTR_PTS_TO_EDGE_ATTR "}\n", type,
560                     get_pointer_points_to_type(type), i);
561         } break;
562       case tpo_primitive:
563         {
564           xfprintf (F, "mode %I\"}\n", get_mode_ident(get_type_mode(type)));
565         } break;
566       default: break;
567       } /* switch type */
568
569     } break; /* case k_type */
570   default:
571     {
572       xfprintf (F, "\" faulty type \"}\n");
573       printf(" *** irdump,  %s(l.%i), faulty type.\n", __FUNCTION__, __LINE__);
574     } break;
575   } /* switch kind_or_entity */
576 }
577
578 /************************************************************************/
579 /* open and close vcg file                                              */
580 /************************************************************************/
581
582 void vcg_open (ir_graph *irg, char *suffix) {
583   char *fname;  /* filename to put the vcg information in */
584   const char *cp;
585   ident *id;
586   int len;
587   char label[4];
588
589   /** open file for vcg graph */
590   id    = get_entity_ld_ident (get_irg_ent(irg));
591   len   = id_to_strlen (id);
592   cp    = id_to_str (id);
593
594   fname = malloc (len + 5 + strlen(suffix));
595   strncpy (fname, cp, len);      /* copy the filename */
596   fname[len] = '\0';
597   strcat (fname, suffix);  /* append file suffix */
598
599   fname = malloc (len + 5 + strlen(suffix));
600   strncpy (fname, cp, len); /* copy the filename */
601   fname[len] = '\0';        /* ensure string termination */
602   /*strcpy (fname, cp);      * copy the filename *
603     this produces wrong, too long strings in conjuction with the
604     jocca frontend.  The \0 seems to be missing. */
605   strcat (fname, suffix);   /* append file suffix */
606   strcat (fname, ".vcg");   /* append the .vcg suffix */
607   F = fopen (fname, "w");   /* open file for writing */
608   if (!F) {
609     panic ("cannot open %s for writing (%m)", fname);  /* not reached */
610   }
611
612   if (edge_label) {
613     strcpy(label, "yes");
614   } else {
615     strcpy (label, "no");
616   }
617
618   /* print header */
619   xfprintf (F,
620             "graph: { title: \"ir graph of %s\"\n"
621             "display_edge_labels: %s\n"
622             "layoutalgorithm: mindepth\n"
623             "manhattan_edges: yes\n"
624             "port_sharing: no\n"
625             "orientation: bottom_to_top\n"
626             "classname 1: \"Data\"\n"
627             "classname 2: \"Block\"\n"
628             "classname 3: \"Entity type\""
629             "classname 4: \"Entity owner\""
630             "classname 5: \"Method Param\""
631             "classname 6: \"Method Res\""
632             "classname 7: \"Super\""
633             "classname 8: \"Union\""
634             "classname 9: \"Points-to\""
635             "classname 10: \"Array Element Type\""
636             , cp, label);
637
638   xfprintf (F, "\n");           /* a separator */
639 }
640
641 void vcg_open_name (const char *name) {
642   char *fname;  /* filename to put the vcg information in */
643   int len;
644   char label[4];
645
646   /** open file for vcg graph */
647   len   = strlen(name);
648   fname = malloc (len + 5);
649   strcpy (fname, name);    /* copy the filename */
650   strcat (fname, ".vcg");  /* append the .vcg suffix */
651   F = fopen (fname, "w");  /* open file for writing */
652   if (!F) {
653     panic ("cannot open %s for writing (%m)", fname);  /* not reached */
654   }
655
656   if (edge_label) {
657     strcpy(label, "yes");
658   } else {
659     strcpy (label, "no");
660   }
661
662   /* print header */
663   xfprintf (F,
664             "graph: { title: \"ir graph of %s\"\n"
665             "display_edge_labels: %s\n"
666             "layoutalgorithm: mindepth\n"
667             "manhattan_edges: yes\n"
668             "port_sharing: no\n"
669             "orientation: bottom_to_top\n"
670             "classname 1: \"Data\"\n"
671             "classname 2: \"Block\"\n"
672             "classname 3: \"Entity type\""
673             "classname 4: \"Entity owner\""
674             "classname 5: \"Method Param\""
675             "classname 6: \"Method Res\""
676             "classname 7: \"Super\""
677             "classname 8: \"Union\""
678             "classname 9: \"Points-to\""
679             "classname 10: \"Array Element Type\""
680             , name, label);
681
682   xfprintf (F, "\n");           /* a separator */
683 }
684
685 void
686 vcg_close () {
687   xfprintf (F, "}\n");  /* print footer */
688   fclose (F);           /* close vcg file */
689 }
690
691 /************************************************************************/
692 /* routines to dump a graph, blocks as conventional nodes.              */
693 /************************************************************************/
694
695 void
696 dump_whole_node (ir_node *n, void* env) {
697   dump_node(n);
698   dump_ir_block_edge(n);
699   dump_ir_data_edges(n);
700 }
701
702 void
703 dump_ir_graph (ir_graph *irg)
704 {
705   ir_graph *rem;
706   rem = current_ir_graph;
707   current_ir_graph = irg;
708
709   vcg_open (irg, "");
710
711   /* walk over the graph */
712   irg_walk(irg->end, dump_whole_node, NULL, NULL);
713
714   vcg_close();
715
716   current_ir_graph = rem;
717 }
718
719 /***********************************************************************/
720 /* the following routines dump the nodes as attached to the blocks.    */
721 /***********************************************************************/
722
723 void
724 dump_ir_blocks_nodes (ir_node *n, void *env) {
725   ir_node *block = (ir_node *)env;
726
727   if (is_no_Block(n) && get_nodes_Block(n) == block) {
728     dump_node(n);
729     dump_ir_data_edges(n);
730   }
731 }
732
733 void
734 dump_ir_block (ir_node *block, void *env) {
735   ir_graph *irg = (ir_graph *)env;
736
737   if (get_irn_opcode(block) == iro_Block) {
738
739     /* This is a block. So dump the vcg information to make a block. */
740     xfprintf(F, "graph: { title: \""); PRINT_NODEID(block); fprintf(F, "\"  label: \"");
741 #ifdef DEBUG_libfirm
742     xfprintf (F, "%ld", get_irn_node_nr(block));
743 #else
744     xfprintf (F, "%I", block->op->name);
745 #endif
746     xfprintf(F, "\" status:clustered color:lightyellow \n");
747     /* dump the blocks edges */
748     dump_ir_data_edges(block);
749
750     /* dump the nodes that go into the block */
751     irg_walk(irg->end, dump_ir_blocks_nodes, NULL, block);
752
753     /* Close the vcg information for the block */
754     xfprintf(F, "}\n\n");
755   }
756 }
757
758 void
759 dump_ir_block_graph (ir_graph *irg)
760 {
761   ir_graph *rem;
762   rem = current_ir_graph;
763   current_ir_graph = irg;
764
765   vcg_open (irg, "");
766
767   /* walk over the blocks in the graph */
768   irg_block_walk(irg->end, dump_ir_block, NULL, irg);
769
770   vcg_close();
771   current_ir_graph = rem;
772 }
773
774
775 /***********************************************************************/
776 /* the following routines dump a control flow graph                    */
777 /***********************************************************************/
778
779
780 void
781 dump_block_to_cfg (ir_node *block, void *env) {
782   int i;
783   ir_node *pred;
784
785   if (get_irn_opcode(block) == iro_Block) {
786     /* This is a block. Dump a node for the block. */
787     xfprintf (F, "node: {title: \"%p\" label: \"%I\"}", block,
788               block->op->name);
789     /* Dump the edges */
790     for ( i = 0; i < get_Block_n_cfgpreds(block); i++) {
791       pred = get_nodes_Block(skip_Proj(get_Block_cfgpred(block, i)));
792       xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" }\n",
793                 block, pred);
794     }
795   }
796 }
797
798 void
799 dump_cfg (ir_graph *irg)
800 {
801   vcg_open (irg, "-cfg");
802
803   /* walk over the blocks in the graph */
804   irg_block_walk(irg->end, dump_block_to_cfg, NULL, NULL);
805
806   vcg_close();
807 }
808
809
810 /***********************************************************************/
811 /* the following routine dumps all type information reachable from an  */
812 /* irg                                                                 */
813 /***********************************************************************/
814
815
816 void
817 dump_type_graph (ir_graph *irg)
818 {
819   ir_graph *rem;
820   rem = current_ir_graph;
821   current_ir_graph = irg;
822
823   vcg_open (irg, "-type");
824
825   /* walk over the blocks in the graph */
826   type_walk_irg(irg, dump_type_info, NULL, NULL);
827
828   vcg_close();
829   current_ir_graph = rem;
830 }
831
832 /***********************************************************************/
833 /* the following routine dumps all type information                    */
834 /***********************************************************************/
835
836
837 void
838 dump_all_types (void)
839 {
840   vcg_open_name ("All_types");
841   type_walk(dump_type_info, NULL, NULL);
842   vcg_close();
843 }
844
845 /***********************************************************************/
846 /* dumps a graph with type information                                 */
847 /***********************************************************************/
848
849
850 void
851 dump_ir_graph_w_types (ir_graph *irg)
852 {
853   ir_graph *rem;
854   rem = current_ir_graph;
855   current_ir_graph = irg;
856
857   vcg_open (irg, "-all");
858
859   /* dump common ir graph */
860   /*  irg_block_walk(irg->end, dump_ir_block, NULL, irg); */
861   irg_walk(irg->end, dump_whole_node, NULL, NULL);
862   /* dump type info */
863   type_walk_irg(irg, dump_type_info, NULL, NULL);
864   /* dump edges from graph to type info */
865   irg_walk(irg->end, dump_node2type_edges, NULL, NULL);
866
867   vcg_close();
868   current_ir_graph = rem;
869 }
870
871 /***********************************************************************/
872 /* dumps all graphs with the graph-dumper passed. Possible dumpers:    */
873 /*  dump_ir_graph                                                      */
874 /*  dump_ir_block_graph                                                */
875 /*  dump_cfg                                                           */
876 /*  dump_type_graph                                                    */
877 /*  dump_ir_graph_w_types                                              */
878 /***********************************************************************/
879 void dump_all_ir_graphs (void dump_graph(ir_graph*)) {
880   int i;
881   for (i=0; i < get_irp_n_irgs(); i++) {
882     dump_graph(get_irp_irg(i));
883   }
884 }
885
886
887 /* To turn off display of edge labels.  Edge labels offen cause xvcg to
888    abort with a segmentation fault. */
889 void turn_of_edge_labels() {
890   edge_label = 0;
891 }