More doxygen docu
[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 /* $Id$ */
10
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14
15 # include <string.h>
16 # include <stdlib.h>
17
18 # include "irnode_t.h"
19 # include "irgraph_t.h"
20 # include "entity_t.h"
21 # include "irop_t.h"
22 # include "firm_common_t.h"
23
24 # include "irdump.h"
25
26 # include "irgwalk.h"
27 # include "typewalk.h"
28 # include "irprog.h"
29 # include "tv_t.h"
30 # include "type_or_entity.h"
31 # include "irouts.h"
32 # include "irdom.h"
33 # include "irloop.h"
34
35 # include "panic.h"
36 # include "array.h"
37 # include "pmap.h"
38
39 # include "exc.h"
40
41
42 /* Attributes of nodes */
43 #define PRINT_DEFAULT_NODE_ATTR
44 #define DEFAULT_NODE_ATTR ""
45 #define DEFAULT_TYPE_ATTRIBUTE ""
46
47 /* Attributes of edges between Firm nodes */
48 #define BLOCK_EDGE_ATTR "class: 2 priority: 2 linestyle: dotted"
49 #define CF_EDGE_ATTR    "color: red"
50 #define MEM_EDGE_ATTR   "color: blue"
51 #define DOMINATOR_EDGE_ATTR "color: red"
52
53 #define BACK_EDGE_ATTR "linestyle: dashed "
54
55 /* Attributes of edges between Firm nodes and type/entity nodes */
56 #define NODE2TYPE_EDGE_ATTR "class: 2 priority: 2 linestyle: dotted"
57
58 /* Attributes of edges in type/entity graphs. */
59 #define TYPE_METH_NODE_ATTR  "color: lightyellow"
60 #define TYPE_CLASS_NODE_ATTR "color: green"
61 #define TYPE_DESCRIPTION_NODE_ATTR "color: lightgreen"
62 #define ENTITY_NODE_ATTR     "color: yellow"
63 #define ENT_TYPE_EDGE_ATTR   "class: 3 label: \"type\" color: red"
64 #define ENT_OWN_EDGE_ATTR    "class: 4 label: \"owner\" color: black"
65 #define METH_PAR_EDGE_ATTR   "class: 5 label: \"param %d\" color: green"
66 #define METH_RES_EDGE_ATTR   "class: 6 label: \"res %d\" color: green"
67 #define TYPE_SUPER_EDGE_ATTR "class: 7 label: \"supertype\" color: red"
68 #define UNION_EDGE_ATTR      "class: 8 label: \"component\" color: blue"
69 #define PTR_PTS_TO_EDGE_ATTR "class: 9 label: \"points to\" color:green"
70 #define ARR_ELT_TYPE_EDGE_ATTR "class: 10 label: \"arr elt tp\" color:green"
71 #define ARR_ENT_EDGE_ATTR    "class: 10 label: \"arr ent\" color: green"
72 #define ENT_OVERWRITES_EDGE_ATTR "class: 11 label: \"overwrites\" color:red"
73 #define ENT_VALUE_EDGE_ATTR "label: \"value %d\""
74 #define ENT_CORR_EDGE_ATTR "label: \"value %d corresponds to \" "
75 #define TYPE_MEMBER_EDGE_ATTR "class: 12 label: \"member\" color:blue"
76
77
78 #if DEBUG_libfirm && NODEID_AS_LABEL
79 #define PRINT_NODEID(X) fprintf(F, "n%ld", get_irn_node_nr(X))
80 #define PRINT_TYPEID(X) fprintf(F, "t%ld", get_type_nr(X))
81 #define PRINT_ENTID(X) fprintf(F, "e%ld", get_entity_nr(X))
82 #define PRINT_IRGID(X) fprintf(F,"g%ld", get_irg_graph_nr(X))
83 #else
84 #define PRINT_NODEID(X) fprintf(F, "%p", X)
85 #define PRINT_TYPEID(X) fprintf(F, "%p", X)
86 #define PRINT_ENTID(X) fprintf(F, "%p", X)
87 #define PRINT_IRGID(X) fprintf(F,"%p",X)
88 #endif
89
90 #define PRINT_TYPE_TYPE_EDGE(S,T,ATR,...) {fprintf (F, "edge: { sourcename:\""); PRINT_TYPEID(S); fprintf (F, "\" targetname: \""); PRINT_TYPEID(T);  fprintf (F,"\" " ATR "}\n",##__VA_ARGS__);}
91 #define PRINT_TYPE_ENT_EDGE(S,T,ATR,...)  {fprintf (F, "edge: { sourcename:\""); PRINT_TYPEID(S); fprintf (F, "\" targetname: \""); PRINT_ENTID(T);  fprintf (F,"\" " ATR "}\n",##__VA_ARGS__);}
92 #define PRINT_ENT_ENT_EDGE(S,T,ATR,...)   {fprintf (F, "edge: { sourcename:\""); PRINT_ENTID(S); fprintf (F, "\" targetname: \""); PRINT_ENTID(T);  fprintf (F,"\" " ATR "}\n",##__VA_ARGS__);}
93 #define PRINT_ENT_TYPE_EDGE(S,T,ATR,...)  {fprintf (F, "edge: { sourcename:\""); PRINT_ENTID(S); fprintf (F, "\" targetname: \""); PRINT_TYPEID(T);  fprintf (F,"\" " ATR "}\n",##__VA_ARGS__);}
94 #define PRINT_NODE_TYPE_EDGE(S,T,ATR,...)  {fprintf (F, "edge: { sourcename:\""); PRINT_NODEID(S); fprintf (F, "\" targetname: \""); PRINT_TYPEID(T);  fprintf (F,"\" " ATR "}\n",##__VA_ARGS__);}
95 #define PRINT_NODE_ENT_EDGE(S,T,ATR,...)   {fprintf (F, "edge: { sourcename:\""); PRINT_NODEID(S); fprintf (F, "\" targetname: \""); PRINT_ENTID(T);  fprintf (F,"\" " ATR "}\n",##__VA_ARGS__);}
96 #define PRINT_ENT_NODE_EDGE(S,T,ATR,...)   {fprintf (F, "edge: { sourcename:\""); PRINT_ENTID(S); fprintf (F, "\" targetname: \""); PRINT_NODEID(T);  fprintf (F,"\" " ATR "}\n",##__VA_ARGS__);}
97
98
99 /* A suffix to manipulate the file name. */
100 char *dump_file_suffix = NULL;
101
102 /* file to dump to */
103 static FILE *F;
104
105 /* A compiler option to turn off edge labels */
106 int edge_label = 1;
107 /* A compiler option to turn off dumping values of constant entities */
108 int const_entities = 1;
109 /* A compiler option to dump the keep alive edges */
110 int dump_keepalive = 0;
111 /* Compiler options to dump analysis information in dump_ir_graph */
112 int dump_out_edge_flag = 0;
113 int dump_dominator_information_flag = 0;
114 int dump_loop_information_flag = 0;
115 int dump_const_local = 0;
116
117 static INLINE bool dump_const_local_set(void) {
118   if (!dump_out_edge_flag && !dump_loop_information_flag)
119     return dump_const_local;
120   else
121     return false;
122 }
123
124 /* A global variable to record output of the Bad node. */
125 static int Bad_dumped;
126
127 static void dump_ir_blocks_nodes (ir_node *n, void *env);
128 static void dump_whole_node(ir_node *n, void* env);
129
130 /*******************************************************************/
131 /* routines to dump information about a single node                */
132 /*******************************************************************/
133
134
135
136 static INLINE void
137 dump_node_opcode (ir_node *n)
138 {
139   char buf[1024];
140   int res;
141
142   assert(n && n->op);
143
144   /* Const */
145   if (n->op->code == iro_Const) {
146     res = tarval_snprintf(buf, sizeof(buf), n->attr.con);
147     assert(res < sizeof(buf) && "buffer to small for tarval_snprintf");
148     fprintf(F, buf);
149
150   /* SymConst */
151   } else if (n->op->code == iro_SymConst) {
152     if (get_SymConst_kind(n) == linkage_ptr_info) {
153       /* don't use get_SymConst_ptr_info as it mangles the name. */
154       fprintf (F, "SymC %s", id_to_str(n->attr.i.tori.ptrinfo));
155     } else {
156       assert(get_kind(get_SymConst_type(n)) == k_type);
157       assert(get_type_ident(get_SymConst_type(n)));
158       fprintf (F, "SymC %s ", id_to_str(get_type_ident(get_SymConst_type(n))));
159       if (get_SymConst_kind(n) == type_tag)
160         fprintf (F, "tag");
161       else
162         fprintf (F, "size");
163     }
164
165   /* Filter */
166   } else if (n->op->code == iro_Filter && !interprocedural_view) {
167     fprintf(F, "Proj'");
168
169   /* all others */
170   } else {
171     fprintf (F, "%s", id_to_str(get_irn_opident(n)));
172   }
173 }
174
175 static INLINE void
176 dump_node_mode (ir_node *n)
177 {
178   switch (n->op->code) {
179   case iro_Phi:
180   case iro_Const:
181   case iro_Id:
182   case iro_Proj:
183   case iro_Filter:
184   case iro_Conv:
185   case iro_Tuple:
186   case iro_Add:
187   case iro_Sub:
188   case iro_Mul:
189   case iro_And:
190   case iro_Or:
191   case iro_Eor:
192   case iro_Shl:
193   case iro_Shr:
194   case iro_Abs:
195   case iro_Cmp:
196     fprintf (F, "%s", id_to_str(get_mode_ident(n->mode)));
197     break;
198   default:
199     ;
200   }
201 }
202
203 static INLINE void
204 dump_node_nodeattr (ir_node *n)
205 {
206   switch (n->op->code) {
207   case iro_Start:
208     if (false && interprocedural_view) {
209       fprintf (F, "%s", id_to_str(get_entity_ident(get_irg_ent(current_ir_graph))));
210     }
211     break;
212   case iro_Proj:
213     if (n->in[1]->op->code == iro_Cmp) {
214       fprintf (F, "%s", get_pnc_string(n->attr.proj));
215     } else {
216       fprintf (F, "%ld", n->attr.proj);
217     }
218     break;
219   case iro_Filter:
220     fprintf (F, "%ld", n->attr.filter.proj);
221     break;
222   case iro_Sel: {
223     assert(get_kind(get_Sel_entity(n)) == k_entity);
224     fprintf (F, "%s", id_to_str(get_entity_ident(get_Sel_entity(n))));
225     } break;
226   default:
227     ;
228   } /* end switch */
229 }
230
231 static INLINE void
232 dump_node_vcgattr (ir_node *n)
233 {
234   switch (n->op->code) {
235   case iro_Start:
236   case iro_EndReg:
237     /* fall through */
238   case iro_EndExcept:
239     /* fall through */
240   case iro_End:
241     fprintf (F, "color: blue");
242     break;
243   case iro_Block:
244     fprintf (F, "color: lightyellow");
245     break;
246   case iro_Phi:
247     fprintf (F, "color: green");
248     break;
249   case iro_Const:
250   case iro_Proj:
251   case iro_Filter:
252   case iro_Tuple:
253     fprintf (F, "color: yellow");
254     break;
255   default:
256     PRINT_DEFAULT_NODE_ATTR;
257   }
258 }
259
260 static bool pred_in_wrong_graph(ir_node *n, int pos, pmap *irgmap) {
261   ir_node *block = (is_Block(n)) ? n : get_nodes_Block(n);
262
263   if (irgmap &&
264       ((get_irn_op(n) == op_Filter) || (get_irn_op(n) == op_Block))) {
265     ir_node *pred = skip_Proj(get_Block_cfgpred(block, pos));
266     if (is_ip_cfop(pred)) {
267       ir_graph *irg = get_ip_cfop_irg(pred);
268       if (pmap_find(irgmap, irg) == NULL) return true;
269     }
270   }
271
272   return false;
273 }
274
275
276 static INLINE
277 bool is_constlike_node(ir_node *n) {
278   ir_op *op = get_irn_op(n);
279   return (op == op_Const || op == op_Bad || op == op_SymConst);
280 }
281
282
283 static void dump_const_node_local(ir_node *n, pmap *irgmap) {
284   int i;
285   if (!dump_const_local_set()) return;
286   /* Use visited flag to avoid outputting nodes twice.
287      initialize it first. */
288   for (i = 0; i < get_irn_arity(n); i++) {
289     ir_node *con = get_irn_n(n, i);
290     if (is_constlike_node(con)) {
291       if (pred_in_wrong_graph(n, i, irgmap)) continue; /* pred not dumped */
292       set_irn_visited(con, get_irg_visited(current_ir_graph)-1);
293     }
294   }
295   for (i = 0; i < get_irn_arity(n); i++) {
296     ir_node *con = get_irn_n(n, i);
297     if (is_constlike_node(con) && irn_not_visited(con)) {
298       if (pred_in_wrong_graph(n, i, irgmap)) continue; /* pred not dumped */
299       mark_irn_visited(con);
300       /* Generate a new name for the node by appending the names of
301          n and const. */
302       fprintf (F, "node: {title: \""); PRINT_NODEID(n); PRINT_NODEID(con);
303       fprintf(F, "\" label: \"");
304       dump_node_opcode(con);
305       dump_node_mode (con);
306       fprintf (F, " ");
307       dump_node_nodeattr(con);
308 #ifdef DEBUG_libfirm
309       fprintf (F, " %ld", get_irn_node_nr(con));
310 #endif
311       fprintf (F, "\" ");
312       dump_node_vcgattr(con);
313       fprintf (F, "}\n");
314     }
315   }
316 }
317
318 static void
319 dump_node (ir_node *n, pmap * map) {
320   if (dump_const_local_set() && is_constlike_node(n)) return;
321
322   /* dump this node */
323   fprintf (F, "node: {title: \""); PRINT_NODEID(n); fprintf(F, "\" label: \"");
324
325   dump_node_opcode(n);
326   dump_node_mode (n);
327   fprintf (F, " ");
328   dump_node_nodeattr(n);
329 #ifdef DEBUG_libfirm
330   fprintf (F, " %ld", get_irn_node_nr(n));
331 #endif
332   fprintf (F, "\" ");
333   dump_node_vcgattr(n);
334   fprintf (F, "}\n");
335   dump_const_node_local(n, map);
336 }
337
338 static void
339 dump_ir_node (ir_node *n)
340 {
341   char buf[1024];
342   int res;
343
344   /* dump this node */
345   fprintf (F, "node: {title: \""); PRINT_NODEID(n); fprintf(F, "\" label: ");
346
347   switch (n->op->code) {  /* node label */
348   case iro_Start:
349     fprintf (F, "\"%s\" color: blue ", id_to_str(get_irn_opident(n)));
350     PRINT_DEFAULT_NODE_ATTR;
351      break;
352   case iro_EndReg:
353     /* fall through */
354   case iro_EndExcept:
355     /* fall through */
356   case iro_End:
357     fprintf (F, "\"%s\" color: blue ", id_to_str(get_irn_opident(n)));
358     PRINT_DEFAULT_NODE_ATTR;
359     break;
360   case iro_Block:
361     fprintf (F, "\"%s\" color: lightyellow ", id_to_str(get_irn_opident(n)));
362     PRINT_DEFAULT_NODE_ATTR;
363     break;
364   case iro_Phi:
365     fprintf (F, "\"%s%s\" color: green", id_to_str(get_irn_opident(n)), id_to_str(get_irn_modeident(n)));
366     if (get_irn_modecode(n) == irm_M)
367       fprintf (F, DEFAULT_NODE_ATTR " color: green");
368     else
369       PRINT_DEFAULT_NODE_ATTR;
370     break;
371   case iro_Const:
372     res = tarval_snprintf(buf, sizeof(buf), n->attr.con);
373     assert(res < sizeof(buf) && "buffer to small for tarval_snprintf");
374
375     fprintf (F, "\"%s%s\" color: yellow ", buf, id_to_str(get_irn_modeident(n)));
376     PRINT_DEFAULT_NODE_ATTR;
377     break;
378   case iro_Proj:
379     if (n->in[1]->op->code == iro_Cmp) {
380       fprintf (F, "\"%s%s %s\" color: yellow", id_to_str(get_irn_opident(n)), id_to_str(get_irn_modeident(n)),
381                 get_pnc_string(n->attr.proj));
382     } else {
383       fprintf (F, "\"%s%s %ld\"", id_to_str(get_irn_opident(n)), id_to_str(get_irn_modeident(n)), n->attr.proj);
384     }
385     PRINT_DEFAULT_NODE_ATTR;
386     break;
387   case iro_Filter:
388     fprintf (F, "\"%s%s %ld\"", id_to_str(get_irn_opident(n)), id_to_str(get_irn_modeident(n)), n->attr.filter.proj);
389     PRINT_DEFAULT_NODE_ATTR;
390     break;
391 #if 0
392   case iro_Id:
393     /* fall through */
394   case iro_Conv:
395     /* fall through */
396   case iro_Tuple:
397     /* fall through */
398   case iro_Add:
399     /* fall through */
400   case iro_Sub:
401     /* fall through */
402   case iro_Mul:
403     /* fall through */
404   case iro_Quot:
405     /* fall through */
406   case iro_DivMod:
407     /* fall through */
408   case iro_Div:
409     /* fall through */
410   case iro_Mod:
411     /* fall through */
412   case iro_And:
413     /* fall through */
414   case iro_Or:
415     /* fall through */
416   case iro_Eor:
417     /* fall through */
418   case iro_Shl:
419     /* fall through */
420   case iro_Shr:
421     /* fall through */
422   case iro_Abs:
423     /* fall through */
424   case iro_Cmp:
425     /* fall through */
426   case iro_Raise:
427     /* fall through */
428   case iro_Unknown:
429     /* fall through */
430   case iro_Bad:
431     /* fall through */
432   case iro_Load:
433     /* fall through */
434   case iro_Store:
435     fprintf (F, "\"%s%s\"", id_to_str(get_irn_opident(n)), id_to_str(get_irn_modeident(n)));
436     PRINT_DEFAULT_NODE_ATTR;
437     break;
438 #endif
439   case iro_Jmp:
440     /* fall through */
441   case iro_Break:
442     /* fall through */
443   case iro_Cond:
444     /* fall through */
445   case iro_Call:
446     /* fall through */
447   case iro_CallBegin:
448     /* fall through */
449   case iro_Return:
450     /* fall through */
451   case iro_Alloc:
452     fprintf (F, "\"%s\"", id_to_str(get_irn_opident(n)));
453     PRINT_DEFAULT_NODE_ATTR;
454     break;
455   case iro_Sel:
456     assert(get_kind(get_Sel_entity(n)) == k_entity);
457     fprintf (F, "\"%s ", id_to_str(get_irn_opident(n)));
458     fprintf (F, "%s", id_to_str(get_entity_ident(get_Sel_entity(n))));
459     PRINT_DEFAULT_NODE_ATTR;
460     break;
461   case iro_SymConst:
462     assert(get_kind(get_SymConst_type(n)) == k_type);
463     assert(get_type_ident(get_SymConst_type(n)));
464     fprintf (F, "\"%s ", get_type_name(get_SymConst_type(n)));
465     switch (n->attr.i.num){
466     case type_tag:
467       fprintf (F, "tag\" ");
468       break;
469     case size:
470       fprintf (F, "size\" ");
471       break;
472     default:
473       assert(0);
474       break;
475     }
476     PRINT_DEFAULT_NODE_ATTR;
477     break;
478   case iro_Sync:
479     fprintf (F, "\"%s\" ", id_to_str(get_irn_opident(n)));
480     fprintf (F, DEFAULT_NODE_ATTR " color: green");
481     break;
482   default:
483     fprintf (F, "\"%s%s\" ", id_to_str(get_irn_opident(n)), id_to_str(get_irn_modeident(n)));
484   }
485   fprintf (F, "}\n");           /* footer */
486 }
487
488
489 /* dump the edge to the block this node belongs to */
490 static void
491 dump_ir_block_edge(ir_node *n)  {
492   if (dump_const_local_set() && is_constlike_node(n)) return;
493   if (is_no_Block(n)) {
494     fprintf (F, "edge: { sourcename: \"");
495     PRINT_NODEID(n);
496     fprintf (F, "\" targetname: \"");
497     PRINT_NODEID(get_nodes_Block(n));
498     fprintf (F, "\" "   BLOCK_EDGE_ATTR "}\n");
499   }
500 }
501
502 static void print_edge_vcgattr(ir_node *from, int to) {
503   assert(from);
504
505   if (is_backedge(from, to)) fprintf (F, BACK_EDGE_ATTR);
506
507   switch (get_irn_opcode(from)) {
508   case iro_Block:
509     fprintf (F, CF_EDGE_ATTR);
510     break;
511   case iro_Start:   break;
512   case iro_End:
513     if (to >= 0) {
514       if (get_irn_mode(get_End_keepalive(from, to)) == mode_BB)
515         fprintf (F, CF_EDGE_ATTR);
516       if (get_irn_mode(get_End_keepalive(from, to)) == mode_X)
517         fprintf (F, MEM_EDGE_ATTR);
518     }
519     break;
520   case iro_EndReg: break;
521   case iro_EndExcept: break;
522   case iro_Jmp:     break;
523   case iro_Break:   break;
524   case iro_Cond:    break;
525   case iro_Return:
526   case iro_Raise:
527     if (to == 0) fprintf (F, MEM_EDGE_ATTR);
528     break;
529   case iro_Const:   break;
530   case iro_SymConst:break;
531   case iro_Sel:
532   case iro_Call:
533     if (to == 0) fprintf (F, MEM_EDGE_ATTR);
534     break;
535   case iro_CallBegin: break;
536   case iro_Add:     break;
537   case iro_Sub:     break;
538   case iro_Minus:   break;
539   case iro_Mul:     break;
540   case iro_Quot:
541   case iro_DivMod:
542   case iro_Div:
543   case iro_Mod:
544     if (to == 0) fprintf (F, MEM_EDGE_ATTR);
545     break;
546   case iro_Abs:    break;
547   case iro_And:    break;
548   case iro_Or:     break;
549   case iro_Eor:    break;
550   case iro_Shl:    break;
551   case iro_Shr:    break;
552   case iro_Shrs:   break;
553   case iro_Rot:    break;
554   case iro_Cmp:    break;
555   case iro_Conv:   break;
556   case iro_Phi:
557     if (get_irn_modecode(from) == irm_M) fprintf (F, MEM_EDGE_ATTR);
558     break;
559   case iro_Load:
560   case iro_Store:
561   case iro_Alloc:
562   case iro_Free:
563     if (to == 0) fprintf (F, MEM_EDGE_ATTR);
564     break;
565   case iro_Sync:
566     fprintf (F, MEM_EDGE_ATTR);
567     break;
568   case iro_Tuple:  break;
569   case iro_Proj:
570   case iro_Filter:
571     switch (get_irn_modecode(from)) {
572     case irm_X:
573       fprintf (F, CF_EDGE_ATTR);
574       break;
575     case irm_M:
576       fprintf (F, MEM_EDGE_ATTR);
577       break;
578     default: break;
579     }
580     break;
581   case iro_Bad:    break;
582   case iro_Unknown: break;
583   case iro_Id:     break;
584   default:
585     ;
586   }
587 }
588
589 /* dump edges to our inputs */
590 static void
591 dump_ir_data_edges(ir_node *n)  {
592   int i, visited = get_irn_visited(n);
593
594   if ((get_irn_op(n) == op_End) && (!dump_keepalive))
595     return;
596
597   for (i = 0; i < get_irn_arity(n); i++) {
598     ir_node * pred = get_irn_n(n, i);
599     assert(pred);
600     if ((interprocedural_view && get_irn_visited(pred) < visited))
601       continue; /* pred not dumped */
602     if (is_backedge(n, i))
603       fprintf (F, "backedge: {sourcename: \"");
604     else
605       fprintf (F, "edge: {sourcename: \"");
606     PRINT_NODEID(n);
607     fprintf (F, "\" targetname: \"");
608     if ((dump_const_local_set()) && is_constlike_node(pred))
609       PRINT_NODEID(n);
610     PRINT_NODEID(pred);
611     fprintf (F, "\"");
612     fprintf (F, " label: \"%d\" ", i);
613     print_edge_vcgattr(n, i);
614     fprintf (F, "}\n");
615   }
616 }
617
618 /* dump out edges */
619 static void
620 dump_out_edge (ir_node *n, void* env) {
621   int i;
622   for (i = 0; i < get_irn_n_outs(n); i++) {
623     assert(get_irn_out(n, i));
624     fprintf (F, "edge: {sourcename: \"");
625     PRINT_NODEID(n);
626     fprintf (F, "\" targetname: \"");
627     PRINT_NODEID(get_irn_out(n, i));
628     fprintf (F, "\" color: red linestyle: dashed");
629     fprintf (F, "}\n");
630   }
631 }
632
633 static INLINE void
634 dump_loop_node_edge (ir_loop *loop, int i) {
635   assert(loop);
636   fprintf (F, "edge: {sourcename: \"%p\" targetname: \"", loop);
637   PRINT_NODEID(get_loop_node(loop, i));
638   fprintf (F, "\" color: green");
639   fprintf (F, "}\n");
640 }
641
642 static
643 void dump_loops (ir_loop *loop) {
644   int i;
645   /* dump this loop node */
646   fprintf (F, "node: {title: \"%p\" label: \"loop %d, %d sons, %d nodes\" }\n",
647             loop, get_loop_depth(loop), get_loop_n_sons(loop), get_loop_n_nodes(loop));
648   /* dump edges to nodes in loop -- only if it is a real loop */
649   if (get_loop_depth(loop) != 0) {
650     for (i = 0; i < get_loop_n_nodes(loop); i++) {
651       dump_loop_node_edge(loop, i);
652     }
653   }
654   for (i = 0; i < get_loop_n_sons(loop); i++) {
655     dump_loops(get_loop_son(loop, i));
656   }
657 }
658
659 static INLINE
660 void dump_loop_info(ir_graph *irg) {
661   ir_graph *rem = current_ir_graph;
662   current_ir_graph = irg;
663
664   if (get_irg_loop(irg))
665     dump_loops(get_irg_loop(irg));
666
667   current_ir_graph = rem;
668 }
669
670
671 /* dumps the edges between nodes and their type or entity attributes. */
672 static void dump_node2type_edges (ir_node *n, void *env)
673 {
674   assert(n);
675
676   switch (get_irn_opcode(n)) {
677   case iro_Const :
678     /* @@@ some consts have an entity */
679     break;
680   case iro_SymConst:
681     if (   (get_SymConst_kind(n) == type_tag)
682            || (get_SymConst_kind(n) == size))
683     {
684             PRINT_NODE_TYPE_EDGE(n,get_SymConst_type(n),NODE2TYPE_EDGE_ATTR);
685     }
686     break;
687   case iro_Sel: {
688             PRINT_NODE_ENT_EDGE(n,get_Sel_entity(n),NODE2TYPE_EDGE_ATTR);
689     } break;
690   case iro_Call: {
691             PRINT_NODE_TYPE_EDGE(n,get_Call_type(n),NODE2TYPE_EDGE_ATTR);
692     } break;
693   case iro_Alloc: {
694             PRINT_NODE_TYPE_EDGE(n,get_Alloc_type(n),NODE2TYPE_EDGE_ATTR);
695     } break;
696   case iro_Free: {
697             PRINT_NODE_TYPE_EDGE(n,get_Free_type(n),NODE2TYPE_EDGE_ATTR);
698     } break;
699   default:
700     break;
701   }
702 }
703
704
705 static void dump_const_expression(ir_node *value) {
706   ir_graph *rem = current_ir_graph;
707   int rem_dump_const_local = dump_const_local;
708   dump_const_local = 0;
709   current_ir_graph = get_const_code_irg();
710   irg_walk(value, dump_ir_blocks_nodes, NULL, get_nodes_Block(value));
711   /* Decrease visited flag so that we walk with the same flag for the next
712      expresssion.  This guarantees that we don't dump the same node twice,
713      as for const expressions cse is performed to save memory. */
714   set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph) -1);
715   current_ir_graph = rem;
716   dump_const_local = rem_dump_const_local;
717 }
718
719
720 static void print_type_info(type *tp) {
721   if (get_type_state(tp) == layout_undefined) {
722     fprintf(F, "state: layout_undefined\n");
723   } else {
724     fprintf(F, "state: layout_fixed,\n");
725   }
726   if (get_type_mode(tp))
727     fprintf(F, "mode: %s,\n", id_to_str(get_mode_ident(get_type_mode(tp))));
728   fprintf(F, "size: %dB,\n", get_type_size(tp));
729 }
730
731
732 static void print_typespecific_info(type *tp) {
733   switch (get_type_tpop_code(tp)) {
734   case tpo_class:
735     {
736       if(existent == get_class_peculiarity(tp))
737         fprintf (F, " " TYPE_CLASS_NODE_ATTR);
738       else
739         fprintf (F, " " TYPE_DESCRIPTION_NODE_ATTR);
740     } break;
741   case tpo_struct:
742     {
743       fprintf (F, " " TYPE_METH_NODE_ATTR);
744     } break;
745   case tpo_method:
746     {
747     } break;
748   case tpo_union:
749     {
750     } break;
751   case tpo_array:
752     {
753     } break;
754   case tpo_enumeration:
755     {
756     } break;
757   case tpo_pointer:
758     {
759     } break;
760   case tpo_primitive:
761     {
762     } break;
763   default: break;
764   } /* switch type */
765 }
766
767 static void print_type_node(type *tp) {
768   fprintf (F, "node: {title: \"");
769   PRINT_TYPEID(tp);
770   fprintf (F, "\" label: \"%s %s\"", id_to_str(get_type_tpop_nameid(tp)), id_to_str(get_type_ident(tp)));
771   fprintf (F, "info1: \"");
772   print_type_info(tp);
773   fprintf (F, "\"");
774   print_typespecific_info(tp);
775   fprintf (F, "}\n");
776 }
777
778 void dump_entity_node(entity *ent) {
779   fprintf (F, "node: {title: \"");
780   PRINT_ENTID(ent);
781   fprintf (F, "\"" DEFAULT_TYPE_ATTRIBUTE);
782   fprintf (F, "label: ");
783   fprintf (F, "\"ent %s\" " ENTITY_NODE_ATTR , id_to_str(get_entity_ident(ent)));
784   fprintf (F, "\n info1:\"\nallocation:  ");
785   switch (get_entity_allocation(ent)) {
786     case dynamic_allocated:   fprintf (F, "dynamic allocated");   break;
787     case automatic_allocated: fprintf (F, "automatic allocated"); break;
788     case static_allocated:    fprintf (F, "static allocated");    break;
789     case parameter_allocated: fprintf (F, "parameter allocated"); break;
790   }
791   fprintf (F, "\nvisibility:  ");
792   switch (get_entity_visibility(ent)) {
793     case local:              fprintf (F, "local");             break;
794     case external_visible:   fprintf (F, "external_visible");  break;
795     case external_allocated: fprintf (F, "external_allocate"); break;
796   }
797   fprintf (F, "\nvariability: ");
798   switch (get_entity_variability(ent)) {
799     case uninitialized: fprintf (F, "uninitialized");break;
800     case initialized:   fprintf (F, "initialized");  break;
801     case part_constant: fprintf (F, "part_constant");break;
802     case constant:      fprintf (F, "constant");     break;
803   }
804   fprintf (F, "\nvolatility:  ");
805   switch (get_entity_volatility(ent)) {
806     case non_volatile: fprintf (F, "non_volatile"); break;
807     case is_volatile:  fprintf (F, "is_volatile");  break;
808   }
809   fprintf (F, "\npeculiarity: ");
810   switch (get_entity_peculiarity(ent)) {
811     case description: fprintf (F, "description"); break;
812     case inherited:   fprintf (F, "inherited");   break;
813     case existent:    fprintf (F, "existent");    break;
814   }
815   fprintf(F, "\nname:    %s\nld_name: %s", id_to_str(get_entity_ident(ent)), id_to_str(get_entity_ld_ident(ent)));
816   fprintf(F, "\noffset:  %d", get_entity_offset(ent));
817   if (is_method_type(get_entity_type(ent))) {
818     if (get_entity_irg(ent))   /* can be null */
819       { fprintf (F, "\nirg = "); PRINT_IRGID(get_entity_irg(ent)); }
820     else
821       { fprintf (F, "\nirg = NULL"); }
822   }
823   fprintf(F, "\"\n}\n");
824 }
825
826 /* dumps a type or entity and it's edges. */
827 static void
828 dump_type_info (type_or_ent *tore, void *env) {
829   int i = 0;  /* to shutup gcc */
830
831   /* dump this type or entity */
832
833   switch (get_kind(tore)) {
834   case k_entity:
835     {
836       entity *ent = (entity *)tore;
837       ir_node *value;
838       /* The node */
839       dump_entity_node(ent);
840       /* The Edges */
841       /* skip this to reduce graph.  Member edge of type is parallel to this edge. *
842       fprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
843                 ENT_OWN_EDGE_ATTR "}\n", ent, get_entity_owner(ent));*/
844       PRINT_ENT_TYPE_EDGE(ent, get_entity_type(ent), ENT_TYPE_EDGE_ATTR);
845       if(is_class_type(get_entity_owner(ent))) {
846         for(i = 0; i < get_entity_n_overwrites(ent); i++){
847           PRINT_ENT_ENT_EDGE(ent, get_entity_overwrites(ent, i), ENT_OVERWRITES_EDGE_ATTR);
848         }
849       }
850       /* attached subgraphs */
851       if (const_entities && (get_entity_variability(ent) != uninitialized)) {
852         if (is_atomic_entity(ent)) {
853           value = get_atomic_ent_value(ent);
854           if (value) {
855             PRINT_ENT_NODE_EDGE(ent, value, ENT_VALUE_EDGE_ATTR, i);
856             /*
857             fprintf (F, "edge: { sourcename: \"%p\" targetname: \"", GET_ENTID(ent));
858             PRINT_NODEID(value);
859             fprintf(F, "\" " ENT_VALUE_EDGE_ATTR "\"}\n");
860             */
861             dump_const_expression(value);
862           }
863         }
864         if (is_compound_entity(ent)) {
865           for (i = 0; i < get_compound_ent_n_values(ent); i++) {
866             value = get_compound_ent_value(ent, i);
867             if (value) {
868               PRINT_ENT_NODE_EDGE(ent,value,ENT_VALUE_EDGE_ATTR,i);
869               dump_const_expression(value);
870               PRINT_ENT_ENT_EDGE(ent, get_compound_ent_value_member(ent, i), ENT_CORR_EDGE_ATTR, i);
871               /*
872                 fprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
873                 ENT_CORR_EDGE_ATTR  "}\n", GET_ENTID(ent),
874                 get_compound_ent_value_member(ent, i), i);
875               */
876             }
877           }
878         }
879       }
880     } break;
881   case k_type:
882     {
883       type *tp = (type *)tore;
884       print_type_node(tp);
885       /* and now the edges */
886       switch (get_type_tpop_code(tp)) {
887       case tpo_class:
888         {
889           for (i=0; i < get_class_n_supertypes(tp); i++) {
890             PRINT_TYPE_TYPE_EDGE(tp,get_class_supertype(tp, i),TYPE_SUPER_EDGE_ATTR);
891           }
892
893           for (i=0; i < get_class_n_members(tp); i++) {
894             PRINT_TYPE_ENT_EDGE(tp,get_class_member(tp, i),TYPE_MEMBER_EDGE_ATTR);
895           }
896         } break;
897       case tpo_struct:
898         {
899           for (i=0; i < get_struct_n_members(tp); i++) {
900             PRINT_TYPE_ENT_EDGE(tp,get_struct_member(tp, i),TYPE_MEMBER_EDGE_ATTR);
901           }
902         } break;
903       case tpo_method:
904         {
905           for (i = 0; i < get_method_n_params(tp); i++)
906           {
907                   PRINT_TYPE_TYPE_EDGE(tp,get_method_param_type(tp, i),METH_PAR_EDGE_ATTR,i);
908           }
909           for (i = 0; i < get_method_n_ress(tp); i++)
910           {
911                   PRINT_TYPE_TYPE_EDGE(tp,get_method_res_type(tp, i),METH_RES_EDGE_ATTR,i);
912           }
913         } break;
914       case tpo_union:
915         {
916           for (i = 0; i < get_union_n_members(tp); i++)
917           {
918                   PRINT_TYPE_ENT_EDGE(tp,get_union_member(tp, i),UNION_EDGE_ATTR);
919           }
920         } break;
921       case tpo_array:
922         {
923                   PRINT_TYPE_TYPE_EDGE(tp,get_array_element_type(tp),ARR_ELT_TYPE_EDGE_ATTR);
924                   PRINT_TYPE_ENT_EDGE(tp,get_array_element_entity(tp),ARR_ENT_EDGE_ATTR);
925         } break;
926       case tpo_enumeration:
927         {
928         } break;
929       case tpo_pointer:
930         {
931                   PRINT_TYPE_TYPE_EDGE(tp,get_pointer_points_to_type(tp), PTR_PTS_TO_EDGE_ATTR);
932         } break;
933       case tpo_primitive:
934         {
935         } break;
936       default: break;
937       } /* switch type */
938     }
939     break; /* case k_type */
940   default:
941     {
942       printf(" *** irdump,  dump_type_info(l.%i), faulty type.\n", __LINE__);
943     } break;
944   } /* switch kind_or_entity */
945 }
946
947 /* dumps a class type node and a superclass edge.
948    If env != null dumps entities of classes and overwrites edges. */
949 static void
950 dump_class_hierarchy_node (type_or_ent *tore, void *env) {
951   int i = 0;  /* to shutup gcc */
952
953   /* dump this type or entity */
954   switch (get_kind(tore)) {
955   case k_entity: {
956     entity *ent = (entity *)tore;
957     if (get_entity_owner(ent) == get_glob_type()) break;
958     if ((env) && is_class_type(get_entity_owner(ent))) {
959       /* The node */
960       dump_entity_node(ent);
961       /* The edges */
962       PRINT_TYPE_ENT_EDGE(get_entity_owner(ent),ent,TYPE_MEMBER_EDGE_ATTR);
963       for(i = 0; i < get_entity_n_overwrites(ent); i++)
964       {
965       PRINT_ENT_ENT_EDGE(get_entity_overwrites(ent, i),ent, ENT_OVERWRITES_EDGE_ATTR);
966       }
967     }
968   } break; /* case k_entity */
969   case k_type:
970     {
971       type *tp = (type *)tore;
972       if (tp == get_glob_type()) break;
973       switch (get_type_tpop_code(tp)) {
974         case tpo_class: {
975           print_type_node(tp);
976           /* and now the edges */
977           for (i=0; i < get_class_n_supertypes(tp); i++)
978           {
979                   PRINT_TYPE_TYPE_EDGE(tp,get_class_supertype(tp, i),TYPE_SUPER_EDGE_ATTR);
980           }
981         } break;
982         default: break;
983       } /* switch type */
984     }
985     break; /* case k_type */
986   default:
987     {
988       printf(" *** irdump,  dump_class_hierarchy_node(l.%i), faulty type.\n", __LINE__);
989     } break;
990   } /* switch kind_or_entity */
991 }
992
993 /************************************************************************/
994 /* open and close vcg file                                              */
995 /************************************************************************/
996
997 static void vcg_open (ir_graph *irg, char *suffix) {
998   char *fname;  /* filename to put the vcg information in */
999   const char *cp;
1000   ident *id;
1001   int len;
1002   char label[4];
1003   entity *ent;
1004
1005   /** open file for vcg graph */
1006   ent = get_irg_ent(irg);
1007   id    = ent->ld_name ? ent->ld_name : ent->name;
1008   /* Don't use get_entity_ld_ident (ent) as it computes the mangled name! */
1009   len   = id_to_strlen (id);
1010   cp    = id_to_str (id);
1011   if (dump_file_suffix)
1012     fname = malloc (len + 5 + strlen(suffix) + strlen(dump_file_suffix));
1013   else
1014     fname = malloc (len + 5 + strlen(suffix));
1015   strncpy (fname, cp, len);      /* copy the filename */
1016   fname[len] = '\0';
1017   if (dump_file_suffix) strcat (fname, dump_file_suffix);  /* append file suffix */
1018   strcat (fname, suffix);  /* append file suffix */
1019   strcat (fname, ".vcg");   /* append the .vcg suffix */
1020   F = fopen (fname, "w");   /* open file for writing */
1021   if (!F) {
1022     panic ("cannot open %s for writing (%m)", fname);  /* not reached */
1023   }
1024
1025   if (edge_label) {
1026     strcpy(label, "yes");
1027   } else {
1028     strcpy (label, "no");
1029   }
1030
1031   /* print header */
1032   fprintf (F,
1033             "graph: { title: \"ir graph of %s\"\n"
1034             "display_edge_labels: %s\n"
1035             "layoutalgorithm: mindepth\n"
1036             "manhattan_edges: yes\n"
1037             "port_sharing: no\n"
1038             "orientation: bottom_to_top\n"
1039             "classname 1: \"Data\"\n"
1040             "classname 2: \"Block\"\n"
1041             "classname 3: \"Entity type\""
1042             "classname 4: \"Entity owner\""
1043             "classname 5: \"Method Param\""
1044             "classname 6: \"Method Res\""
1045             "classname 7: \"Super\""
1046             "classname 8: \"Union\""
1047             "classname 9: \"Points-to\""
1048             "classname 10: \"Array Element Type\""
1049             "classname 11: \"Overwrites\""
1050             "classname 12: \"Member\""
1051             , cp, label);
1052
1053   fprintf (F, "\n");            /* a separator */
1054 }
1055
1056 static void vcg_open_name (const char *name) {
1057   char *fname;  /* filename to put the vcg information in */
1058   int len;
1059   char label[4];
1060
1061   /** open file for vcg graph */
1062   len   = strlen(name);
1063   fname = malloc (len + 5);
1064   if (dump_file_suffix)
1065     fname = malloc (len + 5 + strlen(dump_file_suffix));
1066   else
1067     fname = malloc (len + 5);
1068   strcpy (fname, name);    /* copy the filename */
1069   if (dump_file_suffix) strcat (fname, dump_file_suffix);
1070   strcat (fname, ".vcg");  /* append the .vcg suffix */
1071   F = fopen (fname, "w");  /* open file for writing */
1072   if (!F) {
1073     panic ("cannot open %s for writing (%m)", fname);  /* not reached */
1074   }
1075
1076   if (edge_label) {
1077     strcpy(label, "yes");
1078   } else {
1079     strcpy (label, "no");
1080   }
1081
1082   /* print header */
1083   fprintf (F,
1084             "graph: { title: \"ir graph of %s\"\n"
1085             "display_edge_labels: %s\n"
1086             "layoutalgorithm: mindepth\n"
1087             "manhattan_edges: yes\n"
1088             "port_sharing: no\n"
1089             "orientation: bottom_to_top\n"
1090             "classname 1: \"Data\"\n"
1091             "classname 2: \"Block\"\n"
1092             "classname 3: \"Entity type\"\n"
1093             "classname 4: \"Entity owner\"\n"
1094             "classname 5: \"Method Param\"\n"
1095             "classname 6: \"Method Res\"\n"
1096             "classname 7: \"Super\"\n"
1097             "classname 8: \"Union\"\n"
1098             "classname 9: \"Points-to\"\n"
1099             "classname 10: \"Array Element Type\"\n"
1100             "classname 11: \"Overwrites\"\n"
1101             "classname 12: \"Member\"\n"
1102             , name, label);
1103
1104   fprintf (F, "\n");            /* a separator */
1105 }
1106
1107 static void
1108 vcg_close (void) {
1109   fprintf (F, "}\n");  /* print footer */
1110   fclose (F);           /* close vcg file */
1111 }
1112
1113 /************************************************************************/
1114 /* routines to dump a graph, blocks as conventional nodes.              */
1115 /************************************************************************/
1116
1117 static int node_floats(ir_node *n) {
1118   return ((get_op_pinned(get_irn_op(n)) == floats) &&
1119           (get_irg_pinned(current_ir_graph) == floats));
1120 }
1121
1122 static void
1123 dump_whole_node (ir_node *n, void* env) {
1124   dump_node(n, NULL);
1125   if (!node_floats(n)) dump_ir_block_edge(n);
1126   dump_ir_data_edges(n);
1127 }
1128
1129 void
1130 dump_ir_graph (ir_graph *irg)
1131 {
1132   ir_graph *rem;
1133   rem = current_ir_graph;
1134   current_ir_graph = irg;
1135
1136   vcg_open (irg, "");
1137
1138   /* walk over the graph */
1139   /* dump_whole_node must be called in post visiting predecessors */
1140   irg_walk(irg->end, NULL, dump_whole_node, NULL);
1141
1142   /* dump the out edges in a separate walk */
1143   if ((dump_out_edge_flag) && (get_irg_outs_state(irg) != no_outs)) {
1144     irg_out_walk(irg->start, dump_out_edge, NULL, NULL);
1145   }
1146
1147   vcg_close();
1148
1149   current_ir_graph = rem;
1150 }
1151
1152 /***********************************************************************/
1153 /* the following routines dump the nodes as attached to the blocks.    */
1154 /***********************************************************************/
1155
1156 static void
1157 dump_ir_blocks_nodes (ir_node *n, void *env) {
1158   ir_node *block = (ir_node *)env;
1159
1160   if (is_no_Block(n) && get_nodes_Block(n) == block && !node_floats(n)) {
1161     dump_node(n, NULL);
1162     dump_ir_data_edges(n);
1163   }
1164   if (get_irn_op(n) == op_Bad)
1165     Bad_dumped = 1;
1166 }
1167
1168 static void
1169 dump_ir_block (ir_node *block, void *env) {
1170   ir_graph *irg = (ir_graph *)env;
1171
1172   if (get_irn_opcode(block) == iro_Block) {
1173
1174     /* This is a block. So dump the vcg information to make a block. */
1175     fprintf(F, "graph: { title: \"");
1176         PRINT_NODEID(block);
1177         fprintf(F, "\"  label: \"");
1178 #ifdef DEBUG_libfirm
1179     fprintf (F, "%ld", get_irn_node_nr(block));
1180 #else
1181     fprintf (F, "%s", id_to_str(block->op->name));
1182 #endif
1183     if (exc_normal != get_Block_exc (block))
1184       fprintf (F, " (%s)", exc_to_string (get_Block_exc (block)));
1185
1186     fprintf(F, "\" status:clustered color:%s \n",
1187              get_Block_matured (block) ? "yellow" : "red");
1188     /* dump the blocks edges */
1189     dump_ir_data_edges(block);
1190
1191     /* dump the nodes that go into the block */
1192     irg_walk(irg->end, dump_ir_blocks_nodes, NULL, block);
1193
1194     /* Close the vcg information for the block */
1195     fprintf(F, "}\n\n");
1196     dump_const_node_local(block, NULL);
1197   }
1198 }
1199
1200
1201 static void
1202 dump_blockless_nodes (ir_node *n, void *env) {
1203   if (is_no_Block(n) && get_irn_op(get_nodes_Block(n)) == op_Bad) {
1204     dump_node(n, NULL);
1205     dump_ir_data_edges(n);
1206     dump_ir_block_edge(n);
1207     if (get_irn_op(n) == op_Bad) Bad_dumped = 1;
1208     return;
1209   }
1210   if (node_floats(n)) {
1211     dump_node(n, NULL);
1212     dump_ir_data_edges(n);
1213     if (get_irn_op(n) == op_Bad) Bad_dumped = 1;
1214   }
1215 }
1216
1217 static void dump_ir_block_graph_2  (ir_graph *irg)
1218 {
1219   Bad_dumped = 0;
1220   /* walk over the blocks in the graph */
1221   irg_block_walk(irg->end, dump_ir_block, NULL, irg);
1222
1223   /* dump all nodes that are not in a Block */
1224   irg_walk(irg->end, dump_blockless_nodes, NULL, NULL);
1225
1226   /* dump the Bad node */
1227   if (!Bad_dumped)
1228     dump_node(get_irg_bad(irg), NULL);
1229 }
1230
1231 void
1232 dump_ir_block_graph (ir_graph *irg)
1233 {
1234   ir_graph *rem;
1235   rem = current_ir_graph;
1236   current_ir_graph = irg;
1237
1238   vcg_open (irg, "");
1239
1240   dump_ir_block_graph_2 (irg);
1241
1242   if (dump_loop_information_flag) dump_loop_info(irg);
1243
1244   vcg_close();
1245   current_ir_graph = rem;
1246 }
1247
1248
1249 /***********************************************************************/
1250 /* the following routines dump a control flow graph                    */
1251 /***********************************************************************/
1252
1253
1254 static void
1255 dump_block_to_cfg (ir_node *block, void *env) {
1256   int i;
1257   ir_node *pred;
1258
1259   if (get_irn_opcode(block) == iro_Block) {
1260     /* This is a block. Dump a node for the block. */
1261     fprintf (F, "node: {title:\""); PRINT_NODEID(block);
1262     fprintf (F, "\" label: \"%s ", id_to_str(block->op->name)); PRINT_NODEID(block);
1263
1264         if (exc_normal != get_Block_exc (block))
1265           fprintf (F, " (%s)", exc_to_string (get_Block_exc (block)));
1266
1267     fprintf (F, "\" ");
1268     if (dump_dominator_information_flag)
1269       fprintf(F, "info1:\"dom depth %d\"", get_Block_dom_depth(block));
1270     fprintf (F, "}\n");
1271     /* Dump the edges */
1272     for ( i = 0; i < get_Block_n_cfgpreds(block); i++)
1273       if (get_irn_op(skip_Proj(get_Block_cfgpred(block, i))) != op_Bad) {
1274         pred = get_nodes_Block(skip_Proj(get_Block_cfgpred(block, i)));
1275         fprintf (F, "edge: { sourcename: \"");
1276         PRINT_NODEID(block);
1277         fprintf (F, "\" targetname: \"");
1278         PRINT_NODEID(pred);
1279         fprintf (F, "\" }\n");
1280       }
1281
1282     /* Dump dominator edge */
1283     if (dump_dominator_information_flag && get_Block_idom(block)) {
1284       pred = get_Block_idom(block);
1285       fprintf (F, "edge: { sourcename: \"");
1286       PRINT_NODEID(block);
1287       fprintf (F, "\" targetname: \"");
1288       PRINT_NODEID(pred);
1289       fprintf (F, "\" " DOMINATOR_EDGE_ATTR "}\n");
1290     }
1291   }
1292 }
1293
1294 void
1295 dump_cfg (ir_graph *irg)
1296 {
1297   ir_graph *rem = current_ir_graph;
1298   int ddif = dump_dominator_information_flag;
1299   current_ir_graph = irg;
1300   vcg_open (irg, "-cfg");
1301
1302   if (get_irg_dom_state(irg) != dom_consistent)
1303     dump_dominator_information_flag = 0;
1304
1305   /* walk over the blocks in the graph */
1306   irg_block_walk(irg->end, dump_block_to_cfg, NULL, NULL);
1307   dump_ir_node (irg->bad);
1308
1309   dump_dominator_information_flag = ddif;
1310   vcg_close();
1311   current_ir_graph = rem;
1312 }
1313
1314
1315 /***********************************************************************/
1316 /* the following routine dumps all type information reachable from an  */
1317 /* irg                                                                 */
1318 /***********************************************************************/
1319
1320
1321 void
1322 dump_type_graph (ir_graph *irg)
1323 {
1324   ir_graph *rem;
1325   rem = current_ir_graph;
1326   current_ir_graph = irg;
1327
1328   vcg_open (irg, "-type");
1329
1330   /* walk over the blocks in the graph */
1331   type_walk_irg(irg, dump_type_info, NULL, NULL);
1332   /* The walker for the const code can be called several times for the
1333      same (sub) experssion.  So that no nodes are dumped several times
1334      we decrease the visited flag of the corresponding graph after each
1335      walk.  So now increase it finally. */
1336   inc_irg_visited(get_const_code_irg());
1337
1338   vcg_close();
1339   current_ir_graph = rem;
1340 }
1341
1342 /***********************************************************************/
1343 /* the following routine dumps all type information                    */
1344 /***********************************************************************/
1345
1346
1347 void
1348 dump_all_types (void)
1349 {
1350   vcg_open_name ("All_types");
1351   type_walk(dump_type_info, NULL, NULL);
1352   inc_irg_visited(get_const_code_irg());
1353   vcg_close();
1354 }
1355
1356 void
1357 dump_class_hierarchy (bool entities)
1358 {
1359   vcg_open_name ("class_hierarchy");
1360   if (entities)
1361     type_walk(dump_class_hierarchy_node, NULL, (void *)1);
1362   else
1363     type_walk(dump_class_hierarchy_node, NULL, NULL);
1364   vcg_close();
1365 }
1366
1367 /***********************************************************************/
1368 /* dumps a graph with type information                                 */
1369 /***********************************************************************/
1370
1371
1372 void
1373 dump_ir_graph_w_types (ir_graph *irg)
1374 {
1375   ir_graph *rem;
1376   rem = current_ir_graph;
1377   current_ir_graph = irg;
1378
1379   vcg_open (irg, "-all");
1380
1381   /* dump common ir graph */
1382   irg_walk(irg->end, dump_whole_node, NULL, NULL);
1383   /* dump type info */
1384   type_walk_irg(irg, dump_type_info, NULL, NULL);
1385   inc_irg_visited(get_const_code_irg());
1386   /* dump edges from graph to type info */
1387   irg_walk(irg->end, dump_node2type_edges, NULL, NULL);
1388
1389   vcg_close();
1390   current_ir_graph = rem;
1391 }
1392
1393 void
1394 dump_ir_block_graph_w_types (ir_graph *irg)
1395 {
1396   ir_graph *rem;
1397   rem = current_ir_graph;
1398   current_ir_graph = irg;
1399
1400   vcg_open (irg, "-all");
1401
1402   /* dump common blocked ir graph */
1403   dump_ir_block_graph_2(irg);
1404   /* dump type info */
1405   type_walk_irg(irg, dump_type_info, NULL, NULL);
1406   inc_irg_visited(get_const_code_irg());
1407   /* dump edges from graph to type info */
1408   irg_walk(irg->end, dump_node2type_edges, NULL, NULL);
1409
1410   vcg_close();
1411   current_ir_graph = rem;
1412 }
1413
1414 /***********************************************************************/
1415 /* dumps all graphs with the graph-dumper passed. Possible dumpers:    */
1416 /*  dump_ir_graph                                                      */
1417 /*  dump_ir_block_graph                                                */
1418 /*  dump_cfg                                                           */
1419 /*  dump_type_graph                                                    */
1420 /*  dump_ir_graph_w_types                                              */
1421 /***********************************************************************/
1422 void dump_all_ir_graphs (dump_graph_func *dump_graph) {
1423   int i;
1424   for (i=0; i < get_irp_n_irgs(); i++) {
1425     dump_graph(get_irp_irg(i));
1426   }
1427 }
1428
1429
1430 /* To turn off display of edge labels.  Edge labels offen cause xvcg to
1431    abort with a segmentation fault. */
1432 void turn_off_edge_labels(void) {
1433   edge_label = 0;
1434 }
1435
1436
1437 void dump_consts_local(bool b) {
1438   dump_const_local = b;
1439 }
1440
1441 void turn_off_constant_entity_values(void) {
1442   const_entities = 0;
1443 }
1444
1445 void dump_keepalive_edges(bool b) {
1446   dump_keepalive = b;
1447 }
1448
1449 void dump_out_edges(void) {
1450   dump_out_edge_flag = 1;
1451 }
1452
1453 void dump_dominator_information(void) {
1454   dump_dominator_information_flag = 1;
1455 }
1456
1457 void dump_loop_information(void) {
1458   dump_loop_information_flag = 1;
1459 }
1460
1461 void dont_dump_loop_information(void) {
1462   dump_loop_information_flag = 0;
1463 }
1464
1465 static void clear_link(ir_node * node, void * env) {
1466   set_irn_link(node, NULL);
1467 }
1468
1469 static void collect_blocks_floats_cg(ir_node * node, pmap * map) {
1470   if (is_Block(node)
1471       || node_floats(node)
1472       || get_irn_op(node) == op_Bad
1473       || get_irn_op(node) == op_Unknown) {
1474     pmap_entry * entry = pmap_find(map, current_ir_graph);
1475     if (entry) {
1476       ARR_APP1(ir_node *, (ir_node **) entry->value, node);
1477     } else {
1478       ir_node ** arr = NEW_ARR_F(ir_node *, 1);
1479       arr[0] = node;
1480       pmap_insert(map, current_ir_graph, arr);
1481     }
1482   } else {
1483     ir_node * block = get_nodes_Block(node);
1484     set_irn_link(node, get_irn_link(block));
1485     set_irn_link(block, node);
1486   }
1487 }
1488
1489
1490 static void dump_cg_ir_block(ir_node * block, void * env) {
1491   ir_node *node;
1492   pmap *irgmap = (pmap *)env;
1493   assert(is_Block(block));
1494   fprintf(F, "graph: { title: \"");
1495   PRINT_NODEID(block);
1496   fprintf(F, "\"  label: \"");
1497 #ifdef DEBUG_libfirm
1498   fprintf (F, "%ld", get_irn_node_nr(block));
1499 #else
1500   fprintf (F, "%s", id_to_str(block->op->name));
1501 #endif
1502   if (exc_normal != get_Block_exc(block)) {
1503     fprintf (F, " (%s)", exc_to_string (get_Block_exc(block)));
1504   }
1505
1506   fprintf(F, "\" status:clustered color:%s \n",
1507            get_Block_matured(block) ? "yellow" : "red");
1508
1509   /* dump the blocks edges */
1510   dump_ir_data_edges(block);
1511
1512   /* dump the nodes that go into the block */
1513   for (node = get_irn_link(block); node; node = get_irn_link(node)) {
1514     dump_node(node, irgmap);
1515     dump_ir_data_edges(node);
1516   }
1517
1518   /* Close the vcg information for the block */
1519   fprintf(F, "}\n\n");
1520 }
1521
1522 static void d_cg_block_graph(ir_graph *irg, ir_node **arr, pmap *irgmap) {
1523   int i;
1524
1525   fprintf(F, "graph: { title: \"%p\" label: \"%s\" status:clustered color:white \n",
1526            irg, id_to_str(get_entity_ident(get_irg_ent(irg))));
1527
1528   for (i = ARR_LEN(arr) - 1; i >= 0; --i) {
1529     ir_node * node = arr[i];
1530     if (is_Block(node)) {
1531       /* Dumps the block and all the nodes in the block , which are to
1532          be found in Block->link. */
1533       dump_cg_ir_block(node, irgmap);
1534     } else {
1535       /* Nodes that are not in a Block. */
1536       dump_node(node, NULL);
1537       dump_ir_data_edges(node);
1538     }
1539   }
1540   /* Close the vcg information for the irg */
1541   fprintf(F, "}\n\n");
1542 }
1543
1544 /* dump interprocedural graph with surrounding methods */
1545 void dump_cg_block_graph(ir_graph * irg) {
1546   pmap * map = pmap_create();
1547   pmap * map2 = pmap_create();
1548   pmap_entry * entry;
1549
1550   vcg_open(irg, "");
1551
1552   irg_walk_graph(irg, clear_link, (irg_walk_func *) collect_blocks_floats_cg, map);
1553   for (entry = pmap_first(map); entry; entry = pmap_next(map))
1554     pmap_insert(map2, entry->key, entry->value);
1555   for (entry = pmap_first(map); entry; entry = pmap_next(map)) {
1556     d_cg_block_graph(entry->key, entry->value, map2);
1557     DEL_ARR_F(entry->value);
1558   }
1559
1560   pmap_destroy(map);
1561   pmap_destroy(map2);
1562
1563   if (dump_loop_information_flag) dump_loop_info(irg);
1564   vcg_close();
1565 }
1566
1567 static void collect_node(ir_node * node, void *env) {
1568   if (is_Block(node)
1569       || node_floats(node)
1570       || get_irn_op(node) == op_Bad
1571       || get_irn_op(node) == op_Unknown) {
1572     ir_node ** arr = (ir_node **) get_irg_link(current_ir_graph);
1573     ARR_APP1(ir_node *, arr, node);
1574     set_irg_link(current_ir_graph, arr);    /* arr is an l-value, APP_ARR might change it! */
1575   } else {
1576     ir_node * block = get_nodes_Block(node);
1577     set_irn_link(node, get_irn_link(block));
1578     set_irn_link(block, node);
1579   }
1580 }
1581
1582 /* Links all nodes that have the block field set in the link field of
1583    the block.  Adds all blocks and nodes not associated with a block
1584    in a array in irg->link. */
1585 static void collect_nodes(void) {
1586   int i;
1587   for (i = 0; i < get_irp_n_irgs(); i++)
1588     set_irg_link(get_irp_irg(i), NEW_ARR_F(ir_node *, 0));
1589   cg_walk(clear_link, collect_node, NULL);
1590 }
1591
1592 static void dump_graphs(void) {
1593   int i;
1594   for (i = 0; i < get_irp_n_irgs(); i++) {
1595     current_ir_graph = get_irp_irg(i);
1596     d_cg_block_graph(current_ir_graph, get_irg_link(current_ir_graph), NULL);
1597   }
1598 }
1599
1600 /* Dump all irgs in interprocedural view to a single file. */
1601 void dump_all_cg_block_graph(void) {
1602   int i;
1603   int rem_view = interprocedural_view;
1604   interprocedural_view = 1;
1605   vcg_open_name ("All_graphs");
1606
1607   collect_nodes();
1608   dump_graphs();
1609
1610   if (dump_loop_information_flag)
1611     for (i = 0; i < get_irp_n_irgs(); i++)
1612       dump_loop_info(get_irp_irg(i));
1613
1614   vcg_close();
1615   interprocedural_view = rem_view;
1616 }
1617
1618 /* dump interprocedural block graph with surrounding methods */
1619 void dump_cg_graph(ir_graph * irg) {
1620   pmap * map = pmap_create();
1621   pmap * map2 = pmap_create(); /* We can not iterate in the same map twice! */
1622   pmap_entry * entry;
1623   vcg_open(irg, "");
1624
1625   irg_walk_graph(irg, clear_link, (irg_walk_func *) collect_blocks_floats_cg, map);
1626   for (entry = pmap_first(map); entry; entry = pmap_next(map))
1627     pmap_insert(map2, entry->key, entry->value);
1628   for (entry = pmap_first(map); entry; entry = pmap_next(map)) {
1629     ir_node ** arr = entry->value;
1630     int i;
1631     ident * irg_ident = get_entity_ident(get_irg_ent(entry->key));
1632
1633     fprintf(F, "graph: { title: \"%s\" label: \"%s\" status:clustered color:white \n",
1634              id_to_str(irg_ident), id_to_str(irg_ident));
1635
1636     for (i = ARR_LEN(arr) - 1; i >= 0; --i) {
1637       ir_node * node = arr[i];
1638       dump_node(node, map2);
1639       dump_ir_data_edges(node);
1640       if (is_Block(node)) {
1641         for (node = get_irn_link(node); node; node = get_irn_link(node)) {
1642           dump_node(node, map2);
1643           dump_ir_block_edge(node);
1644           dump_ir_data_edges(node);
1645         }
1646       }
1647     }
1648
1649     DEL_ARR_F(arr);
1650
1651     /* Close the vcg information for the irg */
1652     fprintf(F, "}\n\n");
1653   }
1654
1655   pmap_destroy(map);
1656   pmap_destroy(map2);
1657
1658   vcg_close();
1659 }