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