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