3 * File name: ir/ir/irdump.c
4 * Purpose: Write vcg representation of firm to file.
5 * Author: Martin Trapp, Christian Schaefer
6 * Modified by: Goetz Lindenmaier, Hubert Schmidt
9 * Copyright: (c) 1998-2003 Universität Karlsruhe
10 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
24 #include "firm_common_t.h"
27 #include "irgraph_t.h"
37 #include "type_or_entity.h"
41 #include "callgraph.h"
52 extern void dump_irn_chi_term(FILE *FL, ir_node *n);
53 extern void dump_irn_state(FILE *FL, ir_node *n);
54 extern int get_opt_dump_abstvals(void);
55 typedef unsigned long SeqNo;
56 extern SeqNo get_Block_seqno(ir_node *n);
59 /* basis for a color range for vcg */
60 static int n_colors = 0;
61 static int base_color = 0;
63 /** Dump only irgs with names that start with this string */
64 static ident *dump_file_filter_id = NULL;
66 #define ERROR_TXT "<ERROR>"
69 * returns the name of a mode or <ERROR> if mode is NOT a mode object.
70 * in the later case, sets bad
72 const char *get_mode_name_ex(ir_mode *mode, int *bad)
75 return get_mode_name(mode);
81 * returns the name of a type or <ERROR> if mode is NOT a mode object.
82 * in the later case, sets bad
84 const char *get_type_name_ex(type *tp, int *bad)
87 return get_type_name(tp);
93 * prints the edge from a type S to a type T with additional info fmt, ...
96 static void print_type_type_edge(FILE *F, type *S, type *T, const char *fmt, ...)
101 fprintf(F, "edge: { sourcename: "); PRINT_TYPEID(S);
102 fprintf(F, " targetname: "); PRINT_TYPEID(T);
103 vfprintf(F, fmt, ap);
109 * prints the edge from a type T to an entity E with additional info fmt, ...
112 static void print_type_ent_edge(FILE *F, type *T, entity *E, const char *fmt, ...)
117 fprintf(F, "edge: { sourcename: "); PRINT_TYPEID(T);
118 fprintf(F, " targetname: \""); PRINT_ENTID(E); fprintf(F, "\"");
119 vfprintf(F, fmt, ap);
125 * prints the edge from an entity E to an entity T with additional info fmt, ...
128 static void print_ent_ent_edge(FILE *F, entity *E, entity *T, int backedge, const char *fmt, ...)
134 fprintf(F, "backedge: { sourcename: \"");
136 fprintf(F, "edge: { sourcename: \"");
138 fprintf(F, "\" targetname: \""); PRINT_ENTID(T); fprintf(F, "\"");
139 vfprintf(F, fmt, ap);
145 * prints the edge from an entity E to a type T with additional info fmt, ...
148 static void print_ent_type_edge(FILE *F, entity *E, type *T, const char *fmt, ...)
153 fprintf(F, "edge: { sourcename: \""); PRINT_ENTID(E);
154 fprintf(F, "\" targetname: "); PRINT_TYPEID(T);
155 vfprintf(F, fmt, ap);
161 * prints the edge from a node N to a type T with additional info fmt, ...
164 static void print_node_type_edge(FILE *F, const ir_node *N, type *T, const char *fmt, ...)
169 fprintf(F, "edge: { sourcename: \""); PRINT_NODEID(N);
170 fprintf(F, "\" targetname: "); PRINT_TYPEID(T);
171 vfprintf(F, fmt, ap);
177 * prints the edge from a node N to an entity E with additional info fmt, ...
180 static void print_node_ent_edge(FILE *F, const ir_node *N, entity *E, const char *fmt, ...)
185 fprintf(F, "edge: { sourcename: \""); PRINT_NODEID(N);
186 fprintf(F, "\" targetname: \""); PRINT_ENTID(E);
188 vfprintf(F, fmt, ap);
194 * prints the edge from an entity E to a node N with additional info fmt, ...
197 static void print_ent_node_edge(FILE *F, entity *E, const ir_node *N, const char *fmt, ...)
202 fprintf(F, "edge: { sourcename: \""); PRINT_ENTID(E);
203 fprintf(F, "\" targetname: \""); PRINT_NODEID(N); fprintf(F, "\"");
204 vfprintf(F, fmt, ap);
210 * prints the edge from a type E to an enumeration item item with additional info fmt, ...
213 static void print_enum_item_edge(FILE *F, type *E, int item, const char *fmt, ...)
218 fprintf(F, "edge: { sourcename: "); PRINT_TYPEID(E);
219 fprintf(F, " targetname: \""); PRINT_ITEMID(E, item); fprintf(F, "\" ");
220 vfprintf(F, fmt, ap);
225 /*-----------------------------------------------------------------*/
226 /* global and ahead declarations */
227 /*-----------------------------------------------------------------*/
229 static void dump_whole_node(ir_node *n, void *env);
230 static INLINE void dump_loop_nodes_into_graph(FILE *F, ir_graph *irg);
232 /*-----------------------------------------------------------------*/
233 /* Helper functions. */
234 /*-----------------------------------------------------------------*/
237 * This map is used as a private link attr to be able to call dumper
238 * anywhere without destroying link fields.
240 static pmap *irdump_link_map = NULL;
242 /** Creates the link attribut map. */
243 static void init_irdump(void) {
244 /* We need a new, empty map. */
245 if (irdump_link_map) pmap_destroy(irdump_link_map);
246 irdump_link_map = pmap_create();
247 dump_file_filter_id = new_id_from_str("");
250 * Returns the private link field.
252 static void *ird_get_irn_link(ir_node *n) {
254 if (!irdump_link_map) return NULL;
256 if (pmap_contains(irdump_link_map, (void *)n))
257 res = pmap_get(irdump_link_map, (void *)n);
262 * Sets the private link field.
264 static void ird_set_irn_link(ir_node *n, void *x) {
265 if (!irdump_link_map) init_irdump();
266 pmap_insert(irdump_link_map, (void *)n, x);
270 * Gets the private link field of an irg.
272 static void *ird_get_irg_link(ir_graph *irg) {
274 if (!irdump_link_map) return NULL;
276 if (pmap_contains(irdump_link_map, (void *)irg))
277 res = pmap_get(irdump_link_map, (void *)irg);
282 * Sets the private link field of an irg.
284 static void ird_set_irg_link(ir_graph *irg, void *x) {
285 if (!irdump_link_map) init_irdump();
286 pmap_insert(irdump_link_map, (void *)irg, x);
290 * Walker, clears tzhe private link field
292 static void clear_link(ir_node * node, void * env) {
293 ird_set_irn_link(node, NULL);
297 * If the entity has a ld_name, returns it, else returns the name of the entity.
299 const char *get_ent_dump_name(entity *ent) {
301 return "<NULL entity>";
302 /* Don't use get_entity_ld_ident (ent) as it computes the mangled name! */
303 if (ent->ld_name) return get_id_str(ent->ld_name);
304 return get_id_str(ent->name);
307 /* Returns the name of an IRG. */
308 const char *get_irg_dump_name(ir_graph *irg) {
309 /* Don't use get_entity_ld_ident (ent) as it computes the mangled name! */
310 entity *ent = get_irg_entity(irg);
311 return get_ent_dump_name(ent);
315 * Returns non-zero if a node is in floating state.
317 static int node_floats(ir_node *n) {
318 return ((get_irn_pinned(n) == op_pin_state_floats) &&
319 (get_irg_pinned(current_ir_graph) == op_pin_state_floats));
323 * Walker, allocates an array for all blocks and puts it's nodes non-floating nodes into this array.
325 static void collect_node(ir_node * node, void *env) {
328 || get_irn_op(node) == op_Bad
329 || get_irn_op(node) == op_Unknown
330 || get_irn_op(node) == op_NoMem) {
331 ir_node ** arr = (ir_node **) ird_get_irg_link(get_irn_irg(node));
332 if (!arr) arr = NEW_ARR_F(ir_node *, 0);
333 ARR_APP1(ir_node *, arr, node);
334 ird_set_irg_link(get_irn_irg(node), arr); /* arr is an l-value, APP_ARR might change it! */
336 ir_node * block = get_nodes_block(node);
339 /* this node is in a Bad block, so we must place it into the graph's list */
340 ir_node ** arr = (ir_node **) ird_get_irg_link(get_irn_irg(node));
341 if (!arr) arr = NEW_ARR_F(ir_node *, 0);
342 ARR_APP1(ir_node *, arr, node);
343 ird_set_irg_link(get_irn_irg(node), arr); /* arr is an l-value, APP_ARR might change it! */
346 ird_set_irn_link(node, ird_get_irn_link(block));
347 ird_set_irn_link(block, node);
352 /** Construct lists to walk ir block-wise.
354 * Collects all blocks, nodes not op_pin_state_pinned,
355 * Bad, NoMem and Unknown into a flexible array in link field of
356 * irg they belong to. Sets the irg link field to NULL in all
357 * graphs not visited.
358 * Free the list with DEL_ARR_F().
360 static ir_node ** construct_block_lists(ir_graph *irg) {
361 int i, rem_view = get_interprocedural_view();
362 ir_graph *rem = current_ir_graph;
363 current_ir_graph = irg;
365 for (i = 0; i < get_irp_n_irgs(); i++)
366 ird_set_irg_link(get_irp_irg(i), NULL);
368 irg_walk_graph(current_ir_graph, clear_link, collect_node, current_ir_graph);
370 /* Collect also EndReg and EndExcept. We do not want to change the walker. */
371 set_interprocedural_view(false);
373 set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph)-1);
374 irg_walk(get_irg_end_reg(current_ir_graph), clear_link, collect_node, current_ir_graph);
375 set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph)-1);
376 irg_walk(get_irg_end_except(current_ir_graph), clear_link, collect_node, current_ir_graph);
378 set_interprocedural_view(rem_view);
380 current_ir_graph = rem;
381 return ird_get_irg_link(irg);
384 /*******************************************************************/
385 /* flags to steer output */
386 /*******************************************************************/
388 /** A compiler option to turn off edge labels */
389 static int edge_label = 1;
390 /** A compiler option to turn off dumping values of constant entities */
391 static int const_entities = 1;
392 /** A compiler option to dump the keep alive edges */
393 static int dump_keepalive = 0;
394 /** Compiler options to dump analysis information in dump_ir_graph */
395 int dump_out_edge_flag = 0;
396 int dump_dominator_information_flag = 0;
397 int dump_loop_information_flag = 0;
398 int dump_backedge_information_flag = 1;
399 int dump_const_local = 0;
400 bool opt_dump_analysed_type_info = 1;
401 bool opt_dump_pointer_values_to_info = 0; /* default off: for test compares!! */
403 static const char *overrule_nodecolor = NULL;
405 /** The vcg attribute hook. */
406 static DUMP_NODE_VCGATTR_FUNC dump_node_vcgattr_hook = NULL;
409 void set_dump_node_vcgattr_hook(DUMP_NODE_VCGATTR_FUNC hook)
411 dump_node_vcgattr_hook = hook;
414 INLINE bool get_opt_dump_const_local(void) {
415 if (!dump_out_edge_flag && !dump_loop_information_flag)
416 return dump_const_local;
421 void only_dump_method_with_name(ident *name) {
422 dump_file_filter_id = name;
425 ident *get_dump_file_filter_ident(void) {
426 return dump_file_filter_id;
429 /** Returns true if dump file filter is not set, or if it is a
431 int is_filtered_dump_name(ident *name) {
432 return id_is_prefix(dump_file_filter_id, name);
435 /* To turn off display of edge labels. Edge labels offen cause xvcg to
436 abort with a segmentation fault. */
437 void turn_off_edge_labels(void) {
441 void dump_consts_local(bool b) {
442 dump_const_local = b;
445 void dump_constant_entity_values(bool b) {
449 void dump_keepalive_edges(bool b) {
453 bool get_opt_dump_keepalive_edges(void) {
454 return dump_keepalive;
457 void dump_out_edges(bool b) {
458 dump_out_edge_flag = b;
461 void dump_dominator_information(bool b) {
462 dump_dominator_information_flag = b;
465 void dump_loop_information(bool b) {
466 dump_loop_information_flag = b;
469 void dump_backedge_information(bool b) {
470 dump_backedge_information_flag = b;
473 /* Dump the information of type field specified in ana/irtypeinfo.h.
474 * If the flag is set, the type name is output in [] in the node label,
475 * else it is output as info.
477 void set_opt_dump_analysed_type_info(bool b) {
478 opt_dump_analysed_type_info = b;
481 void dump_pointer_values_to_info(bool b) {
482 opt_dump_pointer_values_to_info = b;
485 /*-----------------------------------------------------------------*/
486 /* Routines to dump information about a single ir node. */
487 /*-----------------------------------------------------------------*/
490 * dump the name of a node n to the File F.
493 dump_node_opcode(FILE *F, ir_node *n)
497 switch(get_irn_opcode(n)) {
502 res = tarval_snprintf(buf, sizeof(buf), get_Const_tarval(n));
503 assert(res < sizeof(buf) && "buffer to small for tarval_snprintf");
508 if (get_SymConst_kind(n) == symconst_addr_name) {
509 /* don't use get_SymConst_ptr_info as it mangles the name. */
510 fprintf (F, "SymC %s", get_id_str(get_SymConst_name(n)));
511 } else if (get_SymConst_kind(n) == symconst_addr_ent) {
512 assert(get_SymConst_entity(n));
513 assert(is_entity(get_SymConst_entity(n)));
514 fprintf (F, "SymC &%s", get_entity_name(get_SymConst_entity(n)));
516 assert(get_kind(get_SymConst_type(n)) == k_type);
517 assert(get_type_ident(get_SymConst_type(n)));
518 fprintf (F, "SymC %s ", get_type_name_ex(get_SymConst_type(n), &bad));
519 if (get_SymConst_kind(n) == symconst_type_tag)
527 if (!get_interprocedural_view())
534 ir_node *pred = get_Proj_pred(n);
536 if (get_irn_opcode(pred) == iro_Cond
537 && get_Proj_proj(n) == get_Cond_defaultProj(pred)
538 && get_irn_mode(get_Cond_selector(pred)) != mode_b)
539 fprintf (F, "defProj");
541 * else if (get_irn_opcode(pred) == iro_Proj && get_irn_opcode(get_Proj_pred(pred)) == iro_Start)
542 * fprintf (F, "Arg");
551 if (get_interprocedural_view()) {
552 fprintf(F, "%s %s", get_irn_opname(n), get_ent_dump_name(get_irg_entity(get_irn_irg(n))));
557 case iro_CallBegin: {
558 ir_node *addr = get_CallBegin_ptr(n);
560 if (get_irn_op(addr) == op_Sel)
561 ent = get_Sel_entity(addr);
562 else if ((get_irn_op(addr) == op_SymConst) && (get_SymConst_kind(addr) == symconst_addr_ent))
563 ent = get_SymConst_entity(addr);
564 fprintf (F, "%s", get_irn_opname(n));
565 if (ent) fprintf (F, " %s", get_entity_name(ent));
569 fprintf (F, "%s[%s]", get_irn_opname(n), get_mode_name_ex(get_Load_mode(n), &bad));
574 fprintf (F, "%s", get_irn_opname(n));
582 * Dump the mode of a node n to a file F.
583 * Ignore modes that are "always known".
586 dump_node_mode(FILE *F, ir_node *n)
589 opcode iro = get_irn_opcode(n);
602 ir_mode *mode = get_irn_mode(n);
604 if (mode && mode != mode_BB && mode != mode_ANY && mode != mode_BAD &&
605 (mode != mode_T || iro == iro_Proj))
606 fprintf(F, "%s", get_mode_name_ex(mode, &bad));
614 * Dump the tpe of a node n to a file F if it's known.
616 static int dump_node_typeinfo(FILE *F, ir_node *n) {
619 if (opt_dump_analysed_type_info) {
620 if (get_irg_typeinfo_state(current_ir_graph) == ir_typeinfo_consistent ||
621 get_irg_typeinfo_state(current_ir_graph) == ir_typeinfo_inconsistent) {
622 type *tp = get_irn_typeinfo_type(n);
623 if (tp != firm_none_type)
624 fprintf(F, "[%s] ", get_type_name_ex(tp, &bad));
633 * Dump addinional node attributes of some nodes to a file F.
636 dump_node_nodeattr(FILE *F, ir_node *n)
640 switch (get_irn_opcode(n)) {
642 if (false && get_interprocedural_view()) {
643 fprintf (F, "%s ", get_ent_dump_name(get_irg_entity(current_ir_graph)));
647 if (get_irn_opcode(get_Proj_pred(n)) == iro_Cmp) {
648 fprintf (F, "%s ", get_pnc_string(get_Proj_proj(n)));
650 fprintf (F, "%ld ", get_Proj_proj(n));
654 fprintf (F, "%ld ", get_Filter_proj(n));
657 fprintf (F, "%s ", get_ent_dump_name(get_Sel_entity(n)));
660 fprintf (F, "(%s) ", get_type_name_ex(get_Cast_type(n), &bad));
663 fprintf (F, "%s ", get_pnc_string(get_Confirm_cmp(n)));
674 /** Dumps a node label without the enclosing ". */
675 static int dump_node_label(FILE *F, ir_node *n) {
678 bad |= dump_node_opcode(F, n);
679 bad |= dump_node_mode(F, n);
681 bad |= dump_node_typeinfo(F, n);
682 bad |= dump_node_nodeattr(F, n);
683 fprintf(F, "%ld", get_irn_node_nr(n));
690 * Dumps the attributes of a node n into the file F.
691 * Currently this is only the color of a node.
693 static void dump_node_vcgattr(FILE *F, ir_node *node, ir_node *local, int bad)
698 fprintf(F, "color: red");
702 if (dump_node_vcgattr_hook)
703 if (dump_node_vcgattr_hook(F, node, local))
706 n = local ? local : node;
708 switch (get_irn_opcode(n)) {
715 fprintf (F, "color: blue");
718 if (is_Block_dead(n))
719 fprintf (F, "color: lightred");
721 fprintf (F, "color: lightyellow");
724 fprintf (F, "color: green");
730 fprintf (F, "color: yellow");
733 PRINT_DEFAULT_NODE_ATTR;
736 if (overrule_nodecolor) fprintf(F, " color: %s", overrule_nodecolor);
741 * Dump the node information of a node n to a file F.
743 static INLINE int dump_node_info(FILE *F, ir_node *n)
745 fprintf (F, " info1: \"");
746 bad = dump_irnode_to_file(F, n);
752 * checks wheater a node is "constant-like", ie can be treated "block-less"
755 bool is_constlike_node(ir_node *n) {
756 ir_op *op = get_irn_op(n);
757 return (op == op_Const || op == op_Bad || op == op_NoMem || op == op_SymConst || op == op_Unknown);
761 /** outputs the predecessors of n, that are constants, local. I.e.,
762 generates a copy of the constant predecessors for each node called with. */
763 static void dump_const_node_local(FILE *F, ir_node *n) {
765 if (!get_opt_dump_const_local()) return;
767 /* Use visited flag to avoid outputting nodes twice.
768 initialize it first. */
769 for (i = 0; i < get_irn_arity(n); i++) {
770 ir_node *con = get_irn_n(n, i);
771 if (is_constlike_node(con)) {
772 set_irn_visited(con, get_irg_visited(current_ir_graph) - 1);
776 for (i = 0; i < get_irn_arity(n); i++) {
777 ir_node *con = get_irn_n(n, i);
778 if (is_constlike_node(con) && irn_not_visited(con)) {
781 mark_irn_visited(con);
782 /* Generate a new name for the node by appending the names of
784 fprintf(F, "node: {title: "); PRINT_CONSTID(n, con);
785 fprintf(F, " label: \"");
786 bad |= dump_node_label(F, con);
788 bad |= dump_node_info(F, con);
789 dump_node_vcgattr(F, n, con, bad);
795 /** If the block of an edge is a const_like node, dump it local with an edge */
796 static void dump_const_block_local(FILE *F, ir_node *n) {
799 if (!get_opt_dump_const_local()) return;
801 blk = get_nodes_block(n);
802 if (is_constlike_node(blk)) {
805 /* Generate a new name for the node by appending the names of
807 fprintf(F, "node: {title: \""); PRINT_CONSTBLKID(n, blk);
808 fprintf(F, "\" label: \"");
809 bad |= dump_node_label(F, blk);
811 bad |= dump_node_info(F, blk);
812 dump_node_vcgattr(F, n, blk, bad);
815 fprintf (F, "edge: { sourcename: \"");
817 fprintf (F, "\" targetname: \""); PRINT_CONSTBLKID(n,blk);
818 fprintf (F, "\" " BLOCK_EDGE_ATTR "}\n");
823 * prints the error message of a node to a file F as info2.
825 static void INLINE print_node_error(FILE *F, const char *err_msg)
830 fprintf (F, " info2: \"%s\"", err_msg);
836 static void dump_node(FILE *F, ir_node *n)
841 if (get_opt_dump_const_local() && is_constlike_node(n))
845 fprintf(F, "node: {title: \""); PRINT_NODEID(n); fprintf(F, "\" label: \"");
847 bad = ! irn_vrfy_irg_dump(n, current_ir_graph, &p);
848 bad |= dump_node_label(F, n);
849 //dump_node_ana_info(F, n);
851 bad |= dump_node_info(F, n);
852 print_node_error(F, p);
853 dump_node_vcgattr(F, n, NULL, bad);
855 dump_const_node_local(F, n);
857 dump_irn_chi_term(F, n);
858 dump_irn_state(F, n);
862 /** dump the edge to the block this node belongs to */
864 dump_ir_block_edge(FILE *F, ir_node *n) {
865 if (get_opt_dump_const_local() && is_constlike_node(n)) return;
866 if (is_no_Block(n)) {
867 ir_node *block = get_nodes_block(n);
869 if (get_opt_dump_const_local() && is_constlike_node(block)) {
870 dump_const_block_local(F, n);
873 fprintf (F, "edge: { sourcename: \"");
875 fprintf (F, "\" targetname: ");
876 fprintf(F, "\""); PRINT_NODEID(block); fprintf(F, "\"");
877 fprintf (F, " " BLOCK_EDGE_ATTR "}\n");
883 print_data_edge_vcgattr(FILE *F, ir_node *from, int to) {
884 if (get_nodes_block(from) == get_nodes_block(get_irn_n(from, to)))
885 fprintf (F, INTRA_DATA_EDGE_ATTR);
887 fprintf (F, INTER_DATA_EDGE_ATTR);
891 print_mem_edge_vcgattr(FILE *F, ir_node *from, int to) {
892 if (get_nodes_block(from) == get_nodes_block(get_irn_n(from, to)))
893 fprintf (F, INTRA_MEM_EDGE_ATTR);
895 fprintf (F, INTER_MEM_EDGE_ATTR);
899 print_edge_vcgattr(FILE *F, ir_node *from, int to) {
902 if (dump_backedge_information_flag && is_backedge(from, to))
903 fprintf (F, BACK_EDGE_ATTR);
905 switch (get_irn_opcode(from)) {
907 fprintf (F, CF_EDGE_ATTR);
909 case iro_Start: break;
912 if (get_irn_mode(get_End_keepalive(from, to)) == mode_BB)
913 fprintf (F, CF_EDGE_ATTR);
914 if (get_irn_mode(get_End_keepalive(from, to)) == mode_X)
915 fprintf (F, INTER_MEM_EDGE_ATTR);
923 print_data_edge_vcgattr(F, from, to);
928 print_mem_edge_vcgattr(F, from, to);
930 print_data_edge_vcgattr(F, from, to);
934 print_data_edge_vcgattr(F, from, to);
939 print_mem_edge_vcgattr(F, from, to);
941 print_data_edge_vcgattr(F, from, to);
948 print_data_edge_vcgattr(F, from, to);
955 print_mem_edge_vcgattr(F, from, to);
957 print_data_edge_vcgattr(F, from, to);
969 print_data_edge_vcgattr(F, from, to);
972 if (get_irn_modecode(from) == irm_M)
973 fprintf (F, INTER_MEM_EDGE_ATTR);
975 print_data_edge_vcgattr(F, from, to);
982 print_mem_edge_vcgattr(F, from, to);
984 print_data_edge_vcgattr(F, from, to);
987 print_mem_edge_vcgattr(F, from, to);
989 case iro_Tuple: break;
992 switch (get_irn_modecode(from)) {
994 fprintf (F, CF_EDGE_ATTR);
997 fprintf (F, INTER_MEM_EDGE_ATTR);
1000 print_data_edge_vcgattr(F, from, to);
1004 case iro_Bad: break;
1005 case iro_Unknown: break;
1007 switch (get_irn_modecode(from)) {
1009 fprintf (F, INTRA_MEM_EDGE_ATTR);
1012 fprintf (F, CF_EDGE_ATTR);
1015 print_data_edge_vcgattr(F, from, to);
1023 /* dump edges to our inputs */
1025 dump_ir_data_edges(FILE *F, ir_node *n) {
1027 unsigned long visited = get_irn_visited(n);
1029 if ((get_irn_op(n) == op_End) && (!dump_keepalive))
1032 for (i = 0; i < get_irn_arity(n); i++) {
1033 ir_node * pred = get_irn_n(n, i);
1036 if ((get_interprocedural_view() && get_irn_visited(pred) < visited))
1037 continue; /* pred not dumped */
1039 if (dump_backedge_information_flag && is_backedge(n, i))
1040 fprintf (F, "backedge: {sourcename: \"");
1042 fprintf (F, "edge: {sourcename: \"");
1044 fprintf (F, "\" targetname: ");
1045 if ((get_opt_dump_const_local()) && is_constlike_node(pred)) {
1046 PRINT_CONSTID(n, pred);
1048 fprintf(F, "\""); PRINT_NODEID(pred); fprintf(F, "\"");
1050 fprintf (F, " label: \"%d\" ", i);
1051 print_edge_vcgattr(F, n, i);
1056 /** Dumps a node and its edges but not the block edge
1059 dump_node_wo_blockedge (ir_node *n, void *env) {
1062 dump_ir_data_edges(F, n);
1065 /** Dumps a node and its edges.
1068 dump_whole_node (ir_node *n, void *env) {
1070 dump_node_wo_blockedge(n, env);
1071 if (!node_floats(n)) dump_ir_block_edge(F, n);
1075 dump_const_node(ir_node *n, void *env) {
1076 if (is_Block(n)) return;
1077 dump_node_wo_blockedge(n, env);
1080 /***********************************************************************/
1081 /* the following routines dump the nodes/irgs bracketed to graphs. */
1082 /***********************************************************************/
1084 /** Dumps a constant expression as entity initializer, array bound ...
1086 static void dump_const_expression(FILE *F, ir_node *value) {
1087 ir_graph *rem = current_ir_graph;
1088 int rem_dump_const_local = dump_const_local;
1089 dump_const_local = 0;
1090 current_ir_graph = get_const_code_irg();
1091 irg_walk(value, dump_const_node, NULL, F);
1092 /* Decrease visited flag so that we walk with the same flag for the next
1093 expresssion. This guarantees that we don't dump the same node twice,
1094 as for const expressions cse is performed to save memory. */
1095 set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph) -1);
1096 current_ir_graph = rem;
1097 dump_const_local = rem_dump_const_local;
1100 /** Dump a block as graph containing its nodes.
1102 * Expects to find nodes belonging to the block as list in its
1104 * Dumps the edges of all nodes including itself. */
1106 dump_whole_block(FILE *F, ir_node *block) {
1108 assert(is_Block(block));
1110 fprintf(F, "graph: { title: \"");
1111 PRINT_NODEID(block);
1112 fprintf(F, "\" label: \"");
1113 dump_node_label(F, block);
1115 if (get_opt_dump_abstvals())
1116 fprintf (F, " seqno: %d", (int)get_Block_seqno(block));
1118 fprintf(F, "\" status:clustered color:%s \n",
1119 get_Block_matured(block) ? "yellow" : "red");
1121 /* dump the blocks edges */
1122 dump_ir_data_edges(F, block);
1124 /* dump the nodes that go into the block */
1125 for (node = ird_get_irn_link(block); node; node = ird_get_irn_link(node)) {
1127 dump_ir_data_edges(F, node);
1130 /* Close the vcg information for the block */
1132 dump_const_node_local(F, block);
1134 dump_irn_chi_term(F, block);
1139 /** dumps a graph block-wise. Expects all blockless nodes in arr in irgs link.
1140 * The outermost nodes: blocks and nodes not op_pin_state_pinned, Bad, Unknown. */
1142 dump_block_graph(FILE *F, ir_graph *irg) {
1144 ir_graph *rem = current_ir_graph;
1145 ir_node **arr = ird_get_irg_link(irg);
1146 current_ir_graph = irg;
1148 for (i = ARR_LEN(arr) - 1; i >= 0; --i) {
1149 ir_node * node = arr[i];
1150 if (is_Block(node)) {
1151 /* Dumps the block and all the nodes in the block, which are to
1152 be found in Block->link. */
1153 dump_whole_block(F, node);
1155 /* Nodes that are not in a Block. */
1157 if (is_Bad(get_nodes_block(node)) && !node_floats(node)) {
1158 dump_const_block_local(F, node);
1160 dump_ir_data_edges(F, node);
1164 if (dump_loop_information_flag && (get_irg_loopinfo_state(irg) & loopinfo_valid))
1165 dump_loop_nodes_into_graph(F, irg);
1167 current_ir_graph = rem;
1170 /** Dumps an irg as a graph.
1171 * If interprocedural view edges can point to nodes out of this graph.
1173 static void dump_graph_from_list(FILE *F, ir_graph *irg) {
1175 fprintf(F, "graph: { title: \"");
1177 fprintf(F, "\" label: \"%s\" status:clustered color:white \n",
1178 get_ent_dump_name(get_irg_entity(irg)));
1180 dump_block_graph(F, irg);
1182 /* Close the vcg information for the irg */
1183 fprintf(F, "}\n\n");
1186 /*******************************************************************/
1187 /* Basic type and entity nodes and edges. */
1188 /*******************************************************************/
1190 /** dumps the edges between nodes and their type or entity attributes. */
1191 static void dump_node2type_edges(ir_node *n, void *env)
1196 switch (get_irn_opcode(n)) {
1198 /* @@@ some consts have an entity */
1201 if ( (get_SymConst_kind(n) ==symconst_type_tag)
1202 || (get_SymConst_kind(n) ==symconst_size))
1204 print_node_type_edge(F,n,get_SymConst_type(n),NODE2TYPE_EDGE_ATTR);
1208 print_node_ent_edge(F,n,get_Sel_entity(n),NODE2TYPE_EDGE_ATTR);
1211 print_node_type_edge(F,n,get_Call_type(n),NODE2TYPE_EDGE_ATTR);
1214 print_node_type_edge(F,n,get_Alloc_type(n),NODE2TYPE_EDGE_ATTR);
1217 print_node_type_edge(F,n,get_Free_type(n),NODE2TYPE_EDGE_ATTR);
1220 print_node_type_edge(F,n,get_Cast_type(n),NODE2TYPE_EDGE_ATTR);
1228 static int print_type_info(FILE *F, type *tp) {
1231 if (get_type_state(tp) == layout_undefined) {
1232 fprintf(F, "state: layout_undefined\n");
1234 fprintf(F, "state: layout_fixed,\n");
1236 if (get_type_mode(tp))
1237 fprintf(F, "mode: %s,\n", get_mode_name_ex(get_type_mode(tp), &bad));
1238 fprintf(F, "size: %db,\n", get_type_size_bits(tp));
1243 static void print_typespecific_info(FILE *F, type *tp) {
1244 switch (get_type_tpop_code(tp)) {
1247 fprintf(F, "peculiarity: %s\n", get_peculiarity_string(get_class_peculiarity(tp)));
1254 fprintf(F, "variadicity: %s\n", get_variadicity_name(get_method_variadicity(tp)));
1255 fprintf(F, "params: %d\n", get_method_n_params(tp));
1256 fprintf(F, "results: %d\n", get_method_n_ress(tp));
1264 case tpo_enumeration:
1278 static void print_typespecific_vcgattr(FILE *F, type *tp) {
1279 switch (get_type_tpop_code(tp)) {
1282 if (peculiarity_existent == get_class_peculiarity(tp))
1283 fprintf (F, " " TYPE_CLASS_NODE_ATTR);
1285 fprintf (F, " " TYPE_DESCRIPTION_NODE_ATTR);
1289 fprintf (F, " " TYPE_METH_NODE_ATTR);
1300 case tpo_enumeration:
1313 static int print_type_node(FILE *F, type *tp)
1317 fprintf (F, "node: {title: ");
1319 fprintf (F, " label: \"%s %s\"", get_type_tpop_name(tp), get_type_name_ex(tp, &bad));
1320 fprintf (F, " info1: \"");
1321 bad |= print_type_info(F, tp);
1322 print_typespecific_info(F, tp);
1324 print_typespecific_vcgattr(F, tp);
1330 #define X(a) case a: fprintf(F, #a); break
1331 void dump_entity_node(FILE *F, entity *ent, int color)
1333 fprintf (F, "node: {title: \"");
1334 PRINT_ENTID(ent); fprintf(F, "\"");
1335 fprintf (F, DEFAULT_TYPE_ATTRIBUTE);
1336 fprintf (F, "label: ");
1337 fprintf (F, "\"ent %s\" ", get_ent_dump_name(ent));
1339 fprintf(F, "color: %d", color);
1341 fprintf (F, ENTITY_NODE_ATTR);
1342 fprintf (F, "\n info1: \"");
1344 dump_entity_to_file(F, ent, dump_verbosity_entattrs | dump_verbosity_entconsts);
1346 fprintf(F, "\"\n}\n");
1350 static void dump_enum_item(FILE *F, type *tp, int pos)
1353 ident *id = get_enumeration_nameid(tp, pos);
1354 tarval *tv = get_enumeration_enum(tp, pos);
1356 tarval_snprintf(buf, sizeof(buf), tv);
1357 fprintf (F, "node: {title: \"");
1358 PRINT_ITEMID(tp, pos); fprintf(F, "\"");
1359 fprintf (F, DEFAULT_ENUM_ITEM_ATTRIBUTE);
1360 fprintf (F, "label: ");
1361 fprintf (F, "\"enum item %s\" " ENUM_ITEM_NODE_ATTR, get_id_str(id));
1362 fprintf (F, "\n info1: \"value: %s\"}\n", buf);
1365 /* dumps a type or entity and it's edges. */
1367 dump_type_info(type_or_ent *tore, void *env) {
1369 int i = 0; /* to shutup gcc */
1371 /* dump this type or entity */
1373 switch (get_kind(tore)) {
1376 entity *ent = (entity *)tore;
1379 dump_entity_node(F, ent, 0);
1381 /* skip this to reduce graph. Member edge of type is parallel to this edge. *
1382 fprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
1383 ENT_OWN_EDGE_ATTR "}\n", ent, get_entity_owner(ent));*/
1384 print_ent_type_edge(F,ent, get_entity_type(ent), ENT_TYPE_EDGE_ATTR);
1385 if (is_Class_type(get_entity_owner(ent))) {
1386 for(i = 0; i < get_entity_n_overwrites(ent); i++)
1387 print_ent_ent_edge(F,ent, get_entity_overwrites(ent, i), 0, ENT_OVERWRITES_EDGE_ATTR);
1389 /* attached subgraphs */
1390 if (const_entities && (get_entity_variability(ent) != variability_uninitialized)) {
1391 if (is_atomic_entity(ent)) {
1392 value = get_atomic_ent_value(ent);
1394 print_ent_node_edge(F, ent, value, ENT_VALUE_EDGE_ATTR, i);
1395 /* DDMN(value); $$$ */
1396 dump_const_expression(F, value);
1399 if (is_compound_entity(ent)) {
1400 for (i = 0; i < get_compound_ent_n_values(ent); i++) {
1401 value = get_compound_ent_value(ent, i);
1403 print_ent_node_edge(F, ent, value, ENT_VALUE_EDGE_ATTR, i);
1404 dump_const_expression(F, value);
1405 print_ent_ent_edge(F, ent, get_compound_ent_value_member(ent, i), 0, ENT_CORR_EDGE_ATTR, i);
1407 fprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
1408 ENT_CORR_EDGE_ATTR "}\n", GET_ENTID(ent),
1409 get_compound_ent_value_member(ent, i), i);
1418 type *tp = (type *)tore;
1419 print_type_node(F, tp);
1420 /* and now the edges */
1421 switch (get_type_tpop_code(tp)) {
1424 for (i=0; i < get_class_n_supertypes(tp); i++)
1425 print_type_type_edge(F, tp,get_class_supertype(tp, i),TYPE_SUPER_EDGE_ATTR);
1426 for (i=0; i < get_class_n_members(tp); i++)
1427 print_type_ent_edge(F,tp,get_class_member(tp, i),TYPE_MEMBER_EDGE_ATTR);
1431 for (i=0; i < get_struct_n_members(tp); i++)
1432 print_type_ent_edge(F,tp,get_struct_member(tp, i),TYPE_MEMBER_EDGE_ATTR);
1436 for (i = 0; i < get_method_n_params(tp); i++)
1437 print_type_type_edge(F,tp,get_method_param_type(tp, i),METH_PAR_EDGE_ATTR,i);
1438 for (i = 0; i < get_method_n_ress(tp); i++)
1439 print_type_type_edge(F,tp,get_method_res_type(tp, i),METH_RES_EDGE_ATTR,i);
1443 for (i = 0; i < get_union_n_members(tp); i++)
1444 print_type_ent_edge(F,tp,get_union_member(tp, i),UNION_EDGE_ATTR);
1448 print_type_type_edge(F,tp,get_array_element_type(tp),ARR_ELT_TYPE_EDGE_ATTR);
1449 print_type_ent_edge(F,tp,get_array_element_entity(tp),ARR_ENT_EDGE_ATTR);
1450 for (i = 0; i < get_array_n_dimensions(tp); i++) {
1451 ir_node *upper = get_array_upper_bound(tp, i);
1452 ir_node *lower = get_array_lower_bound(tp, i);
1453 print_node_type_edge(F, upper, tp, "label: \"upper %d\"", get_array_order(tp, i));
1454 print_node_type_edge(F, lower, tp, "label: \"lower %d\"", get_array_order(tp, i));
1455 dump_const_expression(F, upper);
1456 dump_const_expression(F, lower);
1460 case tpo_enumeration:
1462 for (i = 0; i < get_enumeration_n_enums(tp); ++i) {
1463 dump_enum_item(F, tp, i);
1464 print_enum_item_edge(F, tp, i, "label: \"item %d\"", i);
1469 print_type_type_edge(F,tp,get_pointer_points_to_type(tp), PTR_PTS_TO_EDGE_ATTR);
1477 break; /* case k_type */
1480 printf(" *** irdump, dump_type_info(l.%i), faulty type.\n", __LINE__);
1482 } /* switch kind_or_entity */
1485 typedef struct _h_env {
1490 /** For dumping class hierarchies.
1491 * Dumps a class type node and a superclass edge.
1492 * If env->dump_ent dumps entities of classes and overwrites edges.
1495 dump_class_hierarchy_node (type_or_ent *tore, void *ctx) {
1498 int i = 0; /* to shutup gcc */
1500 /* dump this type or entity */
1501 switch (get_kind(tore)) {
1503 entity *ent = (entity *)tore;
1504 if (get_entity_owner(ent) == get_glob_type()) break;
1505 if (!is_Method_type(get_entity_type(ent))) break; /* GL */
1506 if (env->dump_ent && is_Class_type(get_entity_owner(ent))) {
1508 dump_entity_node(F, ent, 0);
1510 print_type_ent_edge(F,get_entity_owner(ent),ent,TYPE_MEMBER_EDGE_ATTR);
1511 for(i = 0; i < get_entity_n_overwrites(ent); i++)
1512 print_ent_ent_edge(F, get_entity_overwrites(ent, i), ent, 0, ENT_OVERWRITES_EDGE_ATTR);
1514 } break; /* case k_entity */
1517 type *tp = (type *)tore;
1518 if (tp == get_glob_type()) break;
1519 switch (get_type_tpop_code(tp)) {
1521 print_type_node(F, tp);
1522 /* and now the edges */
1523 for (i=0; i < get_class_n_supertypes(tp); i++)
1525 print_type_type_edge(F,tp,get_class_supertype(tp, i),TYPE_SUPER_EDGE_ATTR);
1531 break; /* case k_type */
1534 printf(" *** irdump, dump_class_hierarchy_node(l.%i), faulty type.\n", __LINE__);
1536 } /* switch kind_or_entity */
1539 /*******************************************************************/
1540 /* dump analysis information that is expressed in graph terms. */
1541 /*******************************************************************/
1543 /* dump out edges */
1545 dump_out_edge(ir_node *n, void *env) {
1548 for (i = 0; i < get_irn_n_outs(n); i++) {
1549 assert(get_irn_out(n, i));
1550 fprintf (F, "edge: {sourcename: \"");
1552 fprintf (F, "\" targetname: \"");
1553 PRINT_NODEID(get_irn_out(n, i));
1554 fprintf (F, "\" color: red linestyle: dashed");
1560 dump_loop_label(FILE *F, ir_loop *loop) {
1561 fprintf (F, "loop %d, %d sons, %d nodes",
1562 get_loop_depth(loop), get_loop_n_sons(loop), get_loop_n_nodes(loop));
1565 static INLINE void dump_loop_info(FILE *F, ir_loop *loop) {
1566 fprintf (F, " info1: \"");
1567 fprintf (F, " loop nr: %d", get_loop_loop_nr(loop));
1568 #if DEBUG_libfirm /* GL @@@ debug analyses */
1569 fprintf (F, "\n The loop was analyzed %d times.", (int)get_loop_link(loop));
1575 dump_loop_node(FILE *F, ir_loop *loop) {
1576 fprintf (F, "node: {title: \"");
1578 fprintf (F, "\" label: \"");
1579 dump_loop_label(F, loop);
1581 dump_loop_info(F, loop);
1587 dump_loop_node_edge(FILE *F, ir_loop *loop, int i) {
1589 fprintf (F, "edge: {sourcename: \"");
1591 fprintf (F, "\" targetname: \"");
1592 PRINT_NODEID(get_loop_node(loop, i));
1593 fprintf (F, "\" color: green");
1598 dump_loop_son_edge(FILE *F, ir_loop *loop, int i) {
1600 fprintf (F, "edge: {sourcename: \"");
1602 fprintf (F, "\" targetname: \"");
1603 PRINT_LOOPID(get_loop_son(loop, i));
1604 fprintf (F, "\" color: darkgreen label: \"%d\"}\n",
1605 get_loop_element_pos(loop, get_loop_son(loop, i)));
1609 void dump_loops(FILE *F, ir_loop *loop) {
1611 /* dump this loop node */
1612 dump_loop_node(F, loop);
1614 /* dump edges to nodes in loop -- only if it is a real loop */
1615 if (get_loop_depth(loop) != 0) {
1616 for (i = 0; i < get_loop_n_nodes(loop); i++) {
1617 dump_loop_node_edge(F, loop, i);
1620 for (i = 0; i < get_loop_n_sons(loop); i++) {
1621 dump_loops(F, get_loop_son(loop, i));
1622 dump_loop_son_edge(F, loop, i);
1627 void dump_loop_nodes_into_graph(FILE *F, ir_graph *irg) {
1628 ir_graph *rem = current_ir_graph;
1629 current_ir_graph = irg;
1631 if (get_irg_loop(irg)) dump_loops(F, get_irg_loop(irg));
1633 current_ir_graph = rem;
1638 * dumps the VCG header
1640 INLINE void dump_vcg_header(FILE *F, const char *name, const char *orientation) {
1649 if (!orientation) orientation = "bottom_to_top";
1653 "graph: { title: \"ir graph of %s\"\n"
1654 "display_edge_labels: %s\n"
1655 "layoutalgorithm: mindepth\n"
1656 "manhattan_edges: yes\n"
1657 "port_sharing: no\n"
1659 "classname 1: \"intrablock Data\"\n"
1660 "classname 16: \"interblock Data\"\n"
1661 "classname 2: \"Block\"\n"
1662 "classname 13: \"Control Flow\"\n"
1663 "classname 18: \"Exception Control Flow for Interval Analysis\"\n"
1664 "classname 14: \"intrablock Memory\"\n"
1665 "classname 17: \"interblock Memory\"\n"
1666 "classname 15: \"Dominators\"\n"
1667 "classname 3: \"Entity type\"\n"
1668 "classname 4: \"Entity owner\"\n"
1669 "classname 5: \"Method Param\"\n"
1670 "classname 6: \"Method Res\"\n"
1671 "classname 7: \"Super\"\n"
1672 "classname 8: \"Union\"\n"
1673 "classname 9: \"Points-to\"\n"
1674 "classname 10: \"Array Element Type\"\n"
1675 "classname 11: \"Overwrites\"\n"
1676 "classname 12: \"Member\"\n"
1677 "infoname 1: \"Attribute\"\n"
1678 "infoname 2: \"Verification errors\"\n",
1679 name, label, orientation);
1681 /* don't use all, the range is too whith/black. */
1685 "colorentry 100: 0 0 0\n"
1686 "colorentry 101: 20 0 0\n"
1687 "colorentry 102: 40 0 0\n"
1688 "colorentry 103: 60 0 0\n"
1689 "colorentry 104: 80 0 0\n"
1690 "colorentry 105: 100 0 0\n"
1691 "colorentry 106: 120 0 0\n"
1692 "colorentry 107: 140 0 0\n"
1693 "colorentry 108: 150 0 0\n"
1694 "colorentry 109: 180 0 0\n"
1695 "colorentry 110: 200 0 0\n"
1696 "colorentry 111: 220 0 0\n"
1697 "colorentry 112: 240 0 0\n"
1698 "colorentry 113: 255 0 0\n"
1699 "colorentry 113: 255 20 20\n"
1700 "colorentry 114: 255 40 40\n"
1701 "colorentry 115: 255 60 60\n"
1702 "colorentry 116: 255 80 80\n"
1703 "colorentry 117: 255 100 100\n"
1704 "colorentry 118: 255 120 120\n"
1705 "colorentry 119: 255 140 140\n"
1706 "colorentry 120: 255 150 150\n"
1707 "colorentry 121: 255 180 180\n"
1708 "colorentry 122: 255 200 200\n"
1709 "colorentry 123: 255 220 220\n"
1710 "colorentry 124: 255 240 240\n"
1711 "colorentry 125: 255 250 250\n"
1714 fprintf (F, "\n"); /* a separator */
1720 * @param irg The graph to be dumped
1721 * @param suffix1 first filename suffix
1722 * @param suffix2 second filename suffix
1724 FILE *vcg_open (ir_graph *irg, const char * suffix1, const char *suffix2) {
1726 const char *nm = get_irg_dump_name(irg);
1727 int len = strlen(nm), i, j;
1728 char *fname; /* filename to put the vcg information in */
1730 if (!suffix1) suffix1 = "";
1731 if (!suffix2) suffix2 = "";
1733 /* open file for vcg graph */
1734 fname = malloc (len * 2 + strlen(suffix1) + strlen(suffix2) + 5);
1736 /* strncpy (fname, nm, len); */ /* copy the filename */
1738 for (i = 0; i < len; ++i) { /* replace '/' in the name: escape by @. */
1740 fname[j] = '@'; j++; fname[j] = '1'; j++;
1741 } else if (nm[i] == '@') {
1742 fname[j] = '@'; j++; fname[j] = '2'; j++;
1744 fname[j] = nm[i]; j++;
1748 strcat (fname, suffix1); /* append file suffix */
1749 strcat (fname, suffix2); /* append file suffix */
1750 strcat (fname, ".vcg"); /* append the .vcg suffix */
1752 /* vcg really expect only a <CR> at end of line, so
1753 * the "b"inary mode is what you mean (and even needed for Win32)
1755 F = fopen (fname, "wb"); /* open file for writing */
1757 panic("cannot open %s for writing (%m)", fname); /* not reached */
1767 * @param irg The graph to be dumped
1768 * @param suffix filename suffix
1770 FILE *vcg_open_name (const char *name, const char *suffix) {
1772 char *fname; /* filename to put the vcg information in */
1773 int i, j, len = strlen(name);
1775 if (!suffix) suffix = "";
1777 /** open file for vcg graph */
1778 fname = malloc (len * 2 + 5 + strlen(suffix));
1779 /* strcpy (fname, name);*/ /* copy the filename */
1781 for (i = 0; i < len; ++i) { /* replace '/' in the name: escape by @. */
1782 if (name[i] == '/') {
1783 fname[j] = '@'; j++; fname[j] = '1'; j++;
1784 } else if (name[i] == '@') {
1785 fname[j] = '@'; j++; fname[j] = '2'; j++;
1787 fname[j] = name[i]; j++;
1791 strcat (fname, suffix);
1792 strcat (fname, ".vcg"); /* append the .vcg suffix */
1794 /* vcg really expect only a <CR> at end of line, so
1795 * the "b"inary mode is what you mean (and even needed for Win32)
1797 F = fopen (fname, "wb"); /* open file for writing */
1799 panic ("cannot open %s for writing (%m)", fname); /* not reached */
1807 * Dumps the vcg file footer
1809 static INLINE void dump_vcg_footer (FILE *F) {
1814 * close the vcg file
1816 void vcg_close (FILE *F) {
1817 dump_vcg_footer(F); /* print footer */
1818 fclose (F); /* close vcg file */
1821 /************************************************************************/
1822 /************************************************************************/
1823 /* Routines that dump all or parts of the firm representation to a file */
1824 /************************************************************************/
1825 /************************************************************************/
1827 /************************************************************************/
1828 /* Dump ir graphs, different formats and additional information. */
1829 /************************************************************************/
1831 /** Routine to dump a graph, blocks as conventional nodes. */
1833 dump_ir_graph (ir_graph *irg, const char *suffix )
1838 rem = current_ir_graph;
1840 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg)))) return;
1842 current_ir_graph = irg;
1843 if (get_interprocedural_view()) suffix1 = "-pure-ip";
1844 else suffix1 = "-pure";
1845 f = vcg_open(irg, suffix, suffix1);
1846 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1848 /* walk over the graph */
1849 /* dump_whole_node must be called in post visiting predecessors */
1850 irg_walk(get_irg_end(irg), NULL, dump_whole_node, f);
1852 /* dump the out edges in a separate walk */
1853 if ((dump_out_edge_flag) && (get_irg_outs_state(irg) != outs_none)) {
1854 irg_out_walk(get_irg_start(irg), dump_out_edge, NULL, f);
1859 current_ir_graph = rem;
1864 dump_ir_block_graph (ir_graph *irg, const char *suffix)
1870 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg))))
1873 if (get_interprocedural_view()) suffix1 = "-ip";
1875 f = vcg_open(irg, suffix, suffix1);
1876 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1878 construct_block_lists(irg);
1880 for (i = 0; i < get_irp_n_irgs(); i++) {
1881 ir_node **arr = ird_get_irg_link(get_irp_irg(i));
1883 dump_graph_from_list(f, get_irp_irg(i));
1891 /** dumps a graph with type information */
1893 dump_ir_graph_w_types (ir_graph *irg, const char *suffix)
1896 ir_graph *rem = current_ir_graph;
1899 /* if a filter is set, dump only the irg's that match the filter */
1900 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg))))
1903 current_ir_graph = irg;
1905 if (get_interprocedural_view()) suffix1 = "-pure-wtypes-ip";
1906 else suffix1 = "-pure-wtypes";
1907 f = vcg_open(irg,suffix, suffix1);
1908 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1910 /* dump common ir graph */
1911 irg_walk(get_irg_end(irg), NULL, dump_whole_node, f);
1912 /* dump type info */
1913 type_walk_irg(irg, dump_type_info, NULL, f);
1914 inc_irg_visited(get_const_code_irg());
1915 /* dump edges from graph to type info */
1916 irg_walk(get_irg_end(irg), dump_node2type_edges, NULL, f);
1919 current_ir_graph = rem;
1923 dump_ir_block_graph_w_types (ir_graph *irg, const char *suffix)
1928 ir_graph *rem = current_ir_graph;
1930 /* if a filter is set, dump only the irg's that match the filter */
1931 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg))))
1934 if (get_interprocedural_view()) suffix1 = "-wtypes-ip";
1935 else suffix1 = "-wtypes";
1936 f = vcg_open(irg, suffix, suffix1);
1937 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1939 /* dump common blocked ir graph */
1940 construct_block_lists(irg);
1942 for (i = 0; i < get_irp_n_irgs(); i++) {
1943 ir_node **arr = ird_get_irg_link(get_irp_irg(i));
1945 dump_graph_from_list(f, get_irp_irg(i));
1950 /* dump type info */
1951 current_ir_graph = irg;
1952 type_walk_irg(irg, dump_type_info, NULL, f);
1953 inc_irg_visited(get_const_code_irg());
1955 /* dump edges from graph to type info */
1956 irg_walk(get_irg_end(irg), dump_node2type_edges, NULL, f);
1958 current_ir_graph = rem;
1962 /*---------------------------------------------------------------------*/
1963 /* The following routines dump a control flow graph. */
1964 /*---------------------------------------------------------------------*/
1967 dump_block_to_cfg(ir_node *block, void *env) {
1972 if (is_Block(block)) {
1973 /* This is a block. Dump a node for the block. */
1974 fprintf (F, "node: {title: \""); PRINT_NODEID(block);
1975 fprintf (F, "\" label: \"");
1976 if (block == get_irg_start_block(get_irn_irg(block)))
1977 fprintf(F, "Start ");
1978 if (block == get_irg_end_block(get_irn_irg(block)))
1981 fprintf (F, "%s ", get_op_name(get_irn_op(block)));
1982 PRINT_NODEID(block);
1984 fprintf(F, "info1:\"");
1985 if (dump_dominator_information_flag) {
1986 fprintf(F, "dom depth %d\n", get_Block_dom_depth(block));
1987 fprintf(F, "tree pre num %d\n", get_Block_dom_tree_pre_num(block));
1988 fprintf(F, "max subtree pre num %d\n", get_Block_dom_max_subtree_pre_num(block));
1991 /* show arity and possible Bad predecessors of the block */
1992 fprintf(F, "arity: %d\n", get_Block_n_cfgpreds(block));
1993 for (fl = i = 0; i < get_Block_n_cfgpreds(block); ++i) {
1994 ir_node *pred = get_Block_cfgpred(block, i);
1997 fprintf(F, "Bad pred at pos: ");
1998 fprintf(F, "%d ", i);
2005 fprintf (F, "\""); /* closing quote of info */
2007 if ((block == get_irg_start_block(get_irn_irg(block))) ||
2008 (block == get_irg_end_block(get_irn_irg(block))) )
2009 fprintf(F, " color:blue ");
2011 fprintf(F, " color:yellow ");
2014 /* Dump the edges */
2015 for ( i = 0; i < get_Block_n_cfgpreds(block); i++)
2016 if (get_irn_op(skip_Proj(get_Block_cfgpred(block, i))) != op_Bad) {
2017 pred = get_nodes_block(skip_Proj(get_Block_cfgpred(block, i)));
2018 fprintf (F, "edge: { sourcename: \"");
2019 PRINT_NODEID(block);
2020 fprintf (F, "\" targetname: \"");
2022 fprintf (F, "\"}\n");
2025 /* Dump dominator edge */
2026 if (dump_dominator_information_flag && get_Block_idom(block)) {
2027 pred = get_Block_idom(block);
2028 fprintf (F, "edge: { sourcename: \"");
2029 PRINT_NODEID(block);
2030 fprintf (F, "\" targetname: \"");
2032 fprintf (F, "\" " DOMINATOR_EDGE_ATTR "}\n");
2038 dump_cfg (ir_graph *irg, const char *suffix)
2041 ir_graph *rem = current_ir_graph;
2042 int ddif = dump_dominator_information_flag;
2043 int ipv = get_interprocedural_view();
2045 /* if a filter is set, dump only the irg's that match the filter */
2046 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg))))
2049 current_ir_graph = irg;
2051 f = vcg_open(irg, suffix, "-cfg");
2052 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
2055 printf("Warning: dumping cfg not in interprocedural view!\n");
2056 set_interprocedural_view(false);
2059 if (get_irg_dom_state(irg) != dom_consistent)
2060 dump_dominator_information_flag = 0;
2062 /* walk over the blocks in the graph */
2063 irg_block_walk(get_irg_end(irg), dump_block_to_cfg, NULL, f);
2064 dump_node(f, get_irg_bad(irg));
2066 dump_dominator_information_flag = ddif;
2067 set_interprocedural_view(ipv);
2069 current_ir_graph = rem;
2073 static void descend_and_dump(FILE *F, ir_node *n, int depth, pset *mark_set) {
2074 if (pset_find_ptr(mark_set, n)) return;
2076 pset_insert_ptr(mark_set, n);
2079 int i, start = is_Block(n) ? 0 : -1;
2080 dump_whole_node(n, F);
2081 for (i = start; i < get_irn_arity(n); ++i)
2082 descend_and_dump(F, get_irn_n(n, i), depth-1, mark_set);
2085 /* Don't dump edges to nodes further out. These might be edges to
2086 nodes we already dumped, if there is a shorter path to these. */
2090 static int subgraph_counter = 0;
2091 void dump_subgraph (ir_node *root, int depth, const char *suffix) {
2094 pset *mark_set = pset_new_ptr(1);
2095 sprintf(buf, "-subg_%03d", subgraph_counter++);
2096 F = vcg_open(get_irn_irg(root), suffix, buf);
2097 dump_vcg_header(F, get_irg_dump_name(get_irn_irg(root)), NULL);
2098 descend_and_dump(F, root, depth, mark_set);
2104 static int weight_overall(int rec, int loop) {
2105 return 2*rec + loop;
2108 static int compute_color (int my, int max) {
2115 /* if small, scale to the full color range. */
2117 my = my * (n_colors/max);
2119 step = 1 + (max / n_colors);
2123 return base_color + n_colors - color;
2126 static int get_entity_color(entity *ent) {
2127 ir_graph *irg = get_entity_irg(ent);
2131 int rec_depth = get_irg_recursion_depth(irg);
2132 int loop_depth = get_irg_loop_depth(irg);
2133 int overall_depth = weight_overall(rec_depth, loop_depth);
2135 int max_rec_depth = irp->max_callgraph_recursion_depth;
2136 int max_loop_depth = irp->max_callgraph_loop_depth;
2137 int max_overall_depth = weight_overall(max_rec_depth, max_loop_depth);
2139 /* int my_rec_color = compute_color(rec_depth, max_rec_depth); */
2140 /* int my_loop_color = compute_color(loop_depth, max_loop_depth); */
2141 int my_overall_color = compute_color(overall_depth, max_overall_depth);;
2143 return my_overall_color;
2147 void dump_callgraph(const char *suffix) {
2149 int i, n_irgs = get_irp_n_irgs();
2150 int rem = edge_label;
2152 //ident *prefix = new_id_from_str("java/");
2154 F = vcg_open_name("Callgraph", suffix);
2155 dump_vcg_header(F, "Callgraph", NULL);
2157 for (i = 0; i < n_irgs; ++i) {
2158 ir_graph *irg = get_irp_irg(i);
2159 entity *ent = get_irg_entity(irg);
2160 int j, n_callees = get_irg_n_callees(irg);
2162 /* Do not dump runtime system. */
2163 //if (id_is_prefix(prefix, get_entity_ld_ident(ent))) continue;
2165 dump_entity_node(F, ent, get_entity_color(ent));
2166 for (j = 0; j < n_callees; ++j) {
2167 entity *c = get_irg_entity(get_irg_callee(irg, j));
2168 //if (id_is_prefix(prefix, get_entity_ld_ident(c))) continue;
2169 int be = is_irg_callee_backedge(irg, j);
2172 "label:\"recursion %d\" color: %d" :
2173 "label:\"calls %d\" color: %d";
2174 print_ent_ent_edge(F, ent, c, be, attr, get_irg_callee_loop_depth(irg, j), get_entity_color(ent));
2182 /* Dump all irgs in interprocedural view to a single file. */
2183 void dump_all_cg_block_graph(const char *suffix) {
2186 int rem_view = get_interprocedural_view();
2187 set_interprocedural_view(true);
2189 f = vcg_open_name("All_graphs", suffix);
2190 dump_vcg_header(f, "All_graphs", NULL);
2192 /* collect nodes in all irgs reachable in call graph*/
2193 for (i = 0; i < get_irp_n_irgs(); i++)
2194 ird_set_irg_link(get_irp_irg(i), NULL);
2196 cg_walk(clear_link, collect_node, NULL);
2198 /* dump all graphs */
2199 for (i = 0; i < get_irp_n_irgs(); i++) {
2200 current_ir_graph = get_irp_irg(i);
2201 assert(ird_get_irg_link(current_ir_graph));
2202 dump_graph_from_list(f, current_ir_graph);
2203 DEL_ARR_F(ird_get_irg_link(current_ir_graph));
2207 set_interprocedural_view(rem_view);
2210 /*---------------------------------------------------------------------*/
2211 /* the following routines dumps type information without any ir nodes. */
2212 /*---------------------------------------------------------------------*/
2215 dump_type_graph (ir_graph *irg, const char *suffix)
2219 rem = current_ir_graph;
2221 /* if a filter is set, dump only the irg's that match the filter */
2222 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg)))) return;
2224 current_ir_graph = irg;
2226 f = vcg_open(irg, suffix, "-type");
2227 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
2229 /* walk over the blocks in the graph */
2230 type_walk_irg(irg, dump_type_info, NULL, f);
2231 /* The walker for the const code can be called several times for the
2232 same (sub) expression. So that no nodes are dumped several times
2233 we decrease the visited flag of the corresponding graph after each
2234 walk. So now increase it finally. */
2235 inc_irg_visited(get_const_code_irg());
2238 current_ir_graph = rem;
2242 dump_all_types (const char *suffix)
2244 FILE *f = vcg_open_name("All_types", suffix);
2245 dump_vcg_header(f, "All_types", NULL);
2246 type_walk(dump_type_info, NULL, f);
2247 inc_irg_visited(get_const_code_irg());
2252 dump_class_hierarchy (bool entities, const char *suffix)
2254 FILE *f = vcg_open_name("class_hierarchy", suffix);
2258 dump_vcg_header(f, "class_hierarchy", NULL);
2263 type_walk(dump_class_hierarchy_node, NULL, &env);
2267 /*---------------------------------------------------------------------*/
2268 /* dumps all graphs with the graph-dumper passed. Possible dumpers: */
2270 /* dump_ir_block_graph */
2272 /* dump_type_graph */
2273 /* dump_ir_graph_w_types */
2274 /*---------------------------------------------------------------------*/
2276 void dump_all_ir_graphs(dump_graph_func *dmp_grph, const char *suffix) {
2277 int i, n_irgs = get_irp_n_irgs();
2278 for (i = 0; i < n_irgs; ++i) {
2279 dmp_grph(get_irp_irg(i), suffix);
2284 /*--------------------------------------------------------------------------------*
2285 * Dumps a stand alone loop graph with firm nodes which belong to one loop node *
2286 * packed together in one subgraph/box *
2287 *--------------------------------------------------------------------------------*/
2289 void dump_loops_standalone(FILE *F, ir_loop *loop) {
2290 int i = 0, loop_node_started = 0, son_number = 0, first = 0;
2292 ir_loop *son = NULL;
2294 /* Dump a new loop node. */
2295 dump_loop_node(F, loop);
2297 /* Dump the loop elements. */
2299 for(i = 0; i < get_loop_n_elements(loop); i++) {
2300 le = get_loop_element(loop, i);
2302 if (get_kind(son) == k_ir_loop) {
2304 /* We are a loop son -> Recurse */
2306 if(loop_node_started) { /* Close the "firm-nodes" node first if we started one. */
2307 fprintf(F, "\" }\n");
2308 fprintf (F, "edge: {sourcename: \"");
2310 fprintf (F, "\" targetname: \"");
2312 fprintf (F, "-%d-nodes\" label:\"%d...%d\"}\n", first, first, i-1);
2313 loop_node_started = 0;
2315 dump_loop_son_edge(F, loop, son_number++);
2316 dump_loops_standalone(F, son);
2317 } else if (get_kind(son) == k_ir_node) {
2318 /* We are a loop node -> Collect firm nodes */
2320 ir_node *n = le.node;
2323 if (!loop_node_started) {
2324 /* Start a new node which contains all firm nodes of the current loop */
2325 fprintf (F, "node: { title: \"");
2327 fprintf (F, "-%d-nodes\" color: lightyellow label: \"", i);
2328 loop_node_started = 1;
2334 bad |= dump_node_label(F, n);
2335 /* Causes indeterministic output: if (is_Block(n)) fprintf (F, "\t ->%d", (int)get_irn_link(n)); */
2336 if (has_backedges(n)) fprintf(F, "\t loop head!");
2337 } else { /* for callgraph loop tree */
2339 assert(get_kind(son) == k_ir_graph);
2341 /* We are a loop node -> Collect firm graphs */
2342 n = (ir_graph *)le.node;
2343 if (!loop_node_started) {
2344 /* Start a new node which contains all firm nodes of the current loop */
2345 fprintf (F, "node: { title: \"");
2347 fprintf (F, "-%d-nodes\" color: lightyellow label: \"", i);
2348 loop_node_started = 1;
2353 fprintf (F, " %s", get_irg_dump_name(n));
2354 /* fprintf (F, " %s (depth %d)", get_irg_dump_name(n), n->callgraph_weighted_loop_depth); */
2358 if (loop_node_started) {
2359 fprintf(F, "\" }\n");
2360 fprintf (F, "edge: {sourcename: \"");
2362 fprintf (F, "\" targetname: \"");
2364 fprintf (F, "-%d-nodes\" label:\"%d...%d\"}\n", first, first, i-1);
2365 loop_node_started = 0;
2369 void dump_loop_tree(ir_graph *irg, const char *suffix)
2372 ir_graph *rem = current_ir_graph;
2373 int el_rem = edge_label;
2376 /* if a filter is set, dump only the irg's that match the filter */
2377 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg)))) return;
2379 current_ir_graph = irg;
2381 f = vcg_open(irg, suffix, "-looptree");
2382 dump_vcg_header(f, get_irg_dump_name(irg), "top_to_bottom");
2384 if (get_irg_loop(irg)) dump_loops_standalone(f, get_irg_loop(irg));
2388 edge_label = el_rem;
2389 current_ir_graph = rem;
2392 void dump_callgraph_loop_tree(const char *suffix) {
2394 F = vcg_open_name("Callgraph_looptree", suffix);
2395 dump_vcg_header(F, "callgraph looptree", "top_to_bottom");
2396 dump_loops_standalone(F, irp->outermost_cg_loop);
2401 /*-----------------------------------------------------------------------------*/
2402 /* Dumps the firm nodes in the loop tree to a graph along with the loop nodes. */
2403 /*-----------------------------------------------------------------------------*/
2405 void collect_nodeloop(FILE *F, ir_loop *loop, eset *loopnodes) {
2406 int i, son_number = 0, node_number = 0;
2408 if (dump_loop_information_flag) dump_loop_node(F, loop);
2410 for (i = 0; i < get_loop_n_elements(loop); i++) {
2411 loop_element le = get_loop_element(loop, i);
2412 if (*(le.kind) == k_ir_loop) {
2413 if (dump_loop_information_flag) dump_loop_son_edge(F, loop, son_number++);
2415 collect_nodeloop(F, le.son, loopnodes);
2417 if (dump_loop_information_flag) dump_loop_node_edge(F, loop, node_number++);
2418 eset_insert(loopnodes, le.node);
2423 void collect_nodeloop_external_nodes(ir_loop *loop, eset *loopnodes, eset *extnodes) {
2426 for(i = 0; i < get_loop_n_elements(loop); i++) {
2427 loop_element le = get_loop_element(loop, i);
2428 if (*(le.kind) == k_ir_loop) {
2430 collect_nodeloop_external_nodes(le.son, loopnodes, extnodes);
2432 if (is_Block(le.node)) start = 0; else start = -1;
2433 for (j = start; j < get_irn_arity(le.node); j++) {
2434 ir_node *pred = get_irn_n(le.node, j);
2435 if (!eset_contains(loopnodes, pred)) {
2436 eset_insert(extnodes, pred);
2437 if (!is_Block(pred)) {
2438 pred = get_nodes_block(pred);
2439 if (!eset_contains(loopnodes, pred)) eset_insert(extnodes, pred);
2447 void dump_loop(ir_loop *l, const char *suffix) {
2450 eset *loopnodes = eset_create();
2451 eset *extnodes = eset_create();
2454 snprintf(name, sizeof(name), "loop_%d", get_loop_loop_nr(l));
2455 F = vcg_open_name (name, suffix);
2456 dump_vcg_header(F, name, NULL);
2458 /* collect all nodes to dump */
2459 collect_nodeloop(F, l, loopnodes);
2460 collect_nodeloop_external_nodes(l, loopnodes, extnodes);
2462 /* build block lists */
2463 for (n = eset_first(loopnodes); n != NULL; n = eset_next(loopnodes))
2464 set_irn_link(n, NULL);
2465 for (n = eset_first(extnodes); n != NULL; n = eset_next(extnodes))
2466 set_irn_link(n, NULL);
2467 for (n = eset_first(loopnodes); n != NULL; n = eset_next(loopnodes))
2469 b = get_nodes_block(n);
2470 set_irn_link(n, get_irn_link(b));
2473 for (n = eset_first(extnodes); n != NULL; n = eset_next(extnodes))
2475 b = get_nodes_block(n);
2476 set_irn_link(n, get_irn_link(b));
2480 for (b = eset_first(loopnodes); b != NULL; b = eset_next(loopnodes))
2482 fprintf(F, "graph: { title: \"");
2484 fprintf(F, "\" label: \"");
2485 dump_node_opcode(F, b);
2486 fprintf (F, " %ld", get_irn_node_nr(b));
2487 fprintf(F, "\" status:clustered color:yellow\n");
2489 /* dump the blocks edges */
2490 dump_ir_data_edges(F, b);
2492 /* dump the nodes that go into the block */
2493 for (n = get_irn_link(b); n; n = get_irn_link(n)) {
2494 if (eset_contains(extnodes, n)) overrule_nodecolor = "lightblue";
2496 overrule_nodecolor = NULL;
2497 if (!eset_contains(extnodes, n)) dump_ir_data_edges(F, n);
2500 /* Close the vcg information for the block */
2502 dump_const_node_local(F, b);
2505 for (b = eset_first(extnodes); b != NULL; b = eset_next(extnodes))
2507 fprintf(F, "graph: { title: \"");
2509 fprintf(F, "\" label: \"");
2510 dump_node_opcode(F, b);
2511 fprintf (F, " %ld", get_irn_node_nr(b));
2512 fprintf(F, "\" status:clustered color:lightblue\n");
2514 /* dump the nodes that go into the block */
2515 for (n = get_irn_link(b); n; n = get_irn_link(n)) {
2516 if (!eset_contains(loopnodes, n)) overrule_nodecolor = "lightblue";
2518 overrule_nodecolor = NULL;
2519 if (eset_contains(loopnodes, n)) dump_ir_data_edges(F, n);
2522 /* Close the vcg information for the block */
2524 dump_const_node_local(F, b);
2528 eset_destroy(loopnodes);
2529 eset_destroy(extnodes);