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