do not use current_ir_graph in irdump.c
[libfirm] / ir / ir / irdump.c
1 /*
2  * Copyright (C) 1995-2011 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   Write vcg representation of firm to file.
23  * @author  Martin Trapp, Christian Schaefer, Goetz Lindenmaier, Hubert Schmidt,
24  *          Matthias Braun
25  */
26 #include "config.h"
27
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdbool.h>
32 #include <errno.h>
33
34 #include "list.h"
35 #include "pset.h"
36
37 #include "irnode_t.h"
38 #include "irgraph_t.h"
39 #include "irprog_t.h"
40 #include "entity_t.h"
41 #include "irop.h"
42
43 #include "irdump_t.h"
44 #include "irpass_t.h"
45
46 #include "irgwalk.h"
47 #include "tv_t.h"
48 #include "irouts.h"
49 #include "iredges.h"
50 #include "irdom.h"
51 #include "irloop_t.h"
52 #include "callgraph.h"
53 #include "irextbb_t.h"
54 #include "irhooks.h"
55 #include "dbginfo_t.h"
56 #include "irtools.h"
57 #include "irprintf.h"
58
59 #include "irverify.h"
60
61 #include "error.h"
62 #include "array.h"
63 #include "pmap.h"
64 #include "obst.h"
65 #include "pset.h"
66 #include "util.h"
67
68 typedef struct pns_lookup {
69         long       nr;      /**< the proj number */
70         const char *name;   /**< the name of the Proj */
71 } pns_lookup_t;
72
73 typedef struct proj_lookup {
74         unsigned           code;      /**< the opcode of the Proj predecessor */
75         unsigned           num_data;  /**< number of data entries */
76         const pns_lookup_t *data;     /**< the data */
77 } proj_lookup_t;
78
79 #include "gen_irdump.c.inl"
80
81 /** Dump only irgs with names that start with this prefix. */
82 static ident *dump_file_filter_id = NULL;
83
84 static ir_dump_flags_t flags =
85         ir_dump_flag_blocks_as_subgraphs |
86         ir_dump_flag_keepalive_edges |
87         ir_dump_flag_ld_names |
88         ir_dump_flag_back_edges |
89         ir_dump_flag_consts_local |
90         ir_dump_flag_analysed_types |
91         ir_dump_flag_entities_in_hierarchy |
92         ir_dump_flag_number_label;
93
94 static ird_color_t overrule_nodecolor = ird_color_default_node;
95
96 /** The vcg node attribute hook. */
97 static dump_node_vcgattr_func dump_node_vcgattr_hook = NULL;
98 /** The vcg edge attribute hook. */
99 static dump_edge_vcgattr_func dump_edge_vcgattr_hook = NULL;
100 /** The vcg dump block edge hook */
101 static dump_node_edge_func dump_block_edge_hook = NULL;
102 /** The vcg dump node edge hook. */
103 static dump_node_edge_func dump_node_edge_hook = NULL;
104
105 void set_dump_node_edge_hook(dump_node_edge_func func)
106 {
107         dump_node_edge_hook = func;
108 }
109
110 dump_node_edge_func get_dump_node_edge_hook(void)
111 {
112         return dump_node_edge_hook;
113 }
114
115 void set_dump_block_edge_hook(dump_node_edge_func func)
116 {
117         dump_block_edge_hook = func;
118 }
119
120 dump_node_edge_func get_dump_block_edge_hook(void)
121 {
122         return dump_node_edge_hook;
123 }
124
125 void set_dump_node_vcgattr_hook(dump_node_vcgattr_func hook)
126 {
127         dump_node_vcgattr_hook = hook;
128 }
129
130 void set_dump_edge_vcgattr_hook(dump_edge_vcgattr_func hook)
131 {
132         dump_edge_vcgattr_hook = hook;
133 }
134
135 void ir_set_dump_flags(ir_dump_flags_t new_flags)
136 {
137         flags = new_flags;
138 }
139
140 void ir_add_dump_flags(ir_dump_flags_t new_flags)
141 {
142         flags |= new_flags;
143 }
144
145 void ir_remove_dump_flags(ir_dump_flags_t to_remove)
146 {
147         flags &= ~to_remove;
148 }
149
150 ir_dump_flags_t ir_get_dump_flags(void)
151 {
152         return flags;
153 }
154
155 /** Returns 0 if dump_out_edge_flag or dump_loop_information_flag
156  * are set, else returns dump_const_local_flag.
157  */
158 static bool get_opt_dump_const_local(void)
159 {
160         return (flags & ir_dump_flag_out_edges)
161                 || (flags & ir_dump_flag_loops)
162                 || (flags & ir_dump_flag_consts_local)
163                 || (flags & ir_dump_flag_iredges);
164 }
165
166 static char *dump_filter;
167
168 void ir_set_dump_filter(const char *new_filter)
169 {
170         xfree(dump_filter);
171         dump_filter = xstrdup(new_filter);
172 }
173
174 const char *ir_get_dump_filter(void)
175 {
176         return dump_filter;
177 }
178
179 int ir_should_dump(const char *name)
180 {
181         const char *f, *n;
182
183         if (dump_filter == NULL || dump_filter[0] == '\0')
184                 return 1;
185
186         for (n = name, f = dump_filter; *f != '\0' && *n != '\0';
187                         ++n, ++f) {
188                 if (*n != *f)
189                         return 0;
190         }
191         return 1;
192 }
193
194 /* -------------- some extended helper functions ----------------- */
195
196 const char *get_mode_name_ex(const ir_mode *mode, int *bad)
197 {
198         if (is_mode(mode))
199                 return get_mode_name(mode);
200         if (bad != NULL)
201                 *bad |= 1;
202         return "<ERROR>";
203 }
204
205 #define CUSTOM_COLOR_BASE    100
206 static const char *color_names[ird_color_count];
207 static const char *color_rgb[ird_color_count];
208 static struct obstack color_obst;
209
210 /** define a custom color. */
211 static void custom_color(int num, const char *rgb_def)
212 {
213         assert(num < ird_color_count);
214         obstack_printf(&color_obst, "%d", CUSTOM_COLOR_BASE + num);
215         obstack_1grow(&color_obst, '\0');
216
217         color_rgb[num]   = rgb_def;
218         color_names[num] = (const char*)obstack_finish(&color_obst);
219 }
220
221 /** Define a named color. */
222 static void named_color(int num, const char *name)
223 {
224         assert(num < ird_color_count);
225         color_rgb[num]   = NULL;
226         color_names[num] = name;
227 }
228
229 /** Initializes the used colors. */
230 static void init_colors(void)
231 {
232         static bool initialized = 0;
233         if (initialized)
234                 return;
235
236         obstack_init(&color_obst);
237
238         custom_color(ird_color_prog_background,       "204 204 204");
239         custom_color(ird_color_block_background,      "255 255 0");
240         custom_color(ird_color_dead_block_background, "190 150 150");
241         named_color(ird_color_block_inout,            "lightblue");
242         named_color(ird_color_default_node,           "white");
243         custom_color(ird_color_memory,                "153 153 255");
244         custom_color(ird_color_controlflow,           "255 153 153");
245         custom_color(ird_color_const,                 "204 255 255");
246         custom_color(ird_color_proj,                  "255 255 153");
247         custom_color(ird_color_uses_memory,           "153 153 255");
248         custom_color(ird_color_phi,                   "105 255 105");
249         custom_color(ird_color_anchor,                "100 100 255");
250         named_color(ird_color_error,                  "red");
251         custom_color(ird_color_entity,                "204 204 255");
252
253         initialized = 1;
254 }
255
256 /**
257  * Prints the VCG color to a file.
258  */
259 static void print_vcg_color(FILE *out, ird_color_t color)
260 {
261         assert(color < ird_color_count);
262         fprintf(out, "color:%s", color_names[color]);
263 }
264
265 void print_nodeid(FILE *F, const ir_node *node)
266 {
267         fprintf(F, "\"n%ld\"", get_irn_node_nr(node));
268 }
269
270 void print_irgid(FILE *F, const ir_graph *irg)
271 {
272         fprintf(F, "\"g%ld\"", get_irg_graph_nr(irg));
273 }
274
275 void print_typeid(FILE *F, const ir_type *type)
276 {
277         fprintf(F, "\"t%ld\"", get_type_nr(type));
278 }
279
280 void print_entityid(FILE *F, const ir_entity *entity)
281 {
282         fprintf(F, "\"e%ld\"", get_entity_nr(entity));
283 }
284
285 static void print_itemid(FILE *F, const ir_type *tp, size_t itemnr)
286 {
287         fprintf(F, "\"i%ldT%zu\"", get_type_nr(tp), itemnr);
288 }
289
290 /**
291  * Prints the edge kind of a given IR node.
292  *
293  * Projs should be dumped near their predecessor, so they get "nearedge".
294  */
295 static void print_node_edge_kind(FILE *out, const ir_node *node)
296 {
297         if (is_Proj(node)) {
298                 fprintf(out, "nearedge: ");
299         } else {
300                 fprintf(out, "edge: ");
301         }
302 }
303
304 /**
305  * Prints the edge from a type S to a type T with additional info fmt, ...
306  * to the file F.
307  */
308 static void print_type_type_edge(FILE *F, const ir_type *S, const ir_type *T, const char *fmt, ...)
309 {
310         va_list ap;
311
312         va_start(ap, fmt);
313         fprintf(F, "edge: { sourcename: ");
314         print_typeid(F, S);
315         fprintf(F, " targetname: ");
316         print_typeid(F, T);
317         ir_vfprintf(F, fmt, ap);
318         fprintf(F,"}\n");
319         va_end(ap);
320 }
321
322 /**
323  * Prints the edge from a type tp to an entity ent with additional info fmt, ...
324  * to the file F.
325  */
326 static void print_type_ent_edge(FILE *F, const ir_type *tp, const ir_entity *ent, const char *fmt, ...)
327 {
328         va_list ap;
329
330         va_start(ap, fmt);
331         fprintf(F, "edge: { sourcename: ");
332         print_typeid(F, tp);
333         fprintf(F, " targetname: ");
334         print_entityid(F, ent);
335         ir_vfprintf(F, fmt, ap);
336         fprintf(F, "}\n");
337         va_end(ap);
338 }
339
340 /**
341  * Prints the edge from an entity ent1 to an entity ent2 with additional info fmt, ...
342  * to the file F.
343  */
344 static void print_ent_ent_edge(FILE *F, const ir_entity *ent1, const ir_entity *ent2, int backedge, ird_color_t color, const char *fmt, ...)
345 {
346         va_list ap;
347
348         va_start(ap, fmt);
349         if (backedge)
350                 fprintf(F, "backedge: { sourcename: ");
351         else
352                 fprintf(F, "edge: { sourcename: ");
353         print_entityid(F, ent1);
354         fprintf(F, " targetname: ");
355         print_entityid(F, ent2);
356         ir_vfprintf(F, fmt, ap);
357         fprintf(F, " ");
358         if (color != ird_color_none)
359                 print_vcg_color(F, color);
360         fprintf(F, "}\n");
361         va_end(ap);
362 }
363
364 /**
365  * Prints the edge from an entity ent to a type tp with additional info fmt, ...
366  * to the file F.
367  */
368 static void print_ent_type_edge(FILE *F, const ir_entity *ent, const ir_type *tp, const char *fmt, ...)
369 {
370         va_list ap;
371
372         va_start(ap, fmt);
373         fprintf(F, "edge: { sourcename: ");
374         print_entityid(F, ent);
375         fprintf(F, " targetname: ");
376         print_typeid(F, tp);
377         ir_vfprintf(F, fmt, ap);
378         fprintf(F,"}\n");
379         va_end(ap);
380 }
381
382 /**
383  * Prints the edge from a node irn to a type tp with additional info fmt, ...
384  * to the file F.
385  */
386 static void print_node_type_edge(FILE *F, const ir_node *irn, ir_type *tp, const char *fmt, ...)
387 {
388         va_list ap;
389
390         va_start(ap, fmt);
391         fprintf(F, "edge: { sourcename: ");
392         print_nodeid(F, irn);
393         fprintf(F, " targetname: ");
394         print_typeid(F, tp);
395         ir_vfprintf(F, fmt, ap);
396         fprintf(F,"}\n");
397         va_end(ap);
398 }
399
400 /**
401  * Prints the edge from a node irn to an entity ent with additional info fmt, ...
402  * to the file F.
403  */
404 static void print_node_ent_edge(FILE *F, const ir_node *irn, const ir_entity *ent, const char *fmt, ...)
405 {
406         va_list ap;
407
408         va_start(ap, fmt);
409         fprintf(F, "edge: { sourcename: ");
410         print_nodeid(F, irn);
411         fprintf(F, " targetname: ");
412         print_entityid(F, ent);
413         ir_vfprintf(F, fmt, ap);
414         fprintf(F,"}\n");
415         va_end(ap);
416 }
417
418 /**
419  * Prints the edge from an entity ent to a node irn with additional info fmt, ...
420  * to the file F.
421  */
422 static void print_ent_node_edge(FILE *F, const ir_entity *ent, const ir_node *irn, const char *fmt, ...)
423 {
424         va_list ap;
425
426         va_start(ap, fmt);
427         fprintf(F, "edge: { sourcename: ");
428         print_entityid(F, ent);
429         fprintf(F, "\" targetname: ");
430         print_nodeid(F, irn);
431         ir_vfprintf(F, fmt, ap);
432         fprintf(F,"}\n");
433         va_end(ap);
434 }
435
436 /**
437  * Prints the edge from a type tp to an enumeration item item with additional info fmt, ...
438  * to the file F.
439  */
440 static void print_enum_item_edge(FILE *F, const ir_type *tp, size_t item, const char *fmt, ...)
441 {
442         va_list ap;
443
444         va_start(ap, fmt);
445         fprintf(F, "edge: { sourcename: ");
446         print_typeid(F, tp);
447         fprintf(F, " targetname: ");
448         print_itemid(F, tp, item);
449         ir_vfprintf(F, fmt, ap);
450         fprintf(F,"}\n");
451         va_end(ap);
452 }
453
454 /*-----------------------------------------------------------------*/
455 /* global and ahead declarations                                   */
456 /*-----------------------------------------------------------------*/
457
458 static void dump_loop_nodes_into_graph(FILE *F, ir_graph *irg);
459
460 /*-----------------------------------------------------------------*/
461 /* Helper functions.                                                */
462 /*-----------------------------------------------------------------*/
463
464 /**
465  * This map is used as a private link attr to be able to call dumper
466  * anywhere without destroying link fields.
467  */
468 static pmap *irdump_link_map = NULL;
469
470 /** NOT A STANDARD LIBFIRM INIT METHOD
471  *
472  * We do not want to integrate dumping into libfirm, i.e., if the dumpers
473  * are off, we want to have as few interferences as possible.  Therefore the
474  * initialization is performed lazily and not called from within init_firm.
475  *
476  * Creates the link attribute map. */
477 static void init_irdump(void)
478 {
479         /* We need a new, empty map. */
480         if (irdump_link_map) pmap_destroy(irdump_link_map);
481         irdump_link_map = pmap_create();
482         if (!dump_file_filter_id)
483                 dump_file_filter_id = new_id_from_str("");
484 }
485
486 /**
487  * Returns the private link field.
488  */
489 static void *ird_get_irn_link(const ir_node *n)
490 {
491         void *res = NULL;
492         if (irdump_link_map == NULL)
493                 return NULL;
494
495         if (pmap_contains(irdump_link_map, n))
496                 res = pmap_get(irdump_link_map, n);
497         return res;
498 }
499
500 /**
501  * Sets the private link field.
502  */
503 static void ird_set_irn_link(const ir_node *n, void *x)
504 {
505         if (irdump_link_map == NULL)
506                 init_irdump();
507         pmap_insert(irdump_link_map, n, x);
508 }
509
510 /**
511  * Gets the private link field of an irg.
512  */
513 static void *ird_get_irg_link(const ir_graph *irg)
514 {
515         void *res = NULL;
516         if (irdump_link_map == NULL)
517                 return NULL;
518
519         if (pmap_contains(irdump_link_map, irg))
520                 res = pmap_get(irdump_link_map, irg);
521         return res;
522 }
523
524 /**
525  * Sets the private link field of an irg.
526  */
527 static void ird_set_irg_link(const ir_graph *irg, void *x)
528 {
529         if (irdump_link_map == NULL)
530                 init_irdump();
531         pmap_insert(irdump_link_map, irg, x);
532 }
533
534 /**
535  * Walker, clears the private link field.
536  */
537 static void clear_link(ir_node *node, void *env)
538 {
539         (void) env;
540         ird_set_irn_link(node, NULL);
541 }
542
543 /**
544  * If the entity has a ld_name, returns it if the dump_ld_name is set,
545  * else returns the name of the entity.
546  */
547 static const char *get_ent_dump_name_(const ir_entity *ent, bool dump_ld_name)
548 {
549         if (ent == NULL)
550                 return "<NULL entity>";
551         if (dump_ld_name) {
552                 /* Don't use get_entity_ld_ident (ent) as it computes the mangled name! */
553                 if (ent->ld_name != NULL)
554                         return get_id_str(ent->ld_name);
555         }
556         return get_id_str(ent->name);
557 }
558
559 const char *get_ent_dump_name(const ir_entity *ent)
560 {
561         return get_ent_dump_name_(ent, flags & ir_dump_flag_ld_names);
562 }
563
564 const char *get_irg_dump_name(const ir_graph *irg)
565 {
566         /* Don't use get_entity_ld_ident (ent) as it computes the mangled name! */
567         return get_ent_dump_name_(get_irg_entity(irg), true);
568 }
569
570 /**
571  * Returns non-zero if a node is in floating state.
572  */
573 static int node_floats(const ir_node *n)
574 {
575         ir_graph *irg = get_irn_irg(n);
576         return ((get_irn_pinned(n) == op_pin_state_floats) &&
577                 (get_irg_pinned(irg) == op_pin_state_floats));
578 }
579
580 /**
581  *  Walker that visits the anchors
582  */
583 static void ird_walk_graph(ir_graph *irg, irg_walk_func *pre, irg_walk_func *post, void *env)
584 {
585         if ((flags & ir_dump_flag_all_anchors)
586                         || ((flags & ir_dump_flag_iredges) && edges_activated(irg))) {
587                 irg_walk_anchors(irg, pre, post, env);
588         } else {
589                 irg_walk_graph(irg, pre, post, env);
590         }
591 }
592
593 /**
594  * Walker, allocates an array for all blocks and puts their non-floating
595  * nodes into this array.
596  */
597 static void collect_node(ir_node *node, void *env)
598 {
599         (void) env;
600         if (is_Block(node)
601             || node_floats(node)
602             || (get_op_flags(get_irn_op(node)) & irop_flag_dump_noblock)) {
603                 ir_node ** arr = (ir_node **) ird_get_irg_link(get_irn_irg(node));
604                 if (!arr) arr = NEW_ARR_F(ir_node *, 0);
605                 ARR_APP1(ir_node *, arr, node);
606                 ird_set_irg_link(get_irn_irg(node), arr);    /* arr is an l-value, APP_ARR might change it! */
607         } else {
608                 ir_node * block = get_nodes_block(node);
609
610                 if (is_Bad(block)) {
611                         /* this node is in a Bad block, so we must place it into the graph's list */
612                         ir_node ** arr = (ir_node **) ird_get_irg_link(get_irn_irg(node));
613                         if (!arr) arr = NEW_ARR_F(ir_node *, 0);
614                         ARR_APP1(ir_node *, arr, node);
615                         ird_set_irg_link(get_irn_irg(node), arr);    /* arr is an l-value, APP_ARR might change it! */
616                 } else {
617                         ird_set_irn_link(node, ird_get_irn_link(block));
618                         ird_set_irn_link(block, node);
619                 }
620         }
621 }
622
623 /** Construct lists to walk ir block-wise.
624  *
625  * Collects all blocks, nodes not op_pin_state_pinned,
626  * Bad, NoMem and Unknown into a flexible array in link field of
627  * irg they belong to.  Sets the irg link field to NULL in all
628  * graphs not visited.
629  * Free the list with DEL_ARR_F().
630  */
631 static ir_node **construct_block_lists(ir_graph *irg)
632 {
633         size_t   i;
634         int      walk_flag = ir_resources_reserved(irg) & IR_RESOURCE_IRN_VISITED;
635
636         if (walk_flag) {
637                 ir_free_resources(irg, IR_RESOURCE_IRN_VISITED);
638         }
639
640         for (i = get_irp_n_irgs(); i > 0;)
641                 ird_set_irg_link(get_irp_irg(--i), NULL);
642
643         ird_walk_graph(irg, clear_link, collect_node, irg);
644
645         if (walk_flag) {
646                 ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED);
647         }
648
649         return (ir_node**)ird_get_irg_link(irg);
650 }
651
652 typedef struct list_tuple {
653         ir_node **blk_list;
654         ir_extblk **extbb_list;
655 } list_tuple;
656
657 /** Construct lists to walk IR extended block-wise.
658  * Free the lists in the tuple with DEL_ARR_F(). Sets the irg link field to
659  * NULL in all graphs not visited.
660  */
661 static list_tuple *construct_extblock_lists(ir_graph *irg)
662 {
663         ir_node **blk_list = construct_block_lists(irg);
664         size_t i, n;
665         list_tuple *lists = XMALLOC(list_tuple);
666
667         lists->blk_list   = NEW_ARR_F(ir_node *, 0);
668         lists->extbb_list = NEW_ARR_F(ir_extblk *, 0);
669
670         inc_irg_block_visited(irg);
671         for (i = 0, n = ARR_LEN(blk_list); i < n; ++i) {
672                 ir_extblk *ext;
673
674                 if (is_Block(blk_list[i])) {
675                         ext = get_Block_extbb(blk_list[i]);
676
677                         if (extbb_not_visited(ext)) {
678                                 ARR_APP1(ir_extblk *, lists->extbb_list, ext);
679                                 mark_extbb_visited(ext);
680                         }
681                 } else
682                         ARR_APP1(ir_node *, lists->blk_list, blk_list[i]);
683         }
684         DEL_ARR_F(blk_list);
685
686         ird_set_irg_link(irg, lists);
687         return lists;
688 }
689
690 void dump_node_opcode(FILE *F, const ir_node *n)
691 {
692         const ir_op_ops *ops = get_op_ops(get_irn_op(n));
693
694         /* call the dump_node operation if available */
695         if (ops->dump_node) {
696                 ops->dump_node(F, n, dump_node_opcode_txt);
697                 return;
698         }
699
700         /* implementation for default nodes */
701         switch (get_irn_opcode(n)) {
702         case iro_SymConst:
703                 switch (get_SymConst_kind(n)) {
704                 case symconst_addr_ent:
705                         fprintf(F, "SymC &%s", get_entity_name(get_SymConst_entity(n)));
706                         break;
707                 case symconst_ofs_ent:
708                         fprintf(F, "SymC %s offset", get_entity_name(get_SymConst_entity(n)));
709                         break;
710                 case symconst_type_size:
711                         ir_fprintf(F, "SymC %+F size", get_SymConst_type(n));
712                         break;
713                 case symconst_type_align:
714                         ir_fprintf(F, "SymC %+F align", get_SymConst_type(n));
715                         break;
716                 case symconst_enum_const:
717                         fprintf(F, "SymC %s enum", get_enumeration_const_name(get_SymConst_enum(n)));
718                         break;
719                 }
720                 break;
721
722         case iro_Load:
723                 if (get_Load_unaligned(n) == align_non_aligned)
724                         fprintf(F, "ua");
725                 fprintf(F, "%s[%s]", get_irn_opname(n), get_mode_name_ex(get_Load_mode(n), NULL));
726                 break;
727         case iro_Store:
728                 if (get_Store_unaligned(n) == align_non_aligned)
729                         fprintf(F, "ua");
730                 fprintf(F, "%s", get_irn_opname(n));
731                 break;
732         case iro_Block:
733                 if (n == get_irg_start_block(get_irn_irg(n)))
734                         fputs("Start ", F);
735                 if (n == get_irg_end_block(get_irn_irg(n)))
736                         fputs("End ", F);
737                 fprintf(F, "%s%s", get_irn_opname(n),
738                         (flags & ir_dump_flag_show_marks) ? (get_Block_mark(n) ? "*" : "") : "");
739                 break;
740         case iro_Conv:
741                 if (get_Conv_strict(n))
742                         fprintf(F, "strict");
743                 fprintf(F, "%s", get_irn_opname(n));
744                 break;
745         case iro_Div:
746                 fprintf(F, "%s", get_irn_opname(n));
747                 if (get_Div_no_remainder(n))
748                         fprintf(F, "RL");
749                 fprintf(F, "[%s]", get_mode_name_ex(get_Div_resmode(n), NULL));
750                 break;
751         case iro_Mod:
752                 fprintf(F, "%s[%s]", get_irn_opname(n), get_mode_name_ex(get_Mod_resmode(n), NULL));
753                 break;
754         case iro_Builtin:
755                 fprintf(F, "%s[%s]", get_irn_opname(n), get_builtin_kind_name(get_Builtin_kind(n)));
756                 break;
757
758         default:
759                 fprintf(F, "%s", get_irn_opname(n));
760         }
761 }
762
763 /**
764  * Dump the mode of a node n to a file F.
765  * Ignore modes that are "always known".
766  */
767 static void dump_node_mode(FILE *F, const ir_node *n)
768 {
769         const ir_op_ops *ops = get_op_ops(get_irn_op(n));
770         unsigned         iro;
771         ir_mode         *mode;
772
773         /* call the dump_node operation if available */
774         if (ops->dump_node) {
775                 ops->dump_node(F, n, dump_node_mode_txt);
776                 return;
777         }
778
779         /* default implementation */
780         iro = get_irn_opcode(n);
781         switch (iro) {
782         case iro_SymConst:
783         case iro_Sel:
784         case iro_End:
785         case iro_Return:
786         case iro_Free:
787         case iro_Sync:
788         case iro_Jmp:
789         case iro_NoMem:
790                 break;
791         default:
792                 mode = get_irn_mode(n);
793
794                 if (mode != NULL && mode != mode_BB && mode != mode_ANY && mode != mode_BAD &&
795                         (mode != mode_T || iro == iro_Proj))
796                         fprintf(F, "%s", get_mode_name_ex(mode, NULL));
797         }
798 }
799
800 /**
801  * Dump the type of a node n to a file F if it's known.
802  */
803 static int dump_node_typeinfo(FILE *F, const ir_node *n)
804 {
805         ir_graph *irg = get_irn_irg(n);
806         int bad = 0;
807
808         if (ir_get_dump_flags() & ir_dump_flag_analysed_types) {
809                 if (get_irg_typeinfo_state(irg) == ir_typeinfo_consistent  ||
810                         get_irg_typeinfo_state(irg) == ir_typeinfo_inconsistent) {
811                         ir_type *tp = get_irn_typeinfo_type(n);
812                         if (tp != get_none_type()) {
813                                 ir_fprintf(F, "[%+F]", tp);
814                         } else {
815                                 fprintf(F, "[] ");
816                         }
817                 }
818         }
819         return bad;
820 }
821
822 /**
823  * Dump additional node attributes of some nodes to a file F.
824  */
825 static void dump_node_nodeattr(FILE *F, const ir_node *n)
826 {
827         ir_node *pred;
828         unsigned code;
829         long proj_nr;
830         const ir_op_ops *ops = get_op_ops(get_irn_op(n));
831
832         /* call the dump_node operation if available */
833         if (ops->dump_node) {
834                 ops->dump_node(F, n, dump_node_nodeattr_txt);
835                 return;
836         }
837
838         switch (get_irn_opcode(n)) {
839         case iro_Const:
840                 ir_fprintf(F, "%T ", get_Const_tarval(n));
841                 break;
842
843         case iro_Proj:
844                 pred    = get_Proj_pred(n);
845                 proj_nr = get_Proj_proj(n);
846                 code    = get_irn_opcode(pred);
847
848                 if (code == iro_Proj && get_irn_opcode(get_Proj_pred(pred)) == iro_Start)
849                         fprintf(F, "Arg %ld ", proj_nr);
850                 else if (code == iro_Cond && get_irn_mode(get_Cond_selector(pred)) != mode_b)
851                         fprintf(F, "%ld ", proj_nr);
852                 else {
853                         unsigned i, j, f = 0;
854
855                         for (i = 0; i < ARRAY_SIZE(proj_lut); ++i) {
856                                 if (code == proj_lut[i].code) {
857                                         for (j = 0; j < proj_lut[i].num_data; ++j) {
858                                                 if (proj_nr == proj_lut[i].data[j].nr) {
859                                                         fprintf(F, "%s ", proj_lut[i].data[j].name);
860                                                         f = 1;
861                                                         break;
862                                                 }
863                                         }
864                                         break;
865                                 }
866                         }
867                         if (! f)
868                                 fprintf(F, "%ld ", proj_nr);
869                         if (code == iro_Cond && get_Cond_jmp_pred(pred) != COND_JMP_PRED_NONE) {
870                                 if (proj_nr == pn_Cond_false && get_Cond_jmp_pred(pred) == COND_JMP_PRED_FALSE)
871                                         fprintf(F, "PRED ");
872                                 if (proj_nr == pn_Cond_true && get_Cond_jmp_pred(pred) == COND_JMP_PRED_TRUE)
873                                         fprintf(F, "PRED ");
874                         }
875                 }
876                 break;
877         case iro_Sel:
878                 fprintf(F, "%s ", get_ent_dump_name(get_Sel_entity(n)));
879                 break;
880         case iro_Cast:
881                 ir_fprintf(F, "(%+F)", get_Cast_type(n));
882                 break;
883         case iro_Cmp:
884                 fprintf(F, "%s ", get_relation_string(get_Cmp_relation(n)));
885                 break;
886         case iro_Confirm:
887                 fprintf(F, "%s ", get_relation_string(get_Confirm_relation(n)));
888                 break;
889         case iro_CopyB:
890                 ir_fprintf(F, "(%+F)", get_CopyB_type(n));
891                 break;
892
893         default:
894                 break;
895         }
896 }
897
898 void dump_node_label(FILE *F, const ir_node *n)
899 {
900         dump_node_opcode(F, n);
901         fputs(" ", F);
902         dump_node_mode(F, n);
903         fprintf(F, " ");
904         dump_node_typeinfo(F, n);
905         dump_node_nodeattr(F, n);
906         if (flags & ir_dump_flag_number_label) {
907                 fprintf(F, "%ld", get_irn_node_nr(n));
908         }
909         if (flags & ir_dump_flag_idx_label) {
910                 fprintf(F, ":%u", get_irn_idx(n));
911         }
912 }
913
914 /**
915  * Dumps the attributes of a node n into the file F.
916  * Currently this is only the color of a node.
917  */
918 static void dump_node_vcgattr(FILE *F, const ir_node *node, const ir_node *local, bool bad)
919 {
920         ir_mode *mode;
921         const ir_node *n;
922
923         if (bad) {
924                 print_vcg_color(F, ird_color_error);
925                 return;
926         }
927
928         if (dump_node_vcgattr_hook != NULL) {
929                 dump_node_vcgattr_hook(F, node, local);
930                 return;
931         }
932
933         n = local ? local : node;
934
935         if (overrule_nodecolor != ird_color_default_node) {
936                 print_vcg_color(F, overrule_nodecolor);
937                 return;
938         }
939
940         mode = get_irn_mode(n);
941         if (mode == mode_M) {
942                 print_vcg_color(F, ird_color_memory);
943                 return;
944         }
945         if (mode == mode_X) {
946                 print_vcg_color(F, ird_color_controlflow);
947                 return;
948         }
949
950         switch (get_irn_opcode(n)) {
951         case iro_Start:
952         case iro_End:
953                 print_vcg_color(F, ird_color_anchor);
954                 break;
955         case iro_Bad:
956                 print_vcg_color(F, ird_color_error);
957                 break;
958         case iro_Block:
959                 print_vcg_color(F, ird_color_block_background);
960                 break;
961         case iro_Phi:
962                 print_vcg_color(F, ird_color_phi);
963                 break;
964         case iro_Pin:
965                 print_vcg_color(F, ird_color_memory);
966                 break;
967         case iro_SymConst:
968         case iro_Const:
969                 print_vcg_color(F, ird_color_const);
970                 break;
971         case iro_Proj:
972                 print_vcg_color(F, ird_color_proj);
973                 break;
974         default: {
975                 ir_op *op = get_irn_op(node);
976
977                 if (is_op_constlike(op)) {
978                         print_vcg_color(F, ird_color_const);
979                 } else if (is_op_uses_memory(op)) {
980                         print_vcg_color(F, ird_color_uses_memory);
981                 } else if (is_op_cfopcode(op) || is_op_forking(op)) {
982                         print_vcg_color(F, ird_color_controlflow);
983                 }
984         }
985         }
986 }
987
988 void *dump_add_node_info_callback(dump_node_info_cb_t *cb, void *data)
989 {
990         hook_entry_t *info = XMALLOCZ(hook_entry_t);
991
992         info->hook._hook_node_info = cb;
993         info->context              = data;
994         register_hook(hook_node_info, info);
995
996         return info;
997 }
998
999 void dump_remove_node_info_callback(void *handle)
1000 {
1001         hook_entry_t *info = (hook_entry_t*)handle;
1002         unregister_hook(hook_node_info, info);
1003         xfree(info);
1004 }
1005
1006 /**
1007  * Dump the node information of a node n to a file F.
1008  */
1009 static void dump_node_info(FILE *F, const ir_node *n)
1010 {
1011         const ir_op_ops *ops = get_op_ops(get_irn_op(n));
1012
1013         fprintf(F, " info1: \"");
1014         dump_irnode_to_file(F, n);
1015         /* call the dump_node operation if available */
1016         if (ops->dump_node)
1017                 ops->dump_node(F, n, dump_node_info_txt);
1018
1019         /* allow additional info to be added */
1020         hook_node_info(F, n);
1021         fprintf(F, "\"\n");
1022 }
1023
1024 static int is_constlike_node(const ir_node *node)
1025 {
1026         const ir_op *op = get_irn_op(node);
1027         return is_op_constlike(op);
1028 }
1029
1030 static void print_constid(FILE *F, const ir_node *user, const ir_node *node)
1031 {
1032         fprintf(F, "\"n%ldb%ld\"", get_irn_node_nr(user), get_irn_node_nr(node));
1033 }
1034
1035 static void print_constblkid(FILE *F, const ir_node *node, const ir_node *block)
1036 {
1037         fprintf(F, "\"n%ldb%ld\"", get_irn_node_nr(node), get_irn_node_nr(block));
1038 }
1039
1040
1041 /** outputs the predecessors of n, that are constants, local.  I.e.,
1042    generates a copy of the constant predecessors for each node called with. */
1043 static void dump_const_node_local(FILE *F, const ir_node *n)
1044 {
1045         ir_graph *irg = get_irn_irg(n);
1046         int i;
1047         if (!get_opt_dump_const_local()) return;
1048
1049         /* Use visited flag to avoid outputting nodes twice.
1050         initialize it first. */
1051         for (i = 0; i < get_irn_arity(n); i++) {
1052                 ir_node *con = get_irn_n(n, i);
1053                 if (is_constlike_node(con)) {
1054                         set_irn_visited(con, get_irg_visited(irg) - 1);
1055                 }
1056         }
1057
1058         for (i = 0; i < get_irn_arity(n); i++) {
1059                 ir_node *con = get_irn_n(n, i);
1060                 if (is_constlike_node(con) && !irn_visited_else_mark(con)) {
1061                         /* Generate a new name for the node by appending the names of
1062                         n and const. */
1063                         fprintf(F, "node: {title: ");
1064                         print_constid(F, n, con);
1065                         fprintf(F, " label: \"");
1066                         dump_node_label(F, con);
1067                         fprintf(F, "\" ");
1068                         dump_node_info(F, con);
1069                         dump_node_vcgattr(F, n, con, 0);
1070                         fprintf(F, "}\n");
1071                 }
1072         }
1073 }
1074
1075 /** If the block of an edge is a const_like node, dump it local with an edge */
1076 static void dump_const_block_local(FILE *F, const ir_node *n)
1077 {
1078         ir_node *blk;
1079
1080         if (!get_opt_dump_const_local()) return;
1081
1082         blk = get_nodes_block(n);
1083         if (is_constlike_node(blk)) {
1084                 /* Generate a new name for the node by appending the names of
1085                 n and blk. */
1086                 fprintf(F, "node: {title: ");
1087                 print_constblkid(F, n, blk);
1088                 fprintf(F, " label: \"");
1089                 dump_node_label(F, blk);
1090                 fprintf(F, "\" ");
1091                 dump_node_info(F, blk);
1092                 dump_node_vcgattr(F, n, blk, 0);
1093                 fprintf(F, "}\n");
1094
1095                 fprintf(F, "edge: { sourcename: ");
1096                 print_nodeid(F, n);
1097                 fprintf(F, " targetname: ");
1098                 print_constblkid(F, n, blk);
1099                 fprintf(F, " ");
1100
1101                 if (dump_edge_vcgattr_hook != NULL
1102                     && dump_edge_vcgattr_hook(F, n, -1)) {
1103                         fprintf(F, "}\n");
1104                         return;
1105                 }
1106
1107                 fprintf(F, BLOCK_EDGE_ATTR "}\n");
1108         }
1109 }
1110
1111 /**
1112  * prints the error message of a node to a file F as info2.
1113  */
1114 static void print_node_error(FILE *F, const char *err_msg)
1115 {
1116         if (! err_msg)
1117                 return;
1118
1119         fprintf(F, " info2: \"%s\"", err_msg);
1120 }
1121
1122 /**
1123  * prints debug messages of a node to file F as info3.
1124  */
1125 static void print_dbg_info(FILE *F, dbg_info *dbg)
1126 {
1127         char buf[1024];
1128
1129         ir_dbg_info_snprint(buf, sizeof(buf), dbg);
1130         if (buf[0] != 0) {
1131                 fprintf(F, " info3: \"%s\"\n", buf);
1132         }
1133 }
1134
1135 static void print_type_dbg_info(FILE *F, type_dbg_info *dbg)
1136 {
1137         (void) F;
1138         (void) dbg;
1139         /* TODO */
1140 }
1141
1142 /**
1143  * Dump a node
1144  */
1145 void dump_node(FILE *F, const ir_node *n)
1146 {
1147         int bad = 0;
1148         const char *p;
1149         ir_graph   *irg;
1150
1151         if (get_opt_dump_const_local() && is_constlike_node(n))
1152                 return;
1153
1154         /* dump this node */
1155         fputs("node: {title: ", F);
1156         print_nodeid(F, n);
1157
1158         fputs(" label: \"", F);
1159         irg = get_irn_irg(n);
1160         bad = ! irn_verify_irg_dump(n, irg, &p);
1161         dump_node_label(F, n);
1162         fputs("\" ", F);
1163
1164         dump_node_info(F, n);
1165         print_node_error(F, p);
1166         print_dbg_info(F, get_irn_dbg_info(n));
1167         dump_node_vcgattr(F, n, NULL, bad);
1168         fputs("}\n", F);
1169         dump_const_node_local(F, n);
1170
1171 }
1172
1173 /** dump the edge to the block this node belongs to */
1174 static void dump_ir_block_edge(FILE *F, const ir_node *n)
1175 {
1176         if (get_opt_dump_const_local() && is_constlike_node(n)) return;
1177         if (!is_Block(n)) {
1178                 ir_node *block = get_nodes_block(n);
1179
1180                 if (get_opt_dump_const_local() && is_constlike_node(block)) {
1181                         dump_const_block_local(F, n);
1182                 } else {
1183                         fprintf(F, "edge: { sourcename: ");
1184                         print_nodeid(F, n);
1185                         fprintf(F, " targetname: ");
1186                         print_nodeid(F, block);
1187                         fprintf(F, " ");
1188
1189                         if (dump_edge_vcgattr_hook && dump_edge_vcgattr_hook(F, n, -1)) {
1190                                 fprintf(F, "}\n");
1191                                 return;
1192                         }
1193
1194                         fprintf(F, BLOCK_EDGE_ATTR "}\n");
1195                 }
1196         }
1197 }
1198
1199 static void print_data_edge_vcgattr(FILE *F, const ir_node *from, int to)
1200 {
1201         /*
1202          * do not use get_nodes_block() here, will fail
1203          * if the irg is not pinned.
1204          */
1205         if (get_irn_n(from, -1) == get_irn_n(get_irn_n(from, to), -1))
1206                 fprintf(F, INTRA_DATA_EDGE_ATTR);
1207         else
1208                 fprintf(F, INTER_DATA_EDGE_ATTR);
1209 }
1210
1211 static void print_mem_edge_vcgattr(FILE *F, const ir_node *from, int to)
1212 {
1213         /*
1214          * do not use get_nodes_block() here, will fail
1215          * if the irg is not pinned.
1216          */
1217         if (get_irn_n(from, -1) == get_irn_n(get_irn_n(from, to), -1))
1218                 fprintf(F, INTRA_MEM_EDGE_ATTR);
1219         else
1220                 fprintf(F, INTER_MEM_EDGE_ATTR);
1221 }
1222
1223 /** Print the vcg attributes for the edge from node "from" to its "to"th input */
1224 static void print_edge_vcgattr(FILE *F, const ir_node *from, int to)
1225 {
1226         assert(from);
1227
1228         if (dump_edge_vcgattr_hook)
1229                 if (dump_edge_vcgattr_hook(F, from, to))
1230                         return;
1231
1232         if ((flags & ir_dump_flag_back_edges) && is_backedge(from, to))
1233                 fprintf(F, BACK_EDGE_ATTR);
1234
1235         switch (get_irn_opcode(from)) {
1236         case iro_Block:
1237                 fprintf(F, CF_EDGE_ATTR);
1238                 break;
1239         case iro_Start:  break;
1240         case iro_End:
1241                 if (to >= 0) {
1242                         if (get_irn_mode(get_End_keepalive(from, to)) == mode_BB)
1243                                 fprintf(F, KEEP_ALIVE_CF_EDGE_ATTR);
1244                         else
1245                                 fprintf(F, KEEP_ALIVE_DF_EDGE_ATTR);
1246                 }
1247                 break;
1248         default:
1249                 if (is_Proj(from)) {
1250                         if (get_irn_mode(from) == mode_M)
1251                                 print_mem_edge_vcgattr(F, from, to);
1252                         else if (get_irn_mode(from) == mode_X)
1253                                 fprintf(F, CF_EDGE_ATTR);
1254                         else
1255                                 print_data_edge_vcgattr(F, from, to);
1256                 }
1257                 else if (get_irn_mode(get_irn_n(from, to)) == mode_M)
1258                         print_mem_edge_vcgattr(F, from, to);
1259                 else if (get_irn_mode(get_irn_n(from, to)) == mode_X)
1260                         fprintf(F, CF_EDGE_ATTR);
1261                 else
1262                         print_data_edge_vcgattr(F, from, to);
1263         }
1264 }
1265
1266 /** dump edges to our inputs */
1267 static void dump_ir_data_edges(FILE *F, const ir_node *n)
1268 {
1269         int i, num;
1270
1271         if (dump_node_edge_hook)
1272                 dump_node_edge_hook(F, n);
1273
1274         if (!(flags & ir_dump_flag_keepalive_edges) && is_End(n)) {
1275                 /* the End node has only keep-alive edges */
1276                 return;
1277         }
1278
1279         /* dump the dependency edges. */
1280         num = get_irn_deps(n);
1281         for (i = 0; i < num; ++i) {
1282                 ir_node *dep = get_irn_dep(n, i);
1283
1284                 if (dep) {
1285                         print_node_edge_kind(F, n);
1286                         fprintf(F, "{sourcename: ");
1287                         print_nodeid(F, n);
1288                         fprintf(F, " targetname: ");
1289                         if ((get_opt_dump_const_local()) && is_constlike_node(dep)) {
1290                                 print_constid(F, n, dep);
1291                         } else {
1292                                 print_nodeid(F, dep);
1293                         }
1294                         fprintf(F, " label: \"%d\" ", i);
1295                         fprintf(F, " color: darkgreen}\n");
1296                 }
1297         }
1298
1299         num = get_irn_arity(n);
1300         for (i = 0; i < num; i++) {
1301                 ir_node *pred = get_irn_n(n, i);
1302                 assert(pred);
1303
1304                 if ((flags & ir_dump_flag_back_edges) && is_backedge(n, i)) {
1305                         fprintf(F, "backedge: {sourcename: ");
1306                 } else {
1307                         print_node_edge_kind(F, n);
1308                         fprintf(F, "{sourcename: ");
1309                 }
1310                 print_nodeid(F, n);
1311                 fprintf(F, " targetname: ");
1312                 if ((get_opt_dump_const_local()) && is_constlike_node(pred)) {
1313                         print_constid(F, n, pred);
1314                 } else {
1315                         print_nodeid(F, pred);
1316                 }
1317                 fprintf(F, " label: \"%d\" ", i);
1318                 print_edge_vcgattr(F, n, i);
1319                 fprintf(F, "}\n");
1320         }
1321 }
1322
1323 /**
1324  * Dump the ir_edges
1325  */
1326 static void dump_ir_edges(ir_node *node, void *env)
1327 {
1328         int              i = 0;
1329         FILE            *F = (FILE*)env;
1330         const ir_edge_t *edge;
1331
1332         foreach_out_edge(node, edge) {
1333                 ir_node *succ = get_edge_src_irn(edge);
1334
1335                 print_node_edge_kind(F, succ);
1336                 fprintf(F, "{sourcename: ");
1337                 print_nodeid(F, node);
1338                 fprintf(F, " targetname: ");
1339                 print_nodeid(F, succ);
1340
1341                 fprintf(F, " label: \"%d\" ", i);
1342                 fprintf(F, OUT_EDGE_ATTR);
1343                 fprintf(F, "}\n");
1344                 ++i;
1345         }
1346 }
1347
1348
1349 /** Dumps a node and its edges but not the block edge  */
1350 static void dump_node_wo_blockedge(FILE *F, const ir_node *n)
1351 {
1352         dump_node(F, n);
1353         dump_ir_data_edges(F, n);
1354 }
1355
1356 /** Dumps a node and its edges. */
1357 static void dump_node_with_edges(ir_node *n, void *env)
1358 {
1359         FILE *F = (FILE*)env;
1360         dump_node_wo_blockedge(F, n);
1361         if (!node_floats(n))
1362                 dump_ir_block_edge(F, n);
1363 }
1364
1365 /** Dumps a const-like node. */
1366 static void dump_const_node(ir_node *n, void *env)
1367 {
1368         FILE *F = (FILE*)env;
1369         if (is_Block(n)) return;
1370         dump_node_wo_blockedge(F, n);
1371 }
1372
1373 /***********************************************************************/
1374 /* the following routines dump the nodes/irgs bracketed to graphs.     */
1375 /***********************************************************************/
1376
1377 /** Dumps a constant expression as entity initializer, array bound ... */
1378 static void dump_const_expression(FILE *F, ir_node *value)
1379 {
1380         ir_graph *irg = get_const_code_irg();
1381         ir_dump_flags_t old_flags = ir_get_dump_flags();
1382         ir_remove_dump_flags(ir_dump_flag_consts_local);
1383
1384         irg_walk(value, dump_const_node, NULL, F);
1385         /* Decrease visited flag so that we walk with the same flag for the next
1386            expression.  This guarantees that we don't dump the same node twice,
1387            as for const expressions cse is performed to save memory. */
1388         set_irg_visited(irg, get_irg_visited(irg) -1);
1389
1390         ir_set_dump_flags(old_flags);
1391 }
1392
1393 /** Dump a block as graph containing its nodes.
1394  *
1395  *  Expects to find nodes belonging to the block as list in its
1396  *  link field.
1397  *  Dumps the edges of all nodes including itself. */
1398 static void dump_whole_block(FILE *F, const ir_node *block)
1399 {
1400         ir_node *node;
1401         ird_color_t color = ird_color_block_background;
1402
1403         assert(is_Block(block));
1404
1405         fprintf(F, "graph: { title: ");
1406         print_nodeid(F, block);
1407         fprintf(F, " label: \"");
1408         dump_node_label(F, block);
1409
1410         /* colorize blocks */
1411         if (! get_Block_matured(block))
1412                 color = ird_color_block_background;
1413
1414         fprintf(F, "\" status:clustered ");
1415         print_vcg_color(F, color);
1416         fprintf(F, "\n");
1417
1418         /* yComp can show attributes for blocks, XVCG parses but ignores them */
1419         dump_node_info(F, block);
1420         print_dbg_info(F, get_irn_dbg_info(block));
1421
1422         /* dump the blocks edges */
1423         dump_ir_data_edges(F, block);
1424
1425         if (dump_block_edge_hook)
1426                 dump_block_edge_hook(F, block);
1427
1428         /* dump the nodes that go into the block */
1429         for (node = (ir_node*)ird_get_irn_link(block); node; node = (ir_node*)ird_get_irn_link(node)) {
1430                 dump_node(F, node);
1431                 dump_ir_data_edges(F, node);
1432         }
1433
1434         /* Close the vcg information for the block */
1435         fprintf(F, "}\n");
1436         dump_const_node_local(F, block);
1437         fprintf(F, "\n");
1438 }
1439
1440 /** dumps a graph block-wise. Expects all blockless nodes in arr in irgs link.
1441  *  The outermost nodes: blocks and nodes not op_pin_state_pinned, Bad, Unknown. */
1442 static void dump_block_graph(FILE *F, ir_graph *irg)
1443 {
1444         size_t i, n;
1445         ir_node **arr = (ir_node**)ird_get_irg_link(irg);
1446
1447         for (i = 0, n = ARR_LEN(arr); i < n; ++i) {
1448                 ir_node *node = arr[i];
1449                 if (is_Block(node)) {
1450                 /* Dumps the block and all the nodes in the block, which are to
1451                         be found in Block->link. */
1452                         dump_whole_block(F, node);
1453                 } else {
1454                         /* Nodes that are not in a Block. */
1455                         dump_node(F, node);
1456                         if (!node_floats(node) && is_Bad(get_nodes_block(node))) {
1457                                 dump_const_block_local(F, node);
1458                         }
1459                         dump_ir_data_edges(F, node);
1460                 }
1461                 if ((flags & ir_dump_flag_iredges) && edges_activated(irg))
1462                         dump_ir_edges(node, F);
1463         }
1464
1465         if ((flags & ir_dump_flag_loops)
1466              && is_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_LOOPINFO))
1467                 dump_loop_nodes_into_graph(F, irg);
1468 }
1469
1470 /**
1471  * Dump the info for an irg.
1472  * Parsed by XVCG but not shown. use yComp.
1473  */
1474 static void dump_graph_info(FILE *F, ir_graph *irg)
1475 {
1476         fprintf(F, "info1: \"");
1477         dump_entity_to_file(F, get_irg_entity(irg));
1478         fprintf(F, "\n");
1479
1480         /* dump graph state */
1481         fprintf(F, "state:");
1482         if (is_irg_state(irg, IR_GRAPH_STATE_ARCH_DEP))
1483                 fprintf(F, " arch_dep");
1484         if (is_irg_state(irg, IR_GRAPH_STATE_MODEB_LOWERED))
1485                 fprintf(F, " modeb_lowered");
1486         if (is_irg_state(irg, IR_GRAPH_STATE_NORMALISATION2))
1487                 fprintf(F, " normalisation2");
1488         if (is_irg_state(irg, IR_GRAPH_STATE_IMPLICIT_BITFIELD_MASKING))
1489                 fprintf(F, " implicit_bitfield_masking");
1490         if (is_irg_state(irg, IR_GRAPH_STATE_OPTIMIZE_UNREACHABLE_CODE))
1491                 fprintf(F, " optimize_unreachable_code");
1492         if (is_irg_state(irg, IR_GRAPH_STATE_NO_CRITICAL_EDGES))
1493                 fprintf(F, " no_critical_edges");
1494         if (is_irg_state(irg, IR_GRAPH_STATE_NO_BADS))
1495                 fprintf(F, " no_bads");
1496         if (is_irg_state(irg, IR_GRAPH_STATE_NO_UNREACHABLE_CODE))
1497                 fprintf(F, " no_unreachable_code");
1498         if (is_irg_state(irg, IR_GRAPH_STATE_ONE_RETURN))
1499                 fprintf(F, " one_return");
1500         if (is_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_DOMINANCE))
1501                 fprintf(F, " consistent_dominance");
1502         if (is_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_POSTDOMINANCE))
1503                 fprintf(F, " consistent_postdominance");
1504         if (is_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_OUT_EDGES))
1505                 fprintf(F, " consistent_out_edges");
1506         if (is_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_OUTS))
1507                 fprintf(F, " consistent_outs");
1508         if (is_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_LOOPINFO))
1509                 fprintf(F, " consistent_loopinfo");
1510         if (is_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_ENTITY_USAGE))
1511                 fprintf(F, " consistent_entity_usage");
1512         if (is_irg_state(irg, IR_GRAPH_STATE_VALID_EXTENDED_BLOCKS))
1513                 fprintf(F, " valid_exended_blocks");
1514         fprintf(F, "\"\n");
1515 }
1516
1517 /** Dumps an irg as a graph clustered by block nodes.
1518  *  If interprocedural view edges can point to nodes out of this graph.
1519  */
1520 static void dump_graph_from_list(FILE *F, ir_graph *irg)
1521 {
1522         ir_entity *ent = get_irg_entity(irg);
1523
1524         fprintf(F, "graph: { title: ");
1525         print_irgid(F, irg);
1526         fprintf(F, " label: \"%s\" status:clustered color:%s\n",
1527           get_ent_dump_name(ent), color_names[ird_color_prog_background]);
1528
1529         dump_graph_info(F, irg);
1530         print_dbg_info(F, get_entity_dbg_info(ent));
1531
1532         dump_block_graph(F, irg);
1533
1534         /* Close the vcg information for the irg */
1535         fprintf(F, "}\n\n");
1536 }
1537
1538 /*******************************************************************/
1539 /* Basic type and entity nodes and edges.                          */
1540 /*******************************************************************/
1541
1542 /** dumps the edges between nodes and their type or entity attributes. */
1543 static void dump_node2type_edges(ir_node *n, void *env)
1544 {
1545         FILE *F = (FILE*)env;
1546         assert(n);
1547
1548         switch (get_irn_opcode(n)) {
1549         case iro_Const :
1550                 /* @@@ some consts have an entity */
1551                 break;
1552         case iro_SymConst:
1553                 if (SYMCONST_HAS_TYPE(get_SymConst_kind(n)))
1554                         print_node_type_edge(F,n,get_SymConst_type(n),NODE2TYPE_EDGE_ATTR);
1555                 break;
1556         case iro_Sel:
1557                 print_node_ent_edge(F,n,get_Sel_entity(n),NODE2TYPE_EDGE_ATTR);
1558                 break;
1559         case iro_Call:
1560                 print_node_type_edge(F,n,get_Call_type(n),NODE2TYPE_EDGE_ATTR);
1561                 break;
1562         case iro_Alloc:
1563                 print_node_type_edge(F,n,get_Alloc_type(n),NODE2TYPE_EDGE_ATTR);
1564                 break;
1565         case iro_Free:
1566                 print_node_type_edge(F,n,get_Free_type(n),NODE2TYPE_EDGE_ATTR);
1567                 break;
1568         case iro_Cast:
1569                 print_node_type_edge(F,n,get_Cast_type(n),NODE2TYPE_EDGE_ATTR);
1570                 break;
1571         default:
1572                 break;
1573         }
1574 }
1575
1576 static void print_typespecific_vcgattr(FILE *F, ir_type *tp)
1577 {
1578         switch (get_type_tpop_code(tp)) {
1579         case tpo_class:
1580                 fprintf(F, " " TYPE_CLASS_NODE_ATTR);
1581                 break;
1582         case tpo_struct:
1583                 fprintf(F, " " TYPE_METH_NODE_ATTR);
1584                 break;
1585         case tpo_method:
1586                 break;
1587         case tpo_union:
1588                 break;
1589         case tpo_array:
1590                 break;
1591         case tpo_enumeration:
1592                 break;
1593         case tpo_pointer:
1594                 break;
1595         case tpo_primitive:
1596                 break;
1597         default:
1598                 break;
1599         }
1600 }
1601
1602 void dump_type_node(FILE *F, ir_type *tp)
1603 {
1604         fprintf(F, "node: {title: ");
1605         print_typeid(F, tp);
1606         fprintf(F, " label: \"");
1607         if (tp->dbi != NULL) {
1608                 char buf[1024];
1609                 ir_print_type(buf, sizeof(buf), tp);
1610                 fprintf(F, "%s '%s'", get_type_tpop_name(tp), buf);
1611         } else {
1612                 ir_fprintf(F, "%+F", tp);
1613         }
1614         fputs("\" info1: \"", F);
1615         dump_type_to_file(F, tp);
1616         fprintf(F, "\"\n");
1617         print_type_dbg_info(F, get_type_dbg_info(tp));
1618         print_typespecific_vcgattr(F, tp);
1619         fprintf(F, "}\n");
1620 }
1621
1622 static void dump_entity_node(FILE *F, ir_entity *ent)
1623 {
1624         fprintf(F, "node: {title: ");
1625         print_entityid(F, ent);
1626         fprintf(F, " label: ");
1627         fprintf(F, "\"%s\" ", get_ent_dump_name(ent));
1628
1629         print_vcg_color(F, ird_color_entity);
1630         fprintf(F, "\n info1: \"");
1631
1632         dump_entity_to_file(F, ent);
1633
1634         fprintf(F, "\"\n");
1635         print_dbg_info(F, get_entity_dbg_info(ent));
1636         fprintf(F, "}\n");
1637 }
1638
1639 static void dump_enum_item(FILE *F, ir_type *tp, size_t pos)
1640 {
1641         char buf[1024];
1642         ir_enum_const *ec = get_enumeration_const(tp, pos);
1643         ident         *id = get_enumeration_const_nameid(ec);
1644         ir_tarval     *tv = get_enumeration_value(ec);
1645
1646         if (tv)
1647                 tarval_snprintf(buf, sizeof(buf), tv);
1648         else
1649                 strncpy(buf, "<not set>", sizeof(buf));
1650         fprintf(F, "node: {title: ");
1651         print_itemid(F, tp, pos);
1652         fprintf(F, " label: ");
1653         fprintf(F, "\"enum item %s\" " ENUM_ITEM_NODE_ATTR, get_id_str(id));
1654         fprintf(F, "\n info1: \"value: %s\"}\n", buf);
1655 }
1656
1657 /**
1658  * Dumps a new style initializer.
1659  */
1660 static void dump_entity_initializer(FILE *F, const ir_entity *ent)
1661 {
1662         /* TODO */
1663         (void) F;
1664         (void) ent;
1665 }
1666
1667 /**
1668  * type-walker: Dumps a type or entity and its edges.
1669  */
1670 static void dump_type_info(type_or_ent tore, void *env)
1671 {
1672         FILE *F = (FILE*)env;
1673         size_t i = 0;  /* to shutup gcc */
1674
1675         /* dump this type or entity */
1676
1677         switch (get_kind(tore.ent)) {
1678         case k_entity: {
1679                 ir_entity *ent = tore.ent;
1680                 ir_node *value;
1681                 /* The node */
1682                 dump_entity_node(F, ent);
1683                 /* The Edges */
1684                 /* skip this to reduce graph.  Member edge of type is parallel to this edge. *
1685                 fprintf(F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
1686                 ENT_OWN_EDGE_ATTR "}\n", ent, get_entity_owner(ent));*/
1687                 print_ent_type_edge(F,ent, get_entity_type(ent), ENT_TYPE_EDGE_ATTR);
1688                 if (is_Class_type(get_entity_owner(ent))) {
1689                         for (i = get_entity_n_overwrites(ent); i > 0;)
1690                                 print_ent_ent_edge(F, ent, get_entity_overwrites(ent, --i), 0, ird_color_none, ENT_OVERWRITES_EDGE_ATTR);
1691                 }
1692                 /* attached subgraphs */
1693                 if (! (flags & ir_dump_flag_no_entity_values)) {
1694                         if (ent->initializer != NULL) {
1695                                 /* new style initializers */
1696                                 dump_entity_initializer(F, ent);
1697                         } else if (entity_has_compound_ent_values(ent)) {
1698                                 /* old style compound entity values */
1699                                 for (i = get_compound_ent_n_values(ent); i > 0;) {
1700                                         value = get_compound_ent_value(ent, --i);
1701                                         if (value) {
1702                                                 print_ent_node_edge(F, ent, value, ENT_VALUE_EDGE_ATTR, i);
1703                                                 dump_const_expression(F, value);
1704                                                 print_ent_ent_edge(F, ent, get_compound_ent_value_member(ent, i), 0, ird_color_none, ENT_CORR_EDGE_ATTR, i);
1705                                                 /*
1706                                                 fprintf(F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
1707                                                 ENT_CORR_EDGE_ATTR  "}\n", GET_ENTID(ent),
1708                                                 get_compound_ent_value_member(ent, i), i);
1709                                                 */
1710                                         }
1711                                 }
1712                         }
1713                 }
1714                 break;
1715         }
1716         case k_type: {
1717                 ir_type *tp = tore.typ;
1718                 dump_type_node(F, tp);
1719                 /* and now the edges */
1720                 switch (get_type_tpop_code(tp)) {
1721                 case tpo_class:
1722                         for (i = get_class_n_supertypes(tp); i > 0;) {
1723                                 --i;
1724                                 print_type_type_edge(F, tp, get_class_supertype(tp, i), TYPE_SUPER_EDGE_ATTR);
1725                         }
1726                         for (i = get_class_n_members(tp); i > 0;) {
1727                                 --i;
1728                                 print_type_ent_edge(F, tp, get_class_member(tp, i), TYPE_MEMBER_EDGE_ATTR);
1729                         }
1730                         break;
1731                 case tpo_struct:
1732                         for (i = get_struct_n_members(tp); i > 0;) {
1733                                 --i;
1734                                 print_type_ent_edge(F, tp, get_struct_member(tp, i), TYPE_MEMBER_EDGE_ATTR);
1735                         }
1736                         break;
1737                 case tpo_method:
1738                         for (i = get_method_n_params(tp); i > 0;) {
1739                                 --i;
1740                                 print_type_type_edge(F, tp, get_method_param_type(tp, i), METH_PAR_EDGE_ATTR,i);
1741                         }
1742                         for (i = get_method_n_ress(tp); i > 0;) {
1743                                  --i;
1744                                 print_type_type_edge(F, tp, get_method_res_type(tp, i), METH_RES_EDGE_ATTR,i);
1745                         }
1746                         break;
1747                 case tpo_union:
1748                         for (i = get_union_n_members(tp); i > 0;) {
1749                                  --i;
1750                                 print_type_ent_edge(F, tp, get_union_member(tp, i), UNION_EDGE_ATTR);
1751                         }
1752                         break;
1753                 case tpo_array:
1754                         print_type_type_edge(F, tp, get_array_element_type(tp), ARR_ELT_TYPE_EDGE_ATTR);
1755                         print_type_ent_edge(F, tp, get_array_element_entity(tp), ARR_ENT_EDGE_ATTR);
1756                         for (i = get_array_n_dimensions(tp); i > 0;) {
1757                                 ir_node *upper, *lower;
1758
1759                                  --i;
1760                                 upper = get_array_upper_bound(tp, i);
1761                                 lower = get_array_lower_bound(tp, i);
1762                                 print_node_type_edge(F, upper, tp, "label: \"upper %zu\"", get_array_order(tp, i));
1763                                 print_node_type_edge(F, lower, tp, "label: \"lower %zu\"", get_array_order(tp, i));
1764                                 dump_const_expression(F, upper);
1765                                 dump_const_expression(F, lower);
1766                         }
1767                         break;
1768                 case tpo_enumeration:
1769                         for (i = get_enumeration_n_enums(tp); i > 0;) {
1770                                  --i;
1771                                 dump_enum_item(F, tp, i);
1772                                 print_enum_item_edge(F, tp, i, "label: \"item %zu\"", i);
1773                         }
1774                         break;
1775                 case tpo_pointer:
1776                         print_type_type_edge(F, tp, get_pointer_points_to_type(tp), PTR_PTS_TO_EDGE_ATTR);
1777                         break;
1778                 case tpo_unknown:
1779                 case tpo_code:
1780                 case tpo_uninitialized:
1781                 case tpo_none:
1782                 case tpo_primitive:
1783                         break;
1784                 }
1785                 break; /* case k_type */
1786         }
1787         default:
1788                 printf(" *** irdump,  dump_type_info(l.%i), faulty type.\n", __LINE__);
1789         }
1790 }
1791
1792 /** For dumping class hierarchies.
1793  * Dumps a class type node and a superclass edge.
1794  */
1795 static void dump_class_hierarchy_node(type_or_ent tore, void *ctx)
1796 {
1797         FILE *F = (FILE*)ctx;
1798         size_t i = 0;  /* to shutup gcc */
1799
1800         /* dump this type or entity */
1801         switch (get_kind(tore.ent)) {
1802         case k_entity: {
1803                 ir_entity *ent = tore.ent;
1804                 if (get_entity_owner(ent) == get_glob_type()) break;
1805                 if (!is_Method_type(get_entity_type(ent)))
1806                         break;  /* GL */
1807                 if (flags & ir_dump_flag_entities_in_hierarchy
1808                                 && is_Class_type(get_entity_owner(ent))) {
1809                         /* The node */
1810                         dump_entity_node(F, ent);
1811                         /* The edges */
1812                         print_type_ent_edge(F, get_entity_owner(ent), ent, TYPE_MEMBER_EDGE_ATTR);
1813                         for (i = get_entity_n_overwrites(ent); i > 0;) {
1814                                  --i;
1815                                 print_ent_ent_edge(F, get_entity_overwrites(ent, i), ent, 0, ird_color_none, ENT_OVERWRITES_EDGE_ATTR);
1816                         }
1817                 }
1818                 break;
1819         }
1820         case k_type: {
1821                 ir_type *tp = tore.typ;
1822                 if (tp == get_glob_type())
1823                         break;
1824                 switch (get_type_tpop_code(tp)) {
1825                 case tpo_class:
1826                         dump_type_node(F, tp);
1827                         /* and now the edges */
1828                         for (i = get_class_n_supertypes(tp); i > 0;) {
1829                                  --i;
1830                                 print_type_type_edge(F,tp,get_class_supertype(tp, i),TYPE_SUPER_EDGE_ATTR);
1831                         }
1832                         break;
1833                 default: break;
1834                 }
1835                 break; /* case k_type */
1836         }
1837         default:
1838                 printf(" *** irdump,  dump_class_hierarchy_node(l.%i), faulty type.\n", __LINE__);
1839         }
1840 }
1841
1842 /*******************************************************************/
1843 /* dump analysis information that is expressed in graph terms.     */
1844 /*******************************************************************/
1845
1846 /* dump out edges */
1847 static void dump_out_edge(ir_node *n, void *env)
1848 {
1849         FILE *F = (FILE*)env;
1850         int i;
1851         for (i = get_irn_n_outs(n) - 1; i >= 0; --i) {
1852                 ir_node *succ = get_irn_out(n, i);
1853                 assert(succ);
1854                 print_node_edge_kind(F, succ);
1855                 fprintf(F, "{sourcename: ");
1856                 print_nodeid(F, n);
1857                 fprintf(F, " targetname: ");
1858                 print_nodeid(F, succ);
1859                 fprintf(F, " color: red linestyle: dashed");
1860                 fprintf(F, "}\n");
1861         }
1862 }
1863
1864 static void dump_loop_label(FILE *F, const ir_loop *loop)
1865 {
1866         fprintf(F, "loop %u", get_loop_depth(loop));
1867 }
1868
1869 static void dump_loop_info(FILE *F, const ir_loop *loop)
1870 {
1871         fprintf(F, " info1: \"");
1872         fprintf(F, " loop nr: %ld", get_loop_loop_nr(loop));
1873 #ifdef DEBUG_libfirm
1874         fprintf(F, "\n The loop was analyzed %ld times.", (long int) PTR_TO_INT(get_loop_link(loop)));
1875 #endif
1876         fprintf(F, "\"");
1877 }
1878
1879 void print_loopid(FILE *F, const ir_loop *loop)
1880 {
1881         fprintf(F, "\"l%ld\"", get_loop_loop_nr(loop));
1882 }
1883
1884 static void dump_loop_node(FILE *F, const ir_loop *loop)
1885 {
1886         fprintf(F, "node: {title: ");
1887         print_loopid(F, loop);
1888         fprintf(F, " label: \"");
1889         dump_loop_label(F, loop);
1890         fprintf(F, "\" ");
1891         dump_loop_info(F, loop);
1892         fprintf(F, "}\n");
1893 }
1894
1895 static void dump_loop_node_edge(FILE *F, const ir_loop *loop, size_t i)
1896 {
1897         assert(loop);
1898         fprintf(F, "edge: {sourcename: ");
1899         print_loopid(F, loop);
1900         fprintf(F, " targetname: ");
1901         print_nodeid(F, get_loop_element(loop, i).node);
1902         fprintf(F, " color: green");
1903         fprintf(F, "}\n");
1904 }
1905
1906 static void dump_loop_son_edge(FILE *F, const ir_loop *loop, size_t i)
1907 {
1908         assert(loop);
1909         fprintf(F, "edge: {sourcename: ");
1910         print_loopid(F, loop);
1911         fprintf(F, " targetname: ");
1912         print_loopid(F, get_loop_element(loop, i).son);
1913         ir_fprintf(F, " color: darkgreen label: \"%zu\"}\n", i);
1914 }
1915
1916 static void dump_loops(FILE *F, const ir_loop *loop)
1917 {
1918         size_t i;
1919         size_t n_elements = get_loop_n_elements(loop);
1920         /* dump this loop node */
1921         dump_loop_node(F, loop);
1922
1923         /* dump edges to nodes in loop -- only if it is a real loop */
1924         if (get_loop_depth(loop) != 0) {
1925                 for (i = n_elements; i > 0;) {
1926                         loop_element element;
1927                         --i;
1928                         element = get_loop_element(loop, i);
1929                         if (*element.kind != k_ir_node)
1930                                 continue;
1931                         dump_loop_node_edge(F, loop, i);
1932                 }
1933         }
1934         for (i = n_elements; i > 0;) {
1935                 loop_element element;
1936                 --i;
1937                 element = get_loop_element(loop, i);
1938                 if (*element.kind != k_ir_loop)
1939                         continue;
1940                 dump_loops(F, element.son);
1941                 dump_loop_son_edge(F, loop, i);
1942         }
1943 }
1944
1945 static void dump_loop_nodes_into_graph(FILE *F, ir_graph *irg)
1946 {
1947         ir_loop *loop = get_irg_loop(irg);
1948         if (loop != NULL) {
1949                 dump_loops(F, loop);
1950         }
1951 }
1952
1953 void dump_vcg_header_colors(FILE *F)
1954 {
1955         int i;
1956         init_colors();
1957         for (i = 0; i < ird_color_count; ++i) {
1958                 if (color_rgb[i] != NULL) {
1959                         fprintf(F, "colorentry %s: %s\n", color_names[i], color_rgb[i]);
1960                 }
1961         }
1962 }
1963
1964 void dump_vcg_infonames(FILE *F)
1965 {
1966         fputs(
1967                 "infoname 1: \"Attribute\"\n"
1968                 "infoname 2: \"Verification errors\"\n"
1969                 "infoname 3: \"Debug info\"\n", F);
1970 }
1971
1972 /**
1973  * dumps the VCG header
1974  */
1975 void dump_vcg_header(FILE *F, const char *name, const char *layout, const char *orientation)
1976 {
1977         const char *label
1978                 = (flags & ir_dump_flag_disable_edge_labels) ? "no" : "yes";
1979
1980         if (! layout)     layout = "Compilergraph";
1981         if (!orientation) orientation = "bottom_to_top";
1982
1983         /* print header */
1984         fprintf(F,
1985                 "graph: { title: \"ir graph of %s\"\n"
1986                 "display_edge_labels: %s\n"
1987                 "layoutalgorithm: mindepth //$ \"%s\"\n"
1988                 "manhattan_edges: yes\n"
1989                 "port_sharing: no\n"
1990                 "orientation: %s\n"
1991                 "classname 1:  \"intrablock Data\"\n"
1992                 "classname 2:  \"Block\"\n"
1993                 "classname 3:  \"Entity type\"\n"
1994                 "classname 4:  \"Entity owner\"\n"
1995                 "classname 5:  \"Method Param\"\n"
1996                 "classname 6:  \"Method Res\"\n"
1997                 "classname 7:  \"Super\"\n"
1998                 "classname 8:  \"Union\"\n"
1999                 "classname 9:  \"Points-to\"\n"
2000                 "classname 10: \"Array Element Type\"\n"
2001                 "classname 11: \"Overwrites\"\n"
2002                 "classname 12: \"Member\"\n"
2003                 "classname 13: \"Control Flow\"\n"
2004                 "classname 14: \"intrablock Memory\"\n"
2005                 "classname 15: \"Dominators\"\n"
2006                 "classname 16: \"interblock Data\"\n"
2007                 "classname 17: \"interblock Memory\"\n"
2008                 "classname 18: \"Exception Control Flow for Interval Analysis\"\n"
2009                 "classname 19: \"Postdominators\"\n"
2010                 "classname 20: \"Keep Alive\"\n"
2011                 "classname 21: \"Out Edges\"\n"
2012                 "classname 22: \"Macro Block Edges\"\n",
2013                 name, label, layout, orientation);
2014         dump_vcg_infonames(F);
2015         dump_vcg_header_colors(F);
2016         fprintf(F, "\n");
2017 }
2018
2019 /**
2020  * Dumps the vcg file footer
2021  */
2022 void dump_vcg_footer(FILE *F)
2023 {
2024         fprintf(F, "}\n");
2025 }
2026
2027
2028
2029 static void dump_blocks_as_subgraphs(FILE *out, ir_graph *irg)
2030 {
2031         size_t i;
2032
2033         construct_block_lists(irg);
2034
2035         /*
2036          * If we are in the interprocedural view, we dump not
2037          * only the requested irg but also all irgs that can be reached
2038          * from irg.
2039          */
2040         for (i = get_irp_n_irgs(); i > 0;) {
2041                 ir_graph *other_irg = get_irp_irg(--i);
2042                 ir_node **arr = (ir_node**)ird_get_irg_link(other_irg);
2043                 if (arr == NULL)
2044                         continue;
2045
2046                 dump_graph_from_list(out, other_irg);
2047                 DEL_ARR_F(arr);
2048         }
2049 }
2050
2051 /** dumps a graph extended block-wise. Expects all blockless nodes in arr in irgs link.
2052  *  The outermost nodes: blocks and nodes not op_pin_state_pinned, Bad, Unknown. */
2053 static void dump_extblock_graph(FILE *F, ir_graph *irg)
2054 {
2055         size_t i, arr_len;
2056         ir_extblk **arr = (ir_extblk**)ird_get_irg_link(irg);
2057
2058         for (i = 0, arr_len = ARR_LEN(arr); i < arr_len; ++i) {
2059                 ir_extblk *extbb = arr[i];
2060                 ir_node *leader = get_extbb_leader(extbb);
2061                 size_t j, n_blks;
2062
2063                 fprintf(F, "graph: { title: \"");
2064                 fprintf(F, "x%ld", get_irn_node_nr(leader));
2065                 fprintf(F, "\"  label: \"ExtBB %ld\" status:clustered color:lightgreen\n",
2066                         get_irn_node_nr(leader));
2067
2068                 for (j = 0, n_blks = ARR_LEN(extbb->blks); j < n_blks; ++j) {
2069                         ir_node *node = extbb->blks[j];
2070                         if (is_Block(node)) {
2071                         /* Dumps the block and all the nodes in the block, which are to
2072                                 be found in Block->link. */
2073                                 dump_whole_block(F, node);
2074                         } else {
2075                                 /* Nodes that are not in a Block. */
2076                                 dump_node(F, node);
2077                                 if (is_Bad(get_nodes_block(node)) && !node_floats(node)) {
2078                                         dump_const_block_local(F, node);
2079                                 }
2080                                 dump_ir_data_edges(F, node);
2081                         }
2082                 }
2083                 fprintf(F, "}\n");
2084         }
2085
2086         if ((flags & ir_dump_flag_loops)
2087                         && (is_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_LOOPINFO)))
2088                 dump_loop_nodes_into_graph(F, irg);
2089
2090         free_extbb(irg);
2091 }
2092
2093 static void dump_blocks_extbb_grouped(FILE *F, ir_graph *irg)
2094 {
2095         size_t    i;
2096         ir_entity *ent = get_irg_entity(irg);
2097
2098         if (!is_irg_state(irg, IR_GRAPH_STATE_VALID_EXTENDED_BLOCKS))
2099                 compute_extbb(irg);
2100
2101         construct_extblock_lists(irg);
2102
2103         fprintf(F, "graph: { title: ");
2104         print_irgid(F, irg);
2105         fprintf(F, " label: \"%s\" status:clustered color: white\n",
2106                 get_ent_dump_name(ent));
2107
2108         dump_graph_info(F, irg);
2109         print_dbg_info(F, get_entity_dbg_info(ent));
2110
2111         for (i = get_irp_n_irgs(); i > 0;) {
2112                 ir_graph   *other_irg = get_irp_irg(--i);
2113                 list_tuple *lists     = (list_tuple*)ird_get_irg_link(other_irg);
2114
2115                 if (lists) {
2116                         /* dump the extended blocks first */
2117                         if (ARR_LEN(lists->extbb_list)) {
2118                                 ird_set_irg_link(other_irg, lists->extbb_list);
2119                                 dump_extblock_graph(F, other_irg);
2120                         }
2121
2122                         /* we may have blocks without extended blocks, bad for instance */
2123                         if (ARR_LEN(lists->blk_list)) {
2124                                 ird_set_irg_link(other_irg, lists->blk_list);
2125                                 dump_block_graph(F, other_irg);
2126                         }
2127
2128                         DEL_ARR_F(lists->extbb_list);
2129                         DEL_ARR_F(lists->blk_list);
2130                         xfree(lists);
2131                 }
2132         }
2133
2134         /* Close the vcg information for the irg */
2135         fprintf(F, "}\n\n");
2136
2137         free_extbb(irg);
2138 }
2139
2140 void dump_ir_graph_file(FILE *out, ir_graph *irg)
2141 {
2142         dump_vcg_header(out, get_irg_dump_name(irg), NULL, NULL);
2143
2144         /* dump nodes */
2145         if (flags & ir_dump_flag_blocks_as_subgraphs) {
2146                 if (flags & ir_dump_flag_group_extbb) {
2147                         dump_blocks_extbb_grouped(out, irg);
2148                 } else {
2149                         dump_blocks_as_subgraphs(out, irg);
2150                 }
2151         } else {
2152                 /* dump_node_with_edges must be called in post visiting predecessors */
2153                 ird_walk_graph(irg, NULL, dump_node_with_edges, out);
2154         }
2155
2156         /* dump type info */
2157         if (flags & ir_dump_flag_with_typegraph) {
2158                 type_walk_irg(irg, dump_type_info, NULL, out);
2159                 inc_irg_visited(get_const_code_irg());
2160                 /* dump edges from graph to type info */
2161                 irg_walk(get_irg_end(irg), dump_node2type_edges, NULL, out);
2162         }
2163
2164         /* dump iredges out edges */
2165         if ((flags & ir_dump_flag_iredges) && edges_activated(irg)) {
2166                 irg_walk_edges(get_irg_start_block(irg), dump_ir_edges, NULL, out);
2167         }
2168
2169         /* dump the out edges in a separate walk */
2170         if ((flags & ir_dump_flag_out_edges)
2171                         && (is_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_OUTS))) {
2172                 irg_out_walk(get_irg_start(irg), dump_out_edge, NULL, out);
2173         }
2174
2175         dump_vcg_footer(out);
2176 }
2177
2178 static void dump_block_to_cfg(ir_node *block, void *env)
2179 {
2180         FILE *F = (FILE*)env;
2181         int i;
2182
2183         if (is_Bad(block) && get_irn_mode(block) == mode_X) {
2184                 dump_node(F, block);
2185         }
2186
2187         if (is_Block(block)) {
2188                 /* This is a block. Dump a node for the block. */
2189                 fprintf(F, "node: {title: ");
2190                 print_nodeid(F, block);
2191                 fprintf(F, " label: \"");
2192                 if (block == get_irg_start_block(get_irn_irg(block)))
2193                         fprintf(F, "Start ");
2194                 if (block == get_irg_end_block(get_irn_irg(block)))
2195                         fprintf(F, "End ");
2196
2197                 fprintf(F, "%s ", get_op_name(get_irn_op(block)));
2198                 print_nodeid(F, block);
2199                 fprintf(F, "\" ");
2200                 fprintf(F, "info1:\"");
2201
2202                 /* the generic version. */
2203                 dump_irnode_to_file(F, block);
2204
2205                 fprintf(F, "\"");  /* closing quote of info */
2206
2207                 if ((block == get_irg_start_block(get_irn_irg(block))) ||
2208                         (block == get_irg_end_block(get_irn_irg(block)))     )
2209                         fprintf(F, " color:blue ");
2210
2211                 fprintf(F, "}\n");
2212
2213                 /* Dump the edges */
2214                 for (i = get_Block_n_cfgpreds(block) - 1; i >= 0; --i) {
2215                         ir_node *pred = get_Block_cfgpred(block, i);
2216                         if (!is_Bad(pred))
2217                                 pred = get_nodes_block(pred);
2218                         fprintf(F, "edge: { sourcename: ");
2219                         print_nodeid(F, block);
2220                         fprintf(F, " targetname: ");
2221                         print_nodeid(F, pred);
2222                         fprintf(F, "\"}\n");
2223                 }
2224
2225                 /* Dump dominator/postdominator edge */
2226                 if (ir_get_dump_flags() & ir_dump_flag_dominance) {
2227                         if (is_irg_state(get_irn_irg(block), IR_GRAPH_STATE_CONSISTENT_DOMINANCE) && get_Block_idom(block)) {
2228                                 ir_node *pred = get_Block_idom(block);
2229                                 fprintf(F, "edge: { sourcename: ");
2230                                 print_nodeid(F, block);
2231                                 fprintf(F, " targetname: ");
2232                                 print_nodeid(F, pred);
2233                                 fprintf(F, " " DOMINATOR_EDGE_ATTR "}\n");
2234                         }
2235                         if (is_irg_state(get_irn_irg(block), IR_GRAPH_STATE_CONSISTENT_POSTDOMINANCE) && get_Block_ipostdom(block)) {
2236                                 ir_node *pred = get_Block_ipostdom(block);
2237                                 fprintf(F, "edge: { sourcename: ");
2238                                 print_nodeid(F, block);
2239                                 fprintf(F, " targetname: ");
2240                                 print_nodeid(F, pred);
2241                                 fprintf(F, " " POSTDOMINATOR_EDGE_ATTR "}\n");
2242                         }
2243                 }
2244         }
2245 }
2246
2247 void dump_cfg(FILE *F, ir_graph *irg)
2248 {
2249         dump_vcg_header(F, get_irg_dump_name(irg), NULL, NULL);
2250
2251         /* walk over the blocks in the graph */
2252         irg_walk_graph(irg, dump_block_to_cfg, NULL, F);
2253
2254         dump_vcg_footer(F);
2255 }
2256
2257 void dump_callgraph(FILE *F)
2258 {
2259         size_t          i;
2260         ir_dump_flags_t old_flags = ir_get_dump_flags();
2261
2262         ir_remove_dump_flags(ir_dump_flag_disable_edge_labels);
2263         dump_vcg_header(F, "Callgraph", "Hierarchic", NULL);
2264
2265         for (i = get_irp_n_irgs(); i > 0;) {
2266                 ir_graph *irg = get_irp_irg(--i);
2267                 ir_entity *ent = get_irg_entity(irg);
2268                 size_t j, n_callees = get_irg_n_callees(irg);
2269
2270                 dump_entity_node(F, ent);
2271                 for (j = 0; j < n_callees; ++j) {
2272                         ir_entity  *c    = get_irg_entity(get_irg_callee(irg, j));
2273                         int         be   = is_irg_callee_backedge(irg, j);
2274                         const char *attr = be
2275                                 ? "label:\"recursion %zu\""
2276                                 : "label:\"calls %zu\"";
2277                         print_ent_ent_edge(F, ent, c, be, ird_color_entity, attr,
2278                                            get_irg_callee_loop_depth(irg, j));
2279                 }
2280         }
2281
2282         ir_set_dump_flags(old_flags);
2283         dump_vcg_footer(F);
2284 }
2285
2286 void dump_typegraph(FILE *out)
2287 {
2288         dump_vcg_header(out, "All_types", NULL, NULL);
2289         type_walk(dump_type_info, NULL, out);
2290         dump_vcg_footer(out);
2291 }
2292
2293 void dump_class_hierarchy(FILE *out)
2294 {
2295         dump_vcg_header(out, "class_hierarchy", NULL, NULL);
2296         type_walk(dump_class_hierarchy_node, NULL, out);
2297         dump_vcg_footer(out);
2298 }
2299
2300 static void dump_loops_standalone(FILE *F, ir_loop *loop)
2301 {
2302         size_t i;
2303         bool   loop_node_started = false;
2304         size_t first      = 0;
2305         size_t son_number = 0;
2306         loop_element le;
2307         ir_loop *son = NULL;
2308
2309         /* Dump a new loop node. */
2310         dump_loop_node(F, loop);
2311
2312         /* Dump the loop elements. */
2313         for (i = 0; i < get_loop_n_elements(loop); i++) {
2314                 le = get_loop_element(loop, i);
2315                 son = le.son;
2316                 if (get_kind(son) == k_ir_loop) {
2317
2318                         /* We are a loop son -> Recurse */
2319
2320                         if (loop_node_started) { /* Close the "firm-nodes" node first if we started one. */
2321                                 fprintf(F, "\" }\n");
2322                                 fprintf(F, "edge: {sourcename: ");
2323                                 print_loopid(F, loop);
2324                                 fprintf(F, " targetname: \"l%ld-%lu-nodes\" label:\"%lu...%lu\"}\n",
2325                                         get_loop_loop_nr(loop),
2326                                                 (unsigned long) first,
2327                                                 (unsigned long) first,
2328                                         (unsigned long) i-1);
2329                                 loop_node_started = false;
2330                         }
2331                         dump_loop_son_edge(F, loop, son_number++);
2332                         dump_loops_standalone(F, son);
2333                 } else if (get_kind(son) == k_ir_node) {
2334                         /* We are a loop node -> Collect firm nodes */
2335
2336                         ir_node *n = le.node;
2337                         if (!loop_node_started) {
2338                                 /* Start a new node which contains all firm nodes of the current loop */
2339                                 fprintf(F, "node: { title: \"l%ld-%lu-nodes\" color: lightyellow label: \"",
2340                                         get_loop_loop_nr(loop),
2341                                         (unsigned long)i);
2342                                 loop_node_started = true;
2343                                 first = i;
2344                         } else
2345                                 fprintf(F, "\n");
2346
2347                         dump_node_label(F, n);
2348                         if (has_backedges(n)) fprintf(F, "\t loop head!");
2349                 } else { /* for callgraph loop tree */
2350                         ir_graph *n;
2351                         assert(get_kind(son) == k_ir_graph);
2352
2353                         /* We are a loop node -> Collect firm graphs */
2354                         n = le.irg;
2355                         if (!loop_node_started) {
2356                                 /* Start a new node which contains all firm nodes of the current loop */
2357                                 fprintf(F, "node: { title: \"l%ld-%lu-nodes\" color: lightyellow label: \"",
2358                                         get_loop_loop_nr(loop),
2359                                         (unsigned long)i);
2360                                 loop_node_started = true;
2361                                 first = i;
2362                         } else
2363                                 fprintf(F, "\n");
2364                         fprintf(F, " %s", get_irg_dump_name(n));
2365                         /* fprintf(F, " %s (depth %d)", get_irg_dump_name(n), n->callgraph_weighted_loop_depth); */
2366                 }
2367         }
2368
2369         if (loop_node_started) {
2370                 fprintf(F, "\" }\n");
2371                 fprintf(F, "edge: {sourcename: \"");
2372                 print_loopid(F, loop);
2373                 fprintf(F, "\" targetname: \"l%ld-%lu-nodes\" label:\"%lu...%lu\"}\n",
2374                         get_loop_loop_nr(loop),
2375                         (unsigned long) first,
2376                         (unsigned long) first,
2377                         (unsigned long) i-1);
2378                 loop_node_started = false;
2379         }
2380 }
2381
2382 void dump_loop_tree(FILE *out, ir_graph *irg)
2383 {
2384         ir_dump_flags_t old_flags = ir_get_dump_flags();
2385
2386         ir_remove_dump_flags(ir_dump_flag_disable_edge_labels);
2387
2388         dump_vcg_header(out, get_irg_dump_name(irg), "Tree", "top_to_bottom");
2389
2390         if (get_irg_loop(irg))
2391                 dump_loops_standalone(out, get_irg_loop(irg));
2392
2393         dump_vcg_footer(out);
2394
2395         ir_set_dump_flags(old_flags);
2396 }
2397
2398 void dump_callgraph_loop_tree(FILE *out)
2399 {
2400         dump_vcg_header(out, "callgraph looptree", "Tree", "top_to_bottom");
2401         dump_loops_standalone(out, irp->outermost_cg_loop);
2402         dump_vcg_footer(out);
2403 }
2404
2405 static void collect_nodeloop(FILE *F, ir_loop *loop, pset *loopnodes)
2406 {
2407         size_t i;
2408         int    son_number = 0;
2409         int    node_number = 0;
2410
2411         if (flags & ir_dump_flag_loops)
2412                 dump_loop_node(F, loop);
2413
2414         for (i = 0; i < get_loop_n_elements(loop); i++) {
2415                 loop_element le = get_loop_element(loop, i);
2416                 if (*(le.kind) == k_ir_loop) {
2417                         if (flags & ir_dump_flag_loops)
2418                                 dump_loop_son_edge(F, loop, son_number++);
2419                         /* Recur */
2420                         collect_nodeloop(F, le.son, loopnodes);
2421                 } else {
2422                         if (flags & ir_dump_flag_loops)
2423                                 dump_loop_node_edge(F, loop, node_number++);
2424                         pset_insert_ptr(loopnodes, le.node);
2425                 }
2426         }
2427 }
2428
2429 static void collect_nodeloop_external_nodes(ir_loop *loop, pset *loopnodes,
2430                                             pset *extnodes)
2431 {
2432         size_t i;
2433         int j, start;
2434
2435         for (i = 0; i < get_loop_n_elements(loop); i++) {
2436                 loop_element le = get_loop_element(loop, i);
2437                 if (*(le.kind) == k_ir_loop) {
2438                         /* Recur */
2439                         collect_nodeloop_external_nodes(le.son, loopnodes, extnodes);
2440                 } else {
2441                         if (is_Block(le.node)) start = 0; else start = -1;
2442                         for (j = start; j < get_irn_arity(le.node); j++) {
2443                                 ir_node *pred = get_irn_n(le.node, j);
2444                                 if (!pset_find_ptr(loopnodes, pred)) {
2445                                         pset_insert_ptr(extnodes, pred);
2446                                         if (!is_Block(pred)) {
2447                                                 pred = get_nodes_block(pred);
2448                                                 if (!pset_find_ptr(loopnodes, pred))
2449                                                         pset_insert_ptr(extnodes, pred);
2450                                         }
2451                                 }
2452                         }
2453                 }
2454         }
2455 }
2456
2457 void dump_loop(FILE *F, ir_loop *l)
2458 {
2459         pset *loopnodes = pset_new_ptr_default();
2460         pset *extnodes  = pset_new_ptr_default();
2461         ir_node *n, *b;
2462         char name[50];
2463
2464         snprintf(name, sizeof(name), "loop_%ld", get_loop_loop_nr(l));
2465         dump_vcg_header(F, name, NULL, NULL);
2466
2467         /* collect all nodes to dump */
2468         collect_nodeloop(F, l, loopnodes);
2469         collect_nodeloop_external_nodes(l, loopnodes, extnodes);
2470
2471         /* build block lists */
2472         foreach_pset(loopnodes, ir_node*, n) {
2473                 set_irn_link(n, NULL);
2474         }
2475         foreach_pset(extnodes, ir_node*, n) {
2476                 set_irn_link(n, NULL);
2477         }
2478         foreach_pset(loopnodes, ir_node*, n) {
2479                 if (!is_Block(n)) {
2480                         b = get_nodes_block(n);
2481                         set_irn_link(n, get_irn_link(b));
2482                         set_irn_link(b, n);
2483                 }
2484         }
2485         foreach_pset(extnodes, ir_node*, n) {
2486                 if (!is_Block(n)) {
2487                         b = get_nodes_block(n);
2488                         set_irn_link(n, get_irn_link(b));
2489                         set_irn_link(b, n);
2490                 }
2491         }
2492
2493         foreach_pset(loopnodes, ir_node*, b) {
2494                 if (is_Block(b)) {
2495                         fprintf(F, "graph: { title: ");
2496                         print_nodeid(F, b);
2497                         fprintf(F, "  label: \"");
2498                         dump_node_opcode(F, b);
2499                         fprintf(F, " %ld:%u", get_irn_node_nr(b), get_irn_idx(b));
2500                         fprintf(F, "\" status:clustered color:yellow\n");
2501
2502                         /* dump the blocks edges */
2503                         dump_ir_data_edges(F, b);
2504
2505                         /* dump the nodes that go into the block */
2506                         for (n = (ir_node*)get_irn_link(b); n; n = (ir_node*)get_irn_link(n)) {
2507                                 if (pset_find_ptr(extnodes, n))
2508                                         overrule_nodecolor = ird_color_block_inout;
2509                                 dump_node(F, n);
2510                                 overrule_nodecolor = ird_color_default_node;
2511                                 if (!pset_find_ptr(extnodes, n)) dump_ir_data_edges(F, n);
2512                         }
2513
2514                         /* Close the vcg information for the block */
2515                         fprintf(F, "}\n");
2516                         dump_const_node_local(F, b);
2517                         fprintf(F, "\n");
2518                 }
2519         }
2520         foreach_pset(extnodes, ir_node*, b) {
2521                 if (is_Block(b)) {
2522                         fprintf(F, "graph: { title: ");
2523                         print_nodeid(F, b);
2524                         fprintf(F, " label: \"");
2525                         dump_node_opcode(F, b);
2526                         fprintf(F, " %ld:%u", get_irn_node_nr(b), get_irn_idx(b));
2527                         fprintf(F, "\" status:clustered color:lightblue\n");
2528
2529                         /* dump the nodes that go into the block */
2530                         for (n = (ir_node*)get_irn_link(b); n; n = (ir_node*)get_irn_link(n)) {
2531                                 if (!pset_find_ptr(loopnodes, n))
2532                                         overrule_nodecolor = ird_color_block_inout;
2533                                 dump_node(F, n);
2534                                 overrule_nodecolor = ird_color_default_node;
2535                                 if (pset_find_ptr(loopnodes, n)) dump_ir_data_edges(F, n);
2536                         }
2537
2538                         /* Close the vcg information for the block */
2539                         fprintf(F, "}\n");
2540                         dump_const_node_local(F, b);
2541                         fprintf(F, "\n");
2542                 }
2543         }
2544         del_pset(loopnodes);
2545         del_pset(extnodes);
2546
2547         dump_vcg_footer(F);
2548 }
2549
2550 static bool   obstack_init;
2551 static struct obstack obst;
2552 static char  *dump_path;
2553
2554 void ir_set_dump_path(const char *path)
2555 {
2556         xfree(dump_path);
2557         dump_path = xstrdup(path);
2558 }
2559
2560 static void add_string_escaped(const char *string)
2561 {
2562         const char *p;
2563         for (p = string; *p != '\0'; ++p) {
2564                 char c = *p;
2565                 if (c == '/') {
2566                         obstack_1grow(&obst, '@');
2567                         obstack_1grow(&obst, '1');
2568                 } else if (c == '@') {
2569                         obstack_1grow(&obst, '@');
2570                         obstack_1grow(&obst, '2');
2571                 } else {
2572                         obstack_1grow(&obst, c);
2573                 }
2574         }
2575 }
2576
2577 static void add_dump_path(void)
2578 {
2579         if (!obstack_init) {
2580                 obstack_init(&obst);
2581                 obstack_init = true;
2582         }
2583
2584         if (dump_path != NULL) {
2585                 size_t len = strlen(dump_path);
2586                 obstack_grow(&obst, dump_path, len);
2587                 if (len > 0 && dump_path[len-1] != '/')
2588                         obstack_1grow(&obst, '/');
2589         }
2590 }
2591
2592 void dump_ir_graph_ext(ir_graph_dump_func func, ir_graph *graph,
2593                        const char *suffix)
2594 {
2595         const char *dump_name = get_irg_dump_name(graph);
2596         char       *file_name;
2597         FILE       *out;
2598
2599         if (!ir_should_dump(dump_name))
2600                 return;
2601
2602         add_dump_path();
2603
2604         add_string_escaped(dump_name);
2605         obstack_printf(&obst, "-%02u", graph->dump_nr++);
2606
2607         if (suffix != NULL) {
2608                 if (suffix[0] != '.')
2609                         obstack_1grow(&obst, '-');
2610                 add_string_escaped(suffix);
2611         }
2612         obstack_1grow(&obst, '\0');
2613
2614         file_name = (char*)obstack_finish(&obst);
2615         /* xvcg expects only <LF> so we need "b"inary mode (for win32) */
2616         out       = fopen(file_name, "wb");
2617         obstack_free(&obst, file_name);
2618
2619         if (out == NULL) {
2620                 fprintf(stderr, "Couldn't open '%s': %s\n", file_name, strerror(errno));
2621                 return;
2622         }
2623
2624         func(out, graph);
2625         fclose(out);
2626 }
2627
2628 void dump_ir_prog_ext(ir_prog_dump_func func, const char *suffix)
2629 {
2630         char *file_name;
2631         FILE *out;
2632
2633         add_dump_path();
2634
2635         obstack_printf(&obst, "%02u", irp->dump_nr++);
2636         if (suffix != NULL) {
2637                 if (suffix[0] != '.')
2638                         obstack_1grow(&obst, '-');
2639                 add_string_escaped(suffix);
2640         }
2641         obstack_1grow(&obst, '\0');
2642
2643         file_name = (char*)obstack_finish(&obst);
2644         out       = fopen(file_name, "wb");
2645         obstack_free(&obst, file_name);
2646
2647         if (out == NULL) {
2648                 fprintf(stderr, "Couldn't open '%s': %s\n", file_name, strerror(errno));
2649                 return;
2650         }
2651         func(out);
2652         fclose(out);
2653 }
2654
2655 void dump_ir_graph(ir_graph *graph, const char *suffix)
2656 {
2657         char buf[256];
2658
2659         snprintf(buf, sizeof(buf), "%s.vcg", suffix);
2660         dump_ir_graph_ext(dump_ir_graph_file, graph, buf);
2661 }
2662
2663 void dump_all_ir_graphs(const char *suffix)
2664 {
2665         size_t i, n_irgs = get_irp_n_irgs();
2666
2667         for (i = 0; i < n_irgs; ++i) {
2668                 ir_graph *irg = get_irp_irg(i);
2669                 dump_ir_graph(irg, suffix);
2670         }
2671 }
2672
2673 typedef struct pass_t {
2674         ir_prog_pass_t pass;
2675         char           suffix[1];
2676 } pass_t;
2677
2678 /**
2679  * Wrapper around dump_all_ir_graphs().
2680  */
2681 static int dump_all_ir_graphs_wrapper(ir_prog *irp, void *context)
2682 {
2683         pass_t *pass = (pass_t*)context;
2684
2685         (void)irp;
2686         dump_all_ir_graphs(pass->suffix);
2687         return 0;
2688 }
2689
2690 ir_prog_pass_t *dump_all_ir_graph_pass(const char *name, const char *suffix)
2691 {
2692         size_t  len  = strlen(suffix) + 1;
2693         pass_t *pass = XMALLOCF(pass_t, suffix, len);
2694         ir_prog_pass_t *res  = def_prog_pass_constructor(
2695                 &pass->pass, name ? name : "dump_all_graphs", dump_all_ir_graphs_wrapper);
2696
2697         /* this pass does not change anything, so neither dump nor verify is needed. */
2698         res->dump_irprog   = ir_prog_no_dump;
2699         res->verify_irprog = ir_prog_no_verify;
2700
2701         memcpy(pass->suffix, suffix, len);
2702
2703         return res;
2704 }