*** empty log message ***
[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 # include <assert.h>
10 # include "irdump.h"
11 # include "panic.h"
12 # include <string.h>
13 # include "entity.h"
14 # include <stdlib.h>
15 # include "array.h"
16 # include "irop.h"
17 # include "tv.h"
18 # include "type_or_entity.h"
19 # include "irgwalk.h"
20 # include "typewalk.h"
21
22 #define DEFAULT_NODE_ATTR ""
23 #define BLOCK_EDGE_ATTR "class: 2 priority: 2 linestyle: dotted"
24 #define NODE2TYPE_EDGE_ATTR ""
25 #define DEFAULT_TYPE_ATTRIBUTE ""
26 #define TYPE_EDGE_ATTR ""
27
28 /* file to dump to */
29 static FILE *F;
30
31
32 /*******************************************************************/
33 /* routines to dump information about a single node                */
34 /*******************************************************************/
35
36
37
38 inline void
39 dump_node_opcode (ir_node *n)
40 {
41   /* Const */
42   if (n->op->code == iro_Const) {
43     xfprintf (F, "%v", n->attr.con);
44   /* SymConst */
45   } else if (n->op->code == iro_SymConst) {
46     if (get_SymConst_kind(n) == linkage_ptr_info) {
47       xfprintf (F, "%I", get_SymConst_ptrinfo(n));
48     } else {
49       assert(get_kind(get_SymConst_type(n)) == k_type_class);
50       assert(get_class_ident((type_class *)get_SymConst_type(n)));
51       xfprintf (F, "%s ", id_to_str(get_class_ident((type_class *)get_SymConst_type(n))));
52       if (get_SymConst_kind == type_tag)
53         xfprintf (F, "tag");
54       else
55         xfprintf (F, "size");
56     }
57   /* all others */
58   } else {
59     xfprintf (F, "%I", n->op->name);
60   }
61 }
62
63 inline void
64 dump_node_mode (ir_node *n)
65 {
66   switch (n->op->code) {
67   case iro_Phi:
68   case iro_Const:
69   case iro_Id:
70   case iro_Proj:
71   case iro_Conv:
72   case iro_Tuple:
73   case iro_Add:
74   case iro_Sub:
75   case iro_Mul:
76   case iro_And:
77   case iro_Or:
78   case iro_Eor:
79   case iro_Shl:
80   case iro_Shr:
81   case iro_Abs:
82   case iro_Cmp:
83     xfprintf (F, "%I", n->mode->name);
84     break;
85   default:
86   }
87 }
88
89 inline void
90 dump_node_nodeattr (ir_node *n)
91 {
92   switch (n->op->code) {
93   case iro_Proj:
94     if (n->in[1]->op->code == iro_Cmp) {
95       xfprintf (F, "%s", get_pnc_string(n->attr.proj));
96     } else {
97       xfprintf (F, "%ld", n->attr.proj);
98     }
99     break;
100   case iro_Sel:
101     assert(n->attr.s.ent->kind == k_entity);
102     xfprintf (F, "%s", id_to_str(n->attr.s.ent->name));
103     /*  xdoesn't work for some reason.
104         fprintf (F, "\"%I %I\" ", n->op->name, n->attr.s.ent); */
105     break;
106   default:
107   } /* end switch */
108 }
109
110 inline void
111 dump_node_vcgattr (ir_node *n)
112 {
113   switch (n->op->code) {
114   case iro_Start:
115   case iro_End:
116     xfprintf (F, "color: blue");
117     break;
118   case iro_Block:
119     xfprintf (F, "color: lightyellow");
120     break;
121   case iro_Phi:
122     xfprintf (F, "color: green");
123     break;
124   case iro_Const:
125   case iro_Proj:
126   case iro_Tuple:
127     xfprintf (F, "color: yellow");
128     break;
129   default:
130     xfprintf (F, DEFAULT_NODE_ATTR);
131   }
132 }
133
134 void
135 dump_node (ir_node *n) {
136
137   /* dump this node */
138   xfprintf (F, "node: {title: \"%p\" label: \"", n);
139   dump_node_opcode(n);
140   dump_node_mode (n);
141   xfprintf (F, " ");
142   dump_node_nodeattr(n);
143 #ifdef DEBUG_libfirm
144   xfprintf (F, " %ld", get_irn_node_nr(n));
145 #endif
146   xfprintf (F, "\" ");
147   dump_node_vcgattr(n);
148   xfprintf (F, "}\n");
149 }
150
151 void
152 dump_ir_node (ir_node *n)
153 {
154   /* dump this node */
155   xfprintf (F, "node: {title: \"%p\" label: ", n);
156
157   switch (n->op->code) {  /* node label */
158   case iro_Start:
159     xfprintf (F, "\"%I\" color: blue ", n->op->name);
160     xfprintf (F, DEFAULT_NODE_ATTR);
161      break;
162   case iro_End:
163     xfprintf (F, "\"%I\" color: blue ", n->op->name);
164     xfprintf (F, DEFAULT_NODE_ATTR);
165     break;
166   case iro_Block:
167     xfprintf (F, "\"%I\" color: lightyellow ", n->op->name);
168     xfprintf (F, DEFAULT_NODE_ATTR);
169     break;
170   case iro_Phi:
171     xfprintf (F, "\"%I%I\" color: green", n->op->name, n->mode->name);
172     if (n->mode->code == irm_M)
173       xfprintf (F, DEFAULT_NODE_ATTR " color: green");
174     else
175       xfprintf (F, DEFAULT_NODE_ATTR);
176     break;
177   case iro_Const:
178     xfprintf (F, "\"%v%I\" color: yellow ", n->attr.con, n->mode->name);
179     xfprintf (F, DEFAULT_NODE_ATTR);
180     break;
181   case iro_Id:
182     xfprintf (F, "\"%I%I\" ", n->op->name, n->mode->name);
183     xfprintf (F, DEFAULT_NODE_ATTR);
184     break;
185   case iro_Proj:
186     if (n->in[1]->op->code == iro_Cmp) {
187       xfprintf (F, "\"%I%I %s\" color: yellow", n->op->name, n->mode->name,
188                 get_pnc_string(n->attr.proj));
189     } else {
190       xfprintf (F, "\"%I%I %ld\"", n->op->name, n->mode->name, n->attr.proj);
191     }
192     xfprintf (F, DEFAULT_NODE_ATTR);
193     break;
194   case iro_Conv:
195     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
196     xfprintf (F, DEFAULT_NODE_ATTR);
197     break;
198   case iro_Tuple:
199     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
200     xfprintf (F, DEFAULT_NODE_ATTR);
201     break;
202   case iro_Add:
203     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
204     xfprintf (F, DEFAULT_NODE_ATTR);
205     break;
206   case iro_Sub:
207     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
208     xfprintf (F, DEFAULT_NODE_ATTR);
209     break;
210   case iro_Mul:
211     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
212     xfprintf (F, DEFAULT_NODE_ATTR);
213     break;
214   case iro_Quot:
215     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
216     xfprintf (F, DEFAULT_NODE_ATTR);
217     break;
218   case iro_DivMod:
219     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
220     xfprintf (F, DEFAULT_NODE_ATTR);
221     break;
222   case iro_Div:
223     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
224     xfprintf (F, DEFAULT_NODE_ATTR);
225     break;
226   case iro_Mod:
227     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
228     xfprintf (F, DEFAULT_NODE_ATTR);
229     break;
230   case iro_And:
231     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
232     xfprintf (F, DEFAULT_NODE_ATTR);
233     break;
234   case iro_Or:
235     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
236     xfprintf (F, DEFAULT_NODE_ATTR);
237     break;
238   case iro_Eor:
239     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
240     xfprintf (F, DEFAULT_NODE_ATTR);
241     break;
242   case iro_Shl:
243     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
244     xfprintf (F, DEFAULT_NODE_ATTR);
245     break;
246   case iro_Shr:
247     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
248     xfprintf (F, DEFAULT_NODE_ATTR);
249     break;
250   case iro_Abs:
251     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
252     xfprintf (F, DEFAULT_NODE_ATTR);
253     break;
254   case iro_Cmp:
255     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
256     xfprintf (F, DEFAULT_NODE_ATTR);
257     break;
258   case iro_Jmp:
259     xfprintf (F, "\"%I\"", n->op->name);
260     xfprintf (F, DEFAULT_NODE_ATTR);
261     break;
262   case iro_Cond:
263     xfprintf (F, "\"%I\"", n->op->name);
264     xfprintf (F, DEFAULT_NODE_ATTR);
265     break;
266   case iro_Call:
267     xfprintf (F, "\"%I\"", n->op->name);
268     xfprintf (F, DEFAULT_NODE_ATTR);
269     break;
270   case iro_Return:
271     xfprintf (F, "\"%I\"", n->op->name);
272     xfprintf (F, DEFAULT_NODE_ATTR);
273     break;
274   case iro_Raise:
275     xfprintf (F, "\"%I%I\"", n->op->name, n->mode->name);
276     xfprintf (F, DEFAULT_NODE_ATTR);
277     break;
278   case iro_Load:
279   case iro_Store:
280     xfprintf (F, "\"%R\"", n);
281     xfprintf (F, DEFAULT_NODE_ATTR);
282     break;
283   case iro_Alloc:
284     xfprintf (F, "\"%I\" ", n->op->name);
285     xfprintf (F, DEFAULT_NODE_ATTR);
286     break;
287   case iro_Sel:
288     assert(n->attr.s.ent->kind == k_entity);
289     xfprintf (F, "\"%I ", n->op->name);
290     xfprintf (F, "%s\" ", id_to_str(n->attr.s.ent->name));
291     /*  xdoesn't work for some reason.
292         fprintf (F, "\"%I %I\" ", n->op->name, n->attr.s.ent); */
293     xfprintf (F, DEFAULT_NODE_ATTR);
294     break;
295   case iro_SymConst:
296     assert(get_kind(get_SymConst_type(n)) == k_type_class);
297     /* assert(n->attr.i.type->kind == k_type_class); */
298     assert(get_class_ident((type_class *)get_SymConst_type(n)));
299     /* assert(n->attr.i.type->clss->name); */
300     xfprintf (F, "\"%s ", id_to_str(get_class_ident((type_class *)get_SymConst_type(n))));
301     /* xfprintf (F, "\"%s ", id_to_str(n->attr.i.type->name)); */
302     /* doesn't work for some reason. */
303     /* xfprintf (F, "\"%N\" ", n->attr.i.type); */
304     switch (n->attr.i.num){
305     case type_tag:
306       xfprintf (F, "tag\" ");
307       break;
308     case size:
309       xfprintf (F, "size\" ");
310       break;
311     default:
312       assert(0);
313       break;
314     }
315     xfprintf (F, DEFAULT_NODE_ATTR);
316     break;
317   case iro_Sync:
318     xfprintf (F, "\"%I\" ", n->op->name);
319     xfprintf (F, DEFAULT_NODE_ATTR " color: green");
320     break;
321   case iro_Bad:
322     xfprintf (F, "\"%I%I\" ", n->op->name, n->mode->name);
323     xfprintf (F, DEFAULT_NODE_ATTR);
324     break;
325   default:
326     xfprintf (F, "\"%I%I\" ", n->op->name, n->mode->name);
327   }
328   xfprintf (F, "}\n");          /* footer */
329 }
330
331
332 /* dump the edge to the block this node belongs to */
333 void
334 dump_ir_block_edge(ir_node *n)  {
335   if (is_no_Block(n))
336     xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
337                 BLOCK_EDGE_ATTR "}\n", n, get_nodes_Block(n));
338 }
339
340
341 /* dump edges to our inputs */
342 void
343 dump_ir_data_edges(ir_node *n)  {
344   int i;
345
346   for (i = 0; i < get_irn_arity(n); i++) {
347     assert(get_irn_n(n, i));
348     xfprintf (F, "edge: {sourcename: \"%p\" targetname: \"%p\"",
349               n, get_irn_n(n, i));
350     fprintf (F, " label: \"%d\"", i+1);
351     fprintf (F, "}\n");
352   }
353 }
354
355 /* dumps the edges between nodes and their type or entity attributes. */
356 void dump_node2type_edges (ir_node *n, void *env)
357 {
358   assert(n);
359
360   switch (get_irn_opcode(n)) {
361   case iro_SymConst:
362     if (   (get_SymConst_kind(n) == type_tag)
363         || (get_SymConst_kind(n) == size))
364       xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
365                 NODE2TYPE_EDGE_ATTR "}\n", n, get_SymConst_type(n));
366     break;
367   case iro_Sel:
368     xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
369               NODE2TYPE_EDGE_ATTR "}\n", n, get_Sel_entity(n));
370     break;
371   case iro_Call:
372     xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
373               NODE2TYPE_EDGE_ATTR "}\n", n, get_Call_type(n));
374     break;
375   case iro_Alloc:
376     xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
377               NODE2TYPE_EDGE_ATTR "}\n", n, get_Alloc_type(n));
378     break;
379   case iro_Free:
380     printf(" in irdum\n");
381     xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
382               NODE2TYPE_EDGE_ATTR "}\n", n, get_Free_type(n));
383     break;
384   default:
385     break;
386   }
387 }
388
389
390 /* dumps a type or entity and it's edges. */
391 void
392 dump_type_info (type_or_ent *tore, void *env) {
393   int i = 0;  /* to shutup gcc */
394
395   /* dump this type or entity */
396   xfprintf (F, "node: {title: \"%p\" ", tore);
397   xfprintf (F, DEFAULT_TYPE_ATTRIBUTE);
398   xfprintf (F, "label: ");
399
400   switch (get_kind(tore)) {
401   case k_entity:
402     {
403       entity *ent = (entity *)tore;
404       xfprintf (F, "\"ent %I\"}\n", get_entity_ident(ent));
405       xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
406                 " label: \"owner\" "
407                 TYPE_EDGE_ATTR "}\n", tore, get_entity_owner(ent));
408       xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
409                 " label: \"type\" "
410                 TYPE_EDGE_ATTR "}\n", tore, get_entity_type(ent));
411     }
412     break;
413   case k_type_class:
414     {
415       type_class *type = (type_class *)tore;
416       xfprintf (F, "\"class %I\"}\n", get_class_ident(type));
417       /* edges !!!??? */
418     }
419     break;
420   case k_type_strct:
421     {
422       type_strct *type = (type_strct *)tore;
423       xfprintf (F, "\"strct %I\"}\n", get_strct_ident(type));
424       /* edges !!!??? */
425     }
426     break;
427   case k_type_method:
428     {
429       type_method *type = (type_method *)tore;
430       xfprintf (F, "\"meth %I\"}\n", get_method_ident(type));
431       for (i = 0; i < get_method_arity(type); i++)
432         xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
433                   " label: \"param %d\" " TYPE_EDGE_ATTR "}\n",
434                   tore, get_method_param_type(type, i), i);
435       for (i = 0; i < get_method_n_res(type); i++)
436         xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
437                   " label: \"res %d\" " TYPE_EDGE_ATTR "}\n",
438                   tore, get_method_res_type(type, i), i);
439     }
440     break;
441   case k_type_union:
442     {
443       type_union *type = (type_union *)tore;
444       xfprintf (F, "\"union %I\"}\n", get_union_ident(type));
445       /* edges !!!??? */
446     }
447     break;
448   case k_type_array:
449     {
450       type_array *type = (type_array *)tore;
451       xfprintf (F, "\"array %I\"}\n", get_array_ident(type));
452       xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
453                 TYPE_EDGE_ATTR "}\n", tore, get_array_element_type(type), i);
454     }
455     break;
456   case k_type_enumeration:
457     {
458       type_enumeration *type = (type_enumeration *)tore;
459       xfprintf (F, "\"enum %I\"}\n", get_enumeration_ident(type));
460     }
461     break;
462   case k_type_pointer:
463     {
464       type_pointer *type = (type_pointer *)tore;
465       xfprintf (F, "\"ptr %I\"}\n", get_pointer_ident(type));
466       xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
467                 TYPE_EDGE_ATTR "}\n", tore,
468                 get_pointer_points_to_type(type), i);
469     }
470     break;
471   case k_type_primitive:
472     {
473       type_primitive *type = (type_primitive *)tore;
474       xfprintf (F, "\"prim %I, mode %I\"}\n", get_primitive_ident(type),
475                 get_mode_ident(get_primitive_mode(type)));
476     }
477     break;
478   default:
479     break;
480   }
481
482 }
483
484 /************************************************************************/
485 /* open and close vcg file                                              */
486 /************************************************************************/
487
488 void vcg_open (ir_graph *irg, char *suffix) {
489   char *fname;  /* filename to put the vcg information in */
490   const char *cp;
491   ident *id;
492   int len;
493
494   /** open file for vcg graph */
495   id    = get_entity_ld_name (irg->ent);
496
497   len   = id_to_strlen (id);
498   cp    = id_to_str (id);
499   fname = malloc (len + 5 + strlen(suffix));
500   strcpy (fname, cp);      /* copy the filename */
501   strcat (fname, suffix);  /* append file suffix */
502   strcat (fname, ".vcg");  /* append the .vcg suffix */
503
504   F = fopen (fname, "w");  /* open file for writing */
505   if (!F) {
506     panic ("cannot open %s for writing (%m)", fname);  /* not reached */
507   }
508
509   /* print header */
510   xfprintf (F,
511             "graph: { title: \"ir graph of %s\"\n"
512             "display_edge_labels: yes\n"
513             "layoutalgorithm: mindepth\n"
514             "manhattan_edges: yes\n"
515             "port_sharing: no\n"
516             "orientation: bottom_to_top\n"
517             "classname 1: \"Data\"\n"
518             "classname 2: \"Block\"\n", cp);
519
520   xfprintf (F, "\n");           /* a separator */
521 }
522
523 void
524 vcg_close () {
525   xfprintf (F, "}\n");  /* print footer */
526   fclose (F);           /* close vcg file */
527 }
528
529 /************************************************************************/
530 /* routines to dump a graph, blocks as conventional nodes.              */
531 /************************************************************************/
532
533 void
534 dump_whole_node (ir_node *n, void* env) {
535   dump_node(n);
536   dump_ir_block_edge(n);
537   dump_ir_data_edges(n);
538 }
539
540 void
541 dump_ir_graph (ir_graph *irg)
542 {
543   vcg_open (irg, "");
544
545   /* walk over the graph */
546   irg_walk(irg->end, dump_whole_node, NULL, NULL);
547
548   vcg_close();
549 }
550
551 /***********************************************************************/
552 /* the following routines dump the nodes as attached to the blocks.    */
553 /***********************************************************************/
554
555 void
556 dump_ir_blocks_nodes (ir_node *n, void *env) {
557   ir_node *block = (ir_node *)env;
558
559   if (is_no_Block(n) && get_nodes_Block(n) == block) {
560     dump_node(n);
561     dump_ir_data_edges(n);
562   }
563 }
564
565 void
566 dump_ir_block (ir_node *block, void *env) {
567   ir_graph *irg = (ir_graph *)env;
568
569   if (get_irn_opcode(block) == iro_Block) {
570     /* This is a block. So dump the vcg information to make a block. */
571     xfprintf(F, "graph: { title: \"%p\"  label: \"", block);
572 #ifdef DEBUG_libfirm
573     xfprintf (F, "%ld", get_irn_node_nr(block));
574 #elif
575     xfprintf (F, "%I", block->op->name);
576 #endif
577     xfprintf(F, "\" status:clustered color:lightyellow \n");
578     /* dump the blocks edges */
579     dump_ir_data_edges(block);
580
581     /* dump the nodes that go into the block */
582     irg_walk(irg->end, dump_ir_blocks_nodes, NULL, block);
583
584     /* Close the vcg information for the block */
585     xfprintf(F, "}\n\n");
586   }
587 }
588
589 void
590 dump_ir_block_graph (ir_graph *irg)
591 {
592   vcg_open (irg, "");
593
594   /* walk over the blocks in the graph */
595   irg_block_walk(irg->end, dump_ir_block, NULL, irg);
596
597   vcg_close();
598 }
599
600
601 /***********************************************************************/
602 /* the following routines dump a control flow graph                    */
603 /***********************************************************************/
604
605
606 void
607 dump_block_to_cfg (ir_node *block, void *env) {
608   int i;
609   ir_node *pred;
610
611   if (get_irn_opcode(block) == iro_Block) {
612     /* This is a block. Dump a node for the block. */
613     xfprintf (F, "node: {title: \"%p\" label: \"%I\"}", block,
614               block->op->name);
615     /* Dump the edges */
616     for ( i = 0; i < get_Block_n_cfgpreds(block); i++) {
617       pred = get_nodes_Block(skip_Proj(get_Block_cfgpred(block, i)));
618       xfprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" }\n",
619                 block, pred);
620     }
621   }
622 }
623
624 void
625 dump_cfg (ir_graph *irg)
626 {
627   vcg_open (irg, "-cfg");
628
629   /* walk over the blocks in the graph */
630   irg_block_walk(irg->end, dump_block_to_cfg, NULL, NULL);
631
632   vcg_close();
633 }
634
635
636 /***********************************************************************/
637 /* the following routine dumps all type information                    */
638 /***********************************************************************/
639
640
641 void
642 dump_type_graph (ir_graph *irg)
643 {
644   vcg_open (irg, "-type");
645
646   /* walk over the blocks in the graph */
647   type_walk(irg, dump_type_info, NULL, NULL);
648
649   vcg_close();
650 }
651
652
653 /***********************************************************************/
654 /* dumps a graph with type information                                 */
655 /***********************************************************************/
656
657
658 void
659 dump_ir_graph_w_types (ir_graph *irg)
660 {
661   vcg_open (irg, "-all");
662
663   /* dump common ir graph */
664   /*  irg_block_walk(irg->end, dump_ir_block, NULL, irg); */
665   irg_walk(irg->end, dump_whole_node, NULL, NULL);
666   /* dump type info */
667   type_walk(irg, dump_type_info, NULL, NULL);
668   /* dump edges from graph to type info */
669   irg_walk(irg->end, dump_node2type_edges, NULL, NULL);
670
671   vcg_close();
672 }