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