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 if (!dump_file_filter_id) return 1;
433 return id_is_prefix(dump_file_filter_id, name);
436 /* To turn off display of edge labels. Edge labels offen cause xvcg to
437 abort with a segmentation fault. */
438 void turn_off_edge_labels(void) {
442 void dump_consts_local(bool b) {
443 dump_const_local = b;
446 void dump_constant_entity_values(bool b) {
450 void dump_keepalive_edges(bool b) {
454 bool get_opt_dump_keepalive_edges(void) {
455 return dump_keepalive;
458 void dump_out_edges(bool b) {
459 dump_out_edge_flag = b;
462 void dump_dominator_information(bool b) {
463 dump_dominator_information_flag = b;
466 void dump_loop_information(bool b) {
467 dump_loop_information_flag = b;
470 void dump_backedge_information(bool b) {
471 dump_backedge_information_flag = b;
474 /* Dump the information of type field specified in ana/irtypeinfo.h.
475 * If the flag is set, the type name is output in [] in the node label,
476 * else it is output as info.
478 void set_opt_dump_analysed_type_info(bool b) {
479 opt_dump_analysed_type_info = b;
482 void dump_pointer_values_to_info(bool b) {
483 opt_dump_pointer_values_to_info = b;
486 /*-----------------------------------------------------------------*/
487 /* Routines to dump information about a single ir node. */
488 /*-----------------------------------------------------------------*/
491 * dump the name of a node n to the File F.
494 dump_node_opcode(FILE *F, ir_node *n)
498 switch(get_irn_opcode(n)) {
503 res = tarval_snprintf(buf, sizeof(buf), get_Const_tarval(n));
504 assert(res < sizeof(buf) && "buffer to small for tarval_snprintf");
509 if (get_SymConst_kind(n) == symconst_addr_name) {
510 /* don't use get_SymConst_ptr_info as it mangles the name. */
511 fprintf (F, "SymC %s", get_id_str(get_SymConst_name(n)));
512 } else if (get_SymConst_kind(n) == symconst_addr_ent) {
513 assert(get_SymConst_entity(n));
514 assert(is_entity(get_SymConst_entity(n)));
515 fprintf (F, "SymC &%s", get_entity_name(get_SymConst_entity(n)));
517 assert(get_kind(get_SymConst_type(n)) == k_type);
518 assert(get_type_ident(get_SymConst_type(n)));
519 fprintf (F, "SymC %s ", get_type_name_ex(get_SymConst_type(n), &bad));
520 if (get_SymConst_kind(n) == symconst_type_tag)
528 if (!get_interprocedural_view())
535 ir_node *pred = get_Proj_pred(n);
537 if (get_irn_opcode(pred) == iro_Cond
538 && get_Proj_proj(n) == get_Cond_defaultProj(pred)
539 && get_irn_mode(get_Cond_selector(pred)) != mode_b)
540 fprintf (F, "defProj");
542 * else if (get_irn_opcode(pred) == iro_Proj && get_irn_opcode(get_Proj_pred(pred)) == iro_Start)
543 * fprintf (F, "Arg");
552 if (get_interprocedural_view()) {
553 fprintf(F, "%s %s", get_irn_opname(n), get_ent_dump_name(get_irg_entity(get_irn_irg(n))));
558 case iro_CallBegin: {
559 ir_node *addr = get_CallBegin_ptr(n);
561 if (get_irn_op(addr) == op_Sel)
562 ent = get_Sel_entity(addr);
563 else if ((get_irn_op(addr) == op_SymConst) && (get_SymConst_kind(addr) == symconst_addr_ent))
564 ent = get_SymConst_entity(addr);
565 fprintf (F, "%s", get_irn_opname(n));
566 if (ent) fprintf (F, " %s", get_entity_name(ent));
570 fprintf (F, "%s[%s]", get_irn_opname(n), get_mode_name_ex(get_Load_mode(n), &bad));
575 fprintf (F, "%s", get_irn_opname(n));
583 * Dump the mode of a node n to a file F.
584 * Ignore modes that are "always known".
587 dump_node_mode(FILE *F, ir_node *n)
590 opcode iro = get_irn_opcode(n);
603 ir_mode *mode = get_irn_mode(n);
605 if (mode && mode != mode_BB && mode != mode_ANY && mode != mode_BAD &&
606 (mode != mode_T || iro == iro_Proj))
607 fprintf(F, "%s", get_mode_name_ex(mode, &bad));
615 * Dump the tpe of a node n to a file F if it's known.
617 static int dump_node_typeinfo(FILE *F, ir_node *n) {
620 if (opt_dump_analysed_type_info) {
621 if (get_irg_typeinfo_state(current_ir_graph) == ir_typeinfo_consistent ||
622 get_irg_typeinfo_state(current_ir_graph) == ir_typeinfo_inconsistent) {
623 type *tp = get_irn_typeinfo_type(n);
624 if (tp != firm_none_type)
625 fprintf(F, "[%s] ", get_type_name_ex(tp, &bad));
634 * Dump addinional node attributes of some nodes to a file F.
637 dump_node_nodeattr(FILE *F, ir_node *n)
641 switch (get_irn_opcode(n)) {
643 if (false && get_interprocedural_view()) {
644 fprintf (F, "%s ", get_ent_dump_name(get_irg_entity(current_ir_graph)));
648 if (get_irn_opcode(get_Proj_pred(n)) == iro_Cmp) {
649 fprintf (F, "%s ", get_pnc_string(get_Proj_proj(n)));
651 fprintf (F, "%ld ", get_Proj_proj(n));
655 fprintf (F, "%ld ", get_Filter_proj(n));
658 fprintf (F, "%s ", get_ent_dump_name(get_Sel_entity(n)));
661 fprintf (F, "(%s) ", get_type_name_ex(get_Cast_type(n), &bad));
664 fprintf (F, "%s ", get_pnc_string(get_Confirm_cmp(n)));
675 /** Dumps a node label without the enclosing ". */
676 static int dump_node_label(FILE *F, ir_node *n) {
679 bad |= dump_node_opcode(F, n);
680 bad |= dump_node_mode(F, n);
682 bad |= dump_node_typeinfo(F, n);
683 bad |= dump_node_nodeattr(F, n);
684 fprintf(F, "%ld", get_irn_node_nr(n));
691 * Dumps the attributes of a node n into the file F.
692 * Currently this is only the color of a node.
694 static void dump_node_vcgattr(FILE *F, ir_node *node, ir_node *local, int bad)
699 fprintf(F, "color: red");
703 if (dump_node_vcgattr_hook)
704 if (dump_node_vcgattr_hook(F, node, local))
707 n = local ? local : node;
709 switch (get_irn_opcode(n)) {
716 fprintf (F, "color: blue");
719 if (is_Block_dead(n))
720 fprintf (F, "color: lightred");
722 fprintf (F, "color: lightyellow");
725 fprintf (F, "color: green");
731 fprintf (F, "color: yellow");
734 PRINT_DEFAULT_NODE_ATTR;
737 if (overrule_nodecolor) fprintf(F, " color: %s", overrule_nodecolor);
742 * Dump the node information of a node n to a file F.
744 static INLINE int dump_node_info(FILE *F, ir_node *n)
746 fprintf (F, " info1: \"");
747 bad = dump_irnode_to_file(F, n);
753 * checks wheater a node is "constant-like", ie can be treated "block-less"
756 bool is_constlike_node(ir_node *n) {
757 ir_op *op = get_irn_op(n);
758 return (op == op_Const || op == op_Bad || op == op_NoMem || op == op_SymConst || op == op_Unknown);
762 /** outputs the predecessors of n, that are constants, local. I.e.,
763 generates a copy of the constant predecessors for each node called with. */
764 static void dump_const_node_local(FILE *F, ir_node *n) {
766 if (!get_opt_dump_const_local()) return;
768 /* Use visited flag to avoid outputting nodes twice.
769 initialize it first. */
770 for (i = 0; i < get_irn_arity(n); i++) {
771 ir_node *con = get_irn_n(n, i);
772 if (is_constlike_node(con)) {
773 set_irn_visited(con, get_irg_visited(current_ir_graph) - 1);
777 for (i = 0; i < get_irn_arity(n); i++) {
778 ir_node *con = get_irn_n(n, i);
779 if (is_constlike_node(con) && irn_not_visited(con)) {
782 mark_irn_visited(con);
783 /* Generate a new name for the node by appending the names of
785 fprintf(F, "node: {title: "); PRINT_CONSTID(n, con);
786 fprintf(F, " label: \"");
787 bad |= dump_node_label(F, con);
789 bad |= dump_node_info(F, con);
790 dump_node_vcgattr(F, n, con, bad);
796 /** If the block of an edge is a const_like node, dump it local with an edge */
797 static void dump_const_block_local(FILE *F, ir_node *n) {
800 if (!get_opt_dump_const_local()) return;
802 blk = get_nodes_block(n);
803 if (is_constlike_node(blk)) {
806 /* Generate a new name for the node by appending the names of
808 fprintf(F, "node: {title: \""); PRINT_CONSTBLKID(n, blk);
809 fprintf(F, "\" label: \"");
810 bad |= dump_node_label(F, blk);
812 bad |= dump_node_info(F, blk);
813 dump_node_vcgattr(F, n, blk, bad);
816 fprintf (F, "edge: { sourcename: \"");
818 fprintf (F, "\" targetname: \""); PRINT_CONSTBLKID(n,blk);
819 fprintf (F, "\" " BLOCK_EDGE_ATTR "}\n");
824 * prints the error message of a node to a file F as info2.
826 static void INLINE print_node_error(FILE *F, const char *err_msg)
831 fprintf (F, " info2: \"%s\"", err_msg);
837 static void dump_node(FILE *F, ir_node *n)
842 if (get_opt_dump_const_local() && is_constlike_node(n))
846 fprintf(F, "node: {title: \""); PRINT_NODEID(n); fprintf(F, "\" label: \"");
848 bad = ! irn_vrfy_irg_dump(n, current_ir_graph, &p);
849 bad |= dump_node_label(F, n);
850 //dump_node_ana_info(F, n);
852 bad |= dump_node_info(F, n);
853 print_node_error(F, p);
854 dump_node_vcgattr(F, n, NULL, bad);
856 dump_const_node_local(F, n);
858 dump_irn_chi_term(F, n);
859 dump_irn_state(F, n);
863 /** dump the edge to the block this node belongs to */
865 dump_ir_block_edge(FILE *F, ir_node *n) {
866 if (get_opt_dump_const_local() && is_constlike_node(n)) return;
867 if (is_no_Block(n)) {
868 ir_node *block = get_nodes_block(n);
870 if (get_opt_dump_const_local() && is_constlike_node(block)) {
871 dump_const_block_local(F, n);
874 fprintf (F, "edge: { sourcename: \"");
876 fprintf (F, "\" targetname: ");
877 fprintf(F, "\""); PRINT_NODEID(block); fprintf(F, "\"");
878 fprintf (F, " " BLOCK_EDGE_ATTR "}\n");
884 print_data_edge_vcgattr(FILE *F, ir_node *from, int to) {
885 if (get_nodes_block(from) == get_nodes_block(get_irn_n(from, to)))
886 fprintf (F, INTRA_DATA_EDGE_ATTR);
888 fprintf (F, INTER_DATA_EDGE_ATTR);
892 print_mem_edge_vcgattr(FILE *F, ir_node *from, int to) {
893 if (get_nodes_block(from) == get_nodes_block(get_irn_n(from, to)))
894 fprintf (F, INTRA_MEM_EDGE_ATTR);
896 fprintf (F, INTER_MEM_EDGE_ATTR);
900 print_edge_vcgattr(FILE *F, ir_node *from, int to) {
903 if (dump_backedge_information_flag && is_backedge(from, to))
904 fprintf (F, BACK_EDGE_ATTR);
906 switch (get_irn_opcode(from)) {
908 fprintf (F, CF_EDGE_ATTR);
910 case iro_Start: break;
913 if (get_irn_mode(get_End_keepalive(from, to)) == mode_BB)
914 fprintf (F, CF_EDGE_ATTR);
915 if (get_irn_mode(get_End_keepalive(from, to)) == mode_X)
916 fprintf (F, INTER_MEM_EDGE_ATTR);
924 print_data_edge_vcgattr(F, from, to);
929 print_mem_edge_vcgattr(F, from, to);
931 print_data_edge_vcgattr(F, from, to);
935 print_data_edge_vcgattr(F, from, to);
940 print_mem_edge_vcgattr(F, from, to);
942 print_data_edge_vcgattr(F, from, to);
949 print_data_edge_vcgattr(F, from, to);
956 print_mem_edge_vcgattr(F, from, to);
958 print_data_edge_vcgattr(F, from, to);
970 print_data_edge_vcgattr(F, from, to);
973 if (get_irn_modecode(from) == irm_M)
974 fprintf (F, INTER_MEM_EDGE_ATTR);
976 print_data_edge_vcgattr(F, from, to);
983 print_mem_edge_vcgattr(F, from, to);
985 print_data_edge_vcgattr(F, from, to);
988 print_mem_edge_vcgattr(F, from, to);
990 case iro_Tuple: break;
993 switch (get_irn_modecode(from)) {
995 fprintf (F, CF_EDGE_ATTR);
998 fprintf (F, INTER_MEM_EDGE_ATTR);
1001 print_data_edge_vcgattr(F, from, to);
1005 case iro_Bad: break;
1006 case iro_Unknown: break;
1008 switch (get_irn_modecode(from)) {
1010 fprintf (F, INTRA_MEM_EDGE_ATTR);
1013 fprintf (F, CF_EDGE_ATTR);
1016 print_data_edge_vcgattr(F, from, to);
1024 /* dump edges to our inputs */
1026 dump_ir_data_edges(FILE *F, ir_node *n) {
1028 unsigned long visited = get_irn_visited(n);
1030 if ((get_irn_op(n) == op_End) && (!dump_keepalive))
1033 for (i = 0; i < get_irn_arity(n); i++) {
1034 ir_node * pred = get_irn_n(n, i);
1037 if ((get_interprocedural_view() && get_irn_visited(pred) < visited))
1038 continue; /* pred not dumped */
1040 if (dump_backedge_information_flag && is_backedge(n, i))
1041 fprintf (F, "backedge: {sourcename: \"");
1043 fprintf (F, "edge: {sourcename: \"");
1045 fprintf (F, "\" targetname: ");
1046 if ((get_opt_dump_const_local()) && is_constlike_node(pred)) {
1047 PRINT_CONSTID(n, pred);
1049 fprintf(F, "\""); PRINT_NODEID(pred); fprintf(F, "\"");
1051 fprintf (F, " label: \"%d\" ", i);
1052 print_edge_vcgattr(F, n, i);
1057 /** Dumps a node and its edges but not the block edge
1060 dump_node_wo_blockedge (ir_node *n, void *env) {
1063 dump_ir_data_edges(F, n);
1066 /** Dumps a node and its edges.
1069 dump_whole_node (ir_node *n, void *env) {
1071 dump_node_wo_blockedge(n, env);
1072 if (!node_floats(n)) dump_ir_block_edge(F, n);
1076 dump_const_node(ir_node *n, void *env) {
1077 if (is_Block(n)) return;
1078 dump_node_wo_blockedge(n, env);
1081 /***********************************************************************/
1082 /* the following routines dump the nodes/irgs bracketed to graphs. */
1083 /***********************************************************************/
1085 /** Dumps a constant expression as entity initializer, array bound ...
1087 static void dump_const_expression(FILE *F, ir_node *value) {
1088 ir_graph *rem = current_ir_graph;
1089 int rem_dump_const_local = dump_const_local;
1090 dump_const_local = 0;
1091 current_ir_graph = get_const_code_irg();
1092 irg_walk(value, dump_const_node, NULL, F);
1093 /* Decrease visited flag so that we walk with the same flag for the next
1094 expresssion. This guarantees that we don't dump the same node twice,
1095 as for const expressions cse is performed to save memory. */
1096 set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph) -1);
1097 current_ir_graph = rem;
1098 dump_const_local = rem_dump_const_local;
1101 /** Dump a block as graph containing its nodes.
1103 * Expects to find nodes belonging to the block as list in its
1105 * Dumps the edges of all nodes including itself. */
1107 dump_whole_block(FILE *F, ir_node *block) {
1109 assert(is_Block(block));
1111 fprintf(F, "graph: { title: \"");
1112 PRINT_NODEID(block);
1113 fprintf(F, "\" label: \"");
1114 dump_node_label(F, block);
1116 if (get_opt_dump_abstvals())
1117 fprintf (F, " seqno: %d", (int)get_Block_seqno(block));
1119 fprintf(F, "\" status:clustered color:%s \n",
1120 get_Block_matured(block) ? "yellow" : "red");
1122 /* dump the blocks edges */
1123 dump_ir_data_edges(F, block);
1125 /* dump the nodes that go into the block */
1126 for (node = ird_get_irn_link(block); node; node = ird_get_irn_link(node)) {
1128 dump_ir_data_edges(F, node);
1131 /* Close the vcg information for the block */
1133 dump_const_node_local(F, block);
1135 dump_irn_chi_term(F, block);
1140 /** dumps a graph block-wise. Expects all blockless nodes in arr in irgs link.
1141 * The outermost nodes: blocks and nodes not op_pin_state_pinned, Bad, Unknown. */
1143 dump_block_graph(FILE *F, ir_graph *irg) {
1145 ir_graph *rem = current_ir_graph;
1146 ir_node **arr = ird_get_irg_link(irg);
1147 current_ir_graph = irg;
1149 for (i = ARR_LEN(arr) - 1; i >= 0; --i) {
1150 ir_node * node = arr[i];
1151 if (is_Block(node)) {
1152 /* Dumps the block and all the nodes in the block, which are to
1153 be found in Block->link. */
1154 dump_whole_block(F, node);
1156 /* Nodes that are not in a Block. */
1158 if (is_Bad(get_nodes_block(node)) && !node_floats(node)) {
1159 dump_const_block_local(F, node);
1161 dump_ir_data_edges(F, node);
1165 if (dump_loop_information_flag && (get_irg_loopinfo_state(irg) & loopinfo_valid))
1166 dump_loop_nodes_into_graph(F, irg);
1168 current_ir_graph = rem;
1171 /** Dumps an irg as a graph.
1172 * If interprocedural view edges can point to nodes out of this graph.
1174 static void dump_graph_from_list(FILE *F, ir_graph *irg) {
1176 fprintf(F, "graph: { title: \"");
1178 fprintf(F, "\" label: \"%s\" status:clustered color:white \n",
1179 get_ent_dump_name(get_irg_entity(irg)));
1181 dump_block_graph(F, irg);
1183 /* Close the vcg information for the irg */
1184 fprintf(F, "}\n\n");
1187 /*******************************************************************/
1188 /* Basic type and entity nodes and edges. */
1189 /*******************************************************************/
1191 /** dumps the edges between nodes and their type or entity attributes. */
1192 static void dump_node2type_edges(ir_node *n, void *env)
1197 switch (get_irn_opcode(n)) {
1199 /* @@@ some consts have an entity */
1202 if ( (get_SymConst_kind(n) ==symconst_type_tag)
1203 || (get_SymConst_kind(n) ==symconst_size))
1205 print_node_type_edge(F,n,get_SymConst_type(n),NODE2TYPE_EDGE_ATTR);
1209 print_node_ent_edge(F,n,get_Sel_entity(n),NODE2TYPE_EDGE_ATTR);
1212 print_node_type_edge(F,n,get_Call_type(n),NODE2TYPE_EDGE_ATTR);
1215 print_node_type_edge(F,n,get_Alloc_type(n),NODE2TYPE_EDGE_ATTR);
1218 print_node_type_edge(F,n,get_Free_type(n),NODE2TYPE_EDGE_ATTR);
1221 print_node_type_edge(F,n,get_Cast_type(n),NODE2TYPE_EDGE_ATTR);
1229 static int print_type_info(FILE *F, type *tp) {
1232 if (get_type_state(tp) == layout_undefined) {
1233 fprintf(F, "state: layout_undefined\n");
1235 fprintf(F, "state: layout_fixed,\n");
1237 if (get_type_mode(tp))
1238 fprintf(F, "mode: %s,\n", get_mode_name_ex(get_type_mode(tp), &bad));
1239 fprintf(F, "size: %db,\n", get_type_size_bits(tp));
1244 static void print_typespecific_info(FILE *F, type *tp) {
1245 switch (get_type_tpop_code(tp)) {
1248 fprintf(F, "peculiarity: %s\n", get_peculiarity_string(get_class_peculiarity(tp)));
1255 fprintf(F, "variadicity: %s\n", get_variadicity_name(get_method_variadicity(tp)));
1256 fprintf(F, "params: %d\n", get_method_n_params(tp));
1257 fprintf(F, "results: %d\n", get_method_n_ress(tp));
1265 case tpo_enumeration:
1279 static void print_typespecific_vcgattr(FILE *F, type *tp) {
1280 switch (get_type_tpop_code(tp)) {
1283 if (peculiarity_existent == get_class_peculiarity(tp))
1284 fprintf (F, " " TYPE_CLASS_NODE_ATTR);
1286 fprintf (F, " " TYPE_DESCRIPTION_NODE_ATTR);
1290 fprintf (F, " " TYPE_METH_NODE_ATTR);
1301 case tpo_enumeration:
1314 static int print_type_node(FILE *F, type *tp)
1318 fprintf (F, "node: {title: ");
1320 fprintf (F, " label: \"%s %s\"", get_type_tpop_name(tp), get_type_name_ex(tp, &bad));
1321 fprintf (F, " info1: \"");
1322 bad |= print_type_info(F, tp);
1323 print_typespecific_info(F, tp);
1325 print_typespecific_vcgattr(F, tp);
1331 #define X(a) case a: fprintf(F, #a); break
1332 void dump_entity_node(FILE *F, entity *ent, int color)
1334 fprintf (F, "node: {title: \"");
1335 PRINT_ENTID(ent); fprintf(F, "\"");
1336 fprintf (F, DEFAULT_TYPE_ATTRIBUTE);
1337 fprintf (F, "label: ");
1338 fprintf (F, "\"ent %s\" ", get_ent_dump_name(ent));
1340 fprintf(F, "color: %d", color);
1342 fprintf (F, ENTITY_NODE_ATTR);
1343 fprintf (F, "\n info1: \"");
1345 dump_entity_to_file(F, ent, dump_verbosity_entattrs | dump_verbosity_entconsts);
1347 fprintf(F, "\"\n}\n");
1351 static void dump_enum_item(FILE *F, type *tp, int pos)
1354 ident *id = get_enumeration_nameid(tp, pos);
1355 tarval *tv = get_enumeration_enum(tp, pos);
1357 tarval_snprintf(buf, sizeof(buf), tv);
1358 fprintf (F, "node: {title: \"");
1359 PRINT_ITEMID(tp, pos); fprintf(F, "\"");
1360 fprintf (F, DEFAULT_ENUM_ITEM_ATTRIBUTE);
1361 fprintf (F, "label: ");
1362 fprintf (F, "\"enum item %s\" " ENUM_ITEM_NODE_ATTR, get_id_str(id));
1363 fprintf (F, "\n info1: \"value: %s\"}\n", buf);
1366 /* dumps a type or entity and it's edges. */
1368 dump_type_info(type_or_ent *tore, void *env) {
1370 int i = 0; /* to shutup gcc */
1372 /* dump this type or entity */
1374 switch (get_kind(tore)) {
1377 entity *ent = (entity *)tore;
1380 dump_entity_node(F, ent, 0);
1382 /* skip this to reduce graph. Member edge of type is parallel to this edge. *
1383 fprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
1384 ENT_OWN_EDGE_ATTR "}\n", ent, get_entity_owner(ent));*/
1385 print_ent_type_edge(F,ent, get_entity_type(ent), ENT_TYPE_EDGE_ATTR);
1386 if (is_Class_type(get_entity_owner(ent))) {
1387 for(i = 0; i < get_entity_n_overwrites(ent); i++)
1388 print_ent_ent_edge(F,ent, get_entity_overwrites(ent, i), 0, ENT_OVERWRITES_EDGE_ATTR);
1390 /* attached subgraphs */
1391 if (const_entities && (get_entity_variability(ent) != variability_uninitialized)) {
1392 if (is_atomic_entity(ent)) {
1393 value = get_atomic_ent_value(ent);
1395 print_ent_node_edge(F, ent, value, ENT_VALUE_EDGE_ATTR, i);
1396 /* DDMN(value); $$$ */
1397 dump_const_expression(F, value);
1400 if (is_compound_entity(ent)) {
1401 for (i = 0; i < get_compound_ent_n_values(ent); i++) {
1402 value = get_compound_ent_value(ent, i);
1404 print_ent_node_edge(F, ent, value, ENT_VALUE_EDGE_ATTR, i);
1405 dump_const_expression(F, value);
1406 print_ent_ent_edge(F, ent, get_compound_ent_value_member(ent, i), 0, ENT_CORR_EDGE_ATTR, i);
1408 fprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
1409 ENT_CORR_EDGE_ATTR "}\n", GET_ENTID(ent),
1410 get_compound_ent_value_member(ent, i), i);
1419 type *tp = (type *)tore;
1420 print_type_node(F, tp);
1421 /* and now the edges */
1422 switch (get_type_tpop_code(tp)) {
1425 for (i=0; i < get_class_n_supertypes(tp); i++)
1426 print_type_type_edge(F, tp,get_class_supertype(tp, i),TYPE_SUPER_EDGE_ATTR);
1427 for (i=0; i < get_class_n_members(tp); i++)
1428 print_type_ent_edge(F,tp,get_class_member(tp, i),TYPE_MEMBER_EDGE_ATTR);
1432 for (i=0; i < get_struct_n_members(tp); i++)
1433 print_type_ent_edge(F,tp,get_struct_member(tp, i),TYPE_MEMBER_EDGE_ATTR);
1437 for (i = 0; i < get_method_n_params(tp); i++)
1438 print_type_type_edge(F,tp,get_method_param_type(tp, i),METH_PAR_EDGE_ATTR,i);
1439 for (i = 0; i < get_method_n_ress(tp); i++)
1440 print_type_type_edge(F,tp,get_method_res_type(tp, i),METH_RES_EDGE_ATTR,i);
1444 for (i = 0; i < get_union_n_members(tp); i++)
1445 print_type_ent_edge(F,tp,get_union_member(tp, i),UNION_EDGE_ATTR);
1449 print_type_type_edge(F,tp,get_array_element_type(tp),ARR_ELT_TYPE_EDGE_ATTR);
1450 print_type_ent_edge(F,tp,get_array_element_entity(tp),ARR_ENT_EDGE_ATTR);
1451 for (i = 0; i < get_array_n_dimensions(tp); i++) {
1452 ir_node *upper = get_array_upper_bound(tp, i);
1453 ir_node *lower = get_array_lower_bound(tp, i);
1454 print_node_type_edge(F, upper, tp, "label: \"upper %d\"", get_array_order(tp, i));
1455 print_node_type_edge(F, lower, tp, "label: \"lower %d\"", get_array_order(tp, i));
1456 dump_const_expression(F, upper);
1457 dump_const_expression(F, lower);
1461 case tpo_enumeration:
1463 for (i = 0; i < get_enumeration_n_enums(tp); ++i) {
1464 dump_enum_item(F, tp, i);
1465 print_enum_item_edge(F, tp, i, "label: \"item %d\"", i);
1470 print_type_type_edge(F,tp,get_pointer_points_to_type(tp), PTR_PTS_TO_EDGE_ATTR);
1478 break; /* case k_type */
1481 printf(" *** irdump, dump_type_info(l.%i), faulty type.\n", __LINE__);
1483 } /* switch kind_or_entity */
1486 typedef struct _h_env {
1491 /** For dumping class hierarchies.
1492 * Dumps a class type node and a superclass edge.
1493 * If env->dump_ent dumps entities of classes and overwrites edges.
1496 dump_class_hierarchy_node (type_or_ent *tore, void *ctx) {
1499 int i = 0; /* to shutup gcc */
1501 /* dump this type or entity */
1502 switch (get_kind(tore)) {
1504 entity *ent = (entity *)tore;
1505 if (get_entity_owner(ent) == get_glob_type()) break;
1506 if (!is_Method_type(get_entity_type(ent))) break; /* GL */
1507 if (env->dump_ent && is_Class_type(get_entity_owner(ent))) {
1509 dump_entity_node(F, ent, 0);
1511 print_type_ent_edge(F,get_entity_owner(ent),ent,TYPE_MEMBER_EDGE_ATTR);
1512 for(i = 0; i < get_entity_n_overwrites(ent); i++)
1513 print_ent_ent_edge(F, get_entity_overwrites(ent, i), ent, 0, ENT_OVERWRITES_EDGE_ATTR);
1515 } break; /* case k_entity */
1518 type *tp = (type *)tore;
1519 if (tp == get_glob_type()) break;
1520 switch (get_type_tpop_code(tp)) {
1522 print_type_node(F, tp);
1523 /* and now the edges */
1524 for (i=0; i < get_class_n_supertypes(tp); i++)
1526 print_type_type_edge(F,tp,get_class_supertype(tp, i),TYPE_SUPER_EDGE_ATTR);
1532 break; /* case k_type */
1535 printf(" *** irdump, dump_class_hierarchy_node(l.%i), faulty type.\n", __LINE__);
1537 } /* switch kind_or_entity */
1540 /*******************************************************************/
1541 /* dump analysis information that is expressed in graph terms. */
1542 /*******************************************************************/
1544 /* dump out edges */
1546 dump_out_edge(ir_node *n, void *env) {
1549 for (i = 0; i < get_irn_n_outs(n); i++) {
1550 assert(get_irn_out(n, i));
1551 fprintf (F, "edge: {sourcename: \"");
1553 fprintf (F, "\" targetname: \"");
1554 PRINT_NODEID(get_irn_out(n, i));
1555 fprintf (F, "\" color: red linestyle: dashed");
1561 dump_loop_label(FILE *F, ir_loop *loop) {
1562 fprintf (F, "loop %d, %d sons, %d nodes",
1563 get_loop_depth(loop), get_loop_n_sons(loop), get_loop_n_nodes(loop));
1566 static INLINE void dump_loop_info(FILE *F, ir_loop *loop) {
1567 fprintf (F, " info1: \"");
1568 fprintf (F, " loop nr: %d", get_loop_loop_nr(loop));
1569 #if DEBUG_libfirm /* GL @@@ debug analyses */
1570 fprintf (F, "\n The loop was analyzed %d times.", (int)get_loop_link(loop));
1576 dump_loop_node(FILE *F, ir_loop *loop) {
1577 fprintf (F, "node: {title: \"");
1579 fprintf (F, "\" label: \"");
1580 dump_loop_label(F, loop);
1582 dump_loop_info(F, loop);
1588 dump_loop_node_edge(FILE *F, ir_loop *loop, int i) {
1590 fprintf (F, "edge: {sourcename: \"");
1592 fprintf (F, "\" targetname: \"");
1593 PRINT_NODEID(get_loop_node(loop, i));
1594 fprintf (F, "\" color: green");
1599 dump_loop_son_edge(FILE *F, ir_loop *loop, int i) {
1601 fprintf (F, "edge: {sourcename: \"");
1603 fprintf (F, "\" targetname: \"");
1604 PRINT_LOOPID(get_loop_son(loop, i));
1605 fprintf (F, "\" color: darkgreen label: \"%d\"}\n",
1606 get_loop_element_pos(loop, get_loop_son(loop, i)));
1610 void dump_loops(FILE *F, ir_loop *loop) {
1612 /* dump this loop node */
1613 dump_loop_node(F, loop);
1615 /* dump edges to nodes in loop -- only if it is a real loop */
1616 if (get_loop_depth(loop) != 0) {
1617 for (i = 0; i < get_loop_n_nodes(loop); i++) {
1618 dump_loop_node_edge(F, loop, i);
1621 for (i = 0; i < get_loop_n_sons(loop); i++) {
1622 dump_loops(F, get_loop_son(loop, i));
1623 dump_loop_son_edge(F, loop, i);
1628 void dump_loop_nodes_into_graph(FILE *F, ir_graph *irg) {
1629 ir_graph *rem = current_ir_graph;
1630 current_ir_graph = irg;
1632 if (get_irg_loop(irg)) dump_loops(F, get_irg_loop(irg));
1634 current_ir_graph = rem;
1639 * dumps the VCG header
1641 INLINE void dump_vcg_header(FILE *F, const char *name, const char *orientation) {
1650 if (!orientation) orientation = "bottom_to_top";
1654 "graph: { title: \"ir graph of %s\"\n"
1655 "display_edge_labels: %s\n"
1656 "layoutalgorithm: mindepth\n"
1657 "manhattan_edges: yes\n"
1658 "port_sharing: no\n"
1660 "classname 1: \"intrablock Data\"\n"
1661 "classname 16: \"interblock Data\"\n"
1662 "classname 2: \"Block\"\n"
1663 "classname 13: \"Control Flow\"\n"
1664 "classname 18: \"Exception Control Flow for Interval Analysis\"\n"
1665 "classname 14: \"intrablock Memory\"\n"
1666 "classname 17: \"interblock Memory\"\n"
1667 "classname 15: \"Dominators\"\n"
1668 "classname 3: \"Entity type\"\n"
1669 "classname 4: \"Entity owner\"\n"
1670 "classname 5: \"Method Param\"\n"
1671 "classname 6: \"Method Res\"\n"
1672 "classname 7: \"Super\"\n"
1673 "classname 8: \"Union\"\n"
1674 "classname 9: \"Points-to\"\n"
1675 "classname 10: \"Array Element Type\"\n"
1676 "classname 11: \"Overwrites\"\n"
1677 "classname 12: \"Member\"\n"
1678 "infoname 1: \"Attribute\"\n"
1679 "infoname 2: \"Verification errors\"\n",
1680 name, label, orientation);
1682 /* don't use all, the range is too whith/black. */
1686 "colorentry 100: 0 0 0\n"
1687 "colorentry 101: 20 0 0\n"
1688 "colorentry 102: 40 0 0\n"
1689 "colorentry 103: 60 0 0\n"
1690 "colorentry 104: 80 0 0\n"
1691 "colorentry 105: 100 0 0\n"
1692 "colorentry 106: 120 0 0\n"
1693 "colorentry 107: 140 0 0\n"
1694 "colorentry 108: 150 0 0\n"
1695 "colorentry 109: 180 0 0\n"
1696 "colorentry 110: 200 0 0\n"
1697 "colorentry 111: 220 0 0\n"
1698 "colorentry 112: 240 0 0\n"
1699 "colorentry 113: 255 0 0\n"
1700 "colorentry 113: 255 20 20\n"
1701 "colorentry 114: 255 40 40\n"
1702 "colorentry 115: 255 60 60\n"
1703 "colorentry 116: 255 80 80\n"
1704 "colorentry 117: 255 100 100\n"
1705 "colorentry 118: 255 120 120\n"
1706 "colorentry 119: 255 140 140\n"
1707 "colorentry 120: 255 150 150\n"
1708 "colorentry 121: 255 180 180\n"
1709 "colorentry 122: 255 200 200\n"
1710 "colorentry 123: 255 220 220\n"
1711 "colorentry 124: 255 240 240\n"
1712 "colorentry 125: 255 250 250\n"
1715 fprintf (F, "\n"); /* a separator */
1721 * @param irg The graph to be dumped
1722 * @param suffix1 first filename suffix
1723 * @param suffix2 second filename suffix
1725 FILE *vcg_open (ir_graph *irg, const char * suffix1, const char *suffix2) {
1727 const char *nm = get_irg_dump_name(irg);
1728 int len = strlen(nm), i, j;
1729 char *fname; /* filename to put the vcg information in */
1731 if (!suffix1) suffix1 = "";
1732 if (!suffix2) suffix2 = "";
1734 /* open file for vcg graph */
1735 fname = malloc (len * 2 + strlen(suffix1) + strlen(suffix2) + 5);
1737 /* strncpy (fname, nm, len); */ /* copy the filename */
1739 for (i = 0; i < len; ++i) { /* replace '/' in the name: escape by @. */
1741 fname[j] = '@'; j++; fname[j] = '1'; j++;
1742 } else if (nm[i] == '@') {
1743 fname[j] = '@'; j++; fname[j] = '2'; j++;
1745 fname[j] = nm[i]; j++;
1749 strcat (fname, suffix1); /* append file suffix */
1750 strcat (fname, suffix2); /* append file suffix */
1751 strcat (fname, ".vcg"); /* append the .vcg suffix */
1753 /* vcg really expect only a <CR> at end of line, so
1754 * the "b"inary mode is what you mean (and even needed for Win32)
1756 F = fopen (fname, "wb"); /* open file for writing */
1758 panic("cannot open %s for writing (%m)", fname); /* not reached */
1768 * @param irg The graph to be dumped
1769 * @param suffix filename suffix
1771 FILE *vcg_open_name (const char *name, const char *suffix) {
1773 char *fname; /* filename to put the vcg information in */
1774 int i, j, len = strlen(name);
1776 if (!suffix) suffix = "";
1778 /** open file for vcg graph */
1779 fname = malloc (len * 2 + 5 + strlen(suffix));
1780 /* strcpy (fname, name);*/ /* copy the filename */
1782 for (i = 0; i < len; ++i) { /* replace '/' in the name: escape by @. */
1783 if (name[i] == '/') {
1784 fname[j] = '@'; j++; fname[j] = '1'; j++;
1785 } else if (name[i] == '@') {
1786 fname[j] = '@'; j++; fname[j] = '2'; j++;
1788 fname[j] = name[i]; j++;
1792 strcat (fname, suffix);
1793 strcat (fname, ".vcg"); /* append the .vcg suffix */
1795 /* vcg really expect only a <CR> at end of line, so
1796 * the "b"inary mode is what you mean (and even needed for Win32)
1798 F = fopen (fname, "wb"); /* open file for writing */
1800 panic ("cannot open %s for writing (%m)", fname); /* not reached */
1808 * Dumps the vcg file footer
1810 static INLINE void dump_vcg_footer (FILE *F) {
1815 * close the vcg file
1817 void vcg_close (FILE *F) {
1818 dump_vcg_footer(F); /* print footer */
1819 fclose (F); /* close vcg file */
1822 /************************************************************************/
1823 /************************************************************************/
1824 /* Routines that dump all or parts of the firm representation to a file */
1825 /************************************************************************/
1826 /************************************************************************/
1828 /************************************************************************/
1829 /* Dump ir graphs, different formats and additional information. */
1830 /************************************************************************/
1832 /** Routine to dump a graph, blocks as conventional nodes. */
1834 dump_ir_graph (ir_graph *irg, const char *suffix )
1839 rem = current_ir_graph;
1841 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg)))) return;
1843 current_ir_graph = irg;
1844 if (get_interprocedural_view()) suffix1 = "-pure-ip";
1845 else suffix1 = "-pure";
1846 f = vcg_open(irg, suffix, suffix1);
1847 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1849 /* walk over the graph */
1850 /* dump_whole_node must be called in post visiting predecessors */
1851 irg_walk(get_irg_end(irg), NULL, dump_whole_node, f);
1853 /* dump the out edges in a separate walk */
1854 if ((dump_out_edge_flag) && (get_irg_outs_state(irg) != outs_none)) {
1855 irg_out_walk(get_irg_start(irg), dump_out_edge, NULL, f);
1860 current_ir_graph = rem;
1865 dump_ir_block_graph (ir_graph *irg, const char *suffix)
1871 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg))))
1874 if (get_interprocedural_view()) suffix1 = "-ip";
1876 f = vcg_open(irg, suffix, suffix1);
1877 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1879 construct_block_lists(irg);
1881 for (i = 0; i < get_irp_n_irgs(); i++) {
1882 ir_node **arr = ird_get_irg_link(get_irp_irg(i));
1884 dump_graph_from_list(f, get_irp_irg(i));
1892 /** dumps a graph with type information */
1894 dump_ir_graph_w_types (ir_graph *irg, const char *suffix)
1897 ir_graph *rem = current_ir_graph;
1900 /* if a filter is set, dump only the irg's that match the filter */
1901 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg))))
1904 current_ir_graph = irg;
1906 if (get_interprocedural_view()) suffix1 = "-pure-wtypes-ip";
1907 else suffix1 = "-pure-wtypes";
1908 f = vcg_open(irg,suffix, suffix1);
1909 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1911 /* dump common ir graph */
1912 irg_walk(get_irg_end(irg), NULL, dump_whole_node, f);
1913 /* dump type info */
1914 type_walk_irg(irg, dump_type_info, NULL, f);
1915 inc_irg_visited(get_const_code_irg());
1916 /* dump edges from graph to type info */
1917 irg_walk(get_irg_end(irg), dump_node2type_edges, NULL, f);
1920 current_ir_graph = rem;
1924 dump_ir_block_graph_w_types (ir_graph *irg, const char *suffix)
1929 ir_graph *rem = current_ir_graph;
1931 /* if a filter is set, dump only the irg's that match the filter */
1932 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg))))
1935 if (get_interprocedural_view()) suffix1 = "-wtypes-ip";
1936 else suffix1 = "-wtypes";
1937 f = vcg_open(irg, suffix, suffix1);
1938 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1940 /* dump common blocked ir graph */
1941 construct_block_lists(irg);
1943 for (i = 0; i < get_irp_n_irgs(); i++) {
1944 ir_node **arr = ird_get_irg_link(get_irp_irg(i));
1946 dump_graph_from_list(f, get_irp_irg(i));
1951 /* dump type info */
1952 current_ir_graph = irg;
1953 type_walk_irg(irg, dump_type_info, NULL, f);
1954 inc_irg_visited(get_const_code_irg());
1956 /* dump edges from graph to type info */
1957 irg_walk(get_irg_end(irg), dump_node2type_edges, NULL, f);
1959 current_ir_graph = rem;
1963 /*---------------------------------------------------------------------*/
1964 /* The following routines dump a control flow graph. */
1965 /*---------------------------------------------------------------------*/
1968 dump_block_to_cfg(ir_node *block, void *env) {
1973 if (is_Block(block)) {
1974 /* This is a block. Dump a node for the block. */
1975 fprintf (F, "node: {title: \""); PRINT_NODEID(block);
1976 fprintf (F, "\" label: \"");
1977 if (block == get_irg_start_block(get_irn_irg(block)))
1978 fprintf(F, "Start ");
1979 if (block == get_irg_end_block(get_irn_irg(block)))
1982 fprintf (F, "%s ", get_op_name(get_irn_op(block)));
1983 PRINT_NODEID(block);
1985 fprintf(F, "info1:\"");
1986 if (dump_dominator_information_flag) {
1987 fprintf(F, "dom depth %d\n", get_Block_dom_depth(block));
1988 fprintf(F, "tree pre num %d\n", get_Block_dom_tree_pre_num(block));
1989 fprintf(F, "max subtree pre num %d\n", get_Block_dom_max_subtree_pre_num(block));
1992 /* show arity and possible Bad predecessors of the block */
1993 fprintf(F, "arity: %d\n", get_Block_n_cfgpreds(block));
1994 for (fl = i = 0; i < get_Block_n_cfgpreds(block); ++i) {
1995 ir_node *pred = get_Block_cfgpred(block, i);
1998 fprintf(F, "Bad pred at pos: ");
1999 fprintf(F, "%d ", i);
2006 fprintf (F, "\""); /* closing quote of info */
2008 if ((block == get_irg_start_block(get_irn_irg(block))) ||
2009 (block == get_irg_end_block(get_irn_irg(block))) )
2010 fprintf(F, " color:blue ");
2012 fprintf(F, " color:yellow ");
2015 /* Dump the edges */
2016 for ( i = 0; i < get_Block_n_cfgpreds(block); i++)
2017 if (get_irn_op(skip_Proj(get_Block_cfgpred(block, i))) != op_Bad) {
2018 pred = get_nodes_block(skip_Proj(get_Block_cfgpred(block, i)));
2019 fprintf (F, "edge: { sourcename: \"");
2020 PRINT_NODEID(block);
2021 fprintf (F, "\" targetname: \"");
2023 fprintf (F, "\"}\n");
2026 /* Dump dominator edge */
2027 if (dump_dominator_information_flag && get_Block_idom(block)) {
2028 pred = get_Block_idom(block);
2029 fprintf (F, "edge: { sourcename: \"");
2030 PRINT_NODEID(block);
2031 fprintf (F, "\" targetname: \"");
2033 fprintf (F, "\" " DOMINATOR_EDGE_ATTR "}\n");
2039 dump_cfg (ir_graph *irg, const char *suffix)
2042 ir_graph *rem = current_ir_graph;
2043 int ddif = dump_dominator_information_flag;
2044 int ipv = get_interprocedural_view();
2046 /* if a filter is set, dump only the irg's that match the filter */
2047 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg))))
2050 current_ir_graph = irg;
2052 f = vcg_open(irg, suffix, "-cfg");
2053 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
2056 printf("Warning: dumping cfg not in interprocedural view!\n");
2057 set_interprocedural_view(false);
2060 if (get_irg_dom_state(irg) != dom_consistent)
2061 dump_dominator_information_flag = 0;
2063 /* walk over the blocks in the graph */
2064 irg_block_walk(get_irg_end(irg), dump_block_to_cfg, NULL, f);
2065 dump_node(f, get_irg_bad(irg));
2067 dump_dominator_information_flag = ddif;
2068 set_interprocedural_view(ipv);
2070 current_ir_graph = rem;
2074 static void descend_and_dump(FILE *F, ir_node *n, int depth, pset *mark_set) {
2075 if (pset_find_ptr(mark_set, n)) return;
2077 pset_insert_ptr(mark_set, n);
2080 int i, start = is_Block(n) ? 0 : -1;
2081 dump_whole_node(n, F);
2082 for (i = start; i < get_irn_arity(n); ++i)
2083 descend_and_dump(F, get_irn_n(n, i), depth-1, mark_set);
2086 /* Don't dump edges to nodes further out. These might be edges to
2087 nodes we already dumped, if there is a shorter path to these. */
2091 static int subgraph_counter = 0;
2092 void dump_subgraph (ir_node *root, int depth, const char *suffix) {
2095 pset *mark_set = pset_new_ptr(1);
2096 sprintf(buf, "-subg_%03d", subgraph_counter++);
2097 F = vcg_open(get_irn_irg(root), suffix, buf);
2098 dump_vcg_header(F, get_irg_dump_name(get_irn_irg(root)), NULL);
2099 descend_and_dump(F, root, depth, mark_set);
2105 static int weight_overall(int rec, int loop) {
2106 return 2*rec + loop;
2109 static int compute_color (int my, int max) {
2116 /* if small, scale to the full color range. */
2118 my = my * (n_colors/max);
2120 step = 1 + (max / n_colors);
2124 return base_color + n_colors - color;
2127 static int get_entity_color(entity *ent) {
2128 ir_graph *irg = get_entity_irg(ent);
2132 int rec_depth = get_irg_recursion_depth(irg);
2133 int loop_depth = get_irg_loop_depth(irg);
2134 int overall_depth = weight_overall(rec_depth, loop_depth);
2136 int max_rec_depth = irp->max_callgraph_recursion_depth;
2137 int max_loop_depth = irp->max_callgraph_loop_depth;
2138 int max_overall_depth = weight_overall(max_rec_depth, max_loop_depth);
2140 /* int my_rec_color = compute_color(rec_depth, max_rec_depth); */
2141 /* int my_loop_color = compute_color(loop_depth, max_loop_depth); */
2142 int my_overall_color = compute_color(overall_depth, max_overall_depth);;
2144 return my_overall_color;
2148 void dump_callgraph(const char *suffix) {
2150 int i, n_irgs = get_irp_n_irgs();
2151 int rem = edge_label;
2153 //ident *prefix = new_id_from_str("java/");
2155 F = vcg_open_name("Callgraph", suffix);
2156 dump_vcg_header(F, "Callgraph", NULL);
2158 for (i = 0; i < n_irgs; ++i) {
2159 ir_graph *irg = get_irp_irg(i);
2160 entity *ent = get_irg_entity(irg);
2161 int j, n_callees = get_irg_n_callees(irg);
2163 /* Do not dump runtime system. */
2164 //if (id_is_prefix(prefix, get_entity_ld_ident(ent))) continue;
2166 dump_entity_node(F, ent, get_entity_color(ent));
2167 for (j = 0; j < n_callees; ++j) {
2168 entity *c = get_irg_entity(get_irg_callee(irg, j));
2169 //if (id_is_prefix(prefix, get_entity_ld_ident(c))) continue;
2170 int be = is_irg_callee_backedge(irg, j);
2173 "label:\"recursion %d\" color: %d" :
2174 "label:\"calls %d\" color: %d";
2175 print_ent_ent_edge(F, ent, c, be, attr, get_irg_callee_loop_depth(irg, j), get_entity_color(ent));
2183 /* Dump all irgs in interprocedural view to a single file. */
2184 void dump_all_cg_block_graph(const char *suffix) {
2187 int rem_view = get_interprocedural_view();
2188 set_interprocedural_view(true);
2190 f = vcg_open_name("All_graphs", suffix);
2191 dump_vcg_header(f, "All_graphs", NULL);
2193 /* collect nodes in all irgs reachable in call graph*/
2194 for (i = 0; i < get_irp_n_irgs(); i++)
2195 ird_set_irg_link(get_irp_irg(i), NULL);
2197 cg_walk(clear_link, collect_node, NULL);
2199 /* dump all graphs */
2200 for (i = 0; i < get_irp_n_irgs(); i++) {
2201 current_ir_graph = get_irp_irg(i);
2202 assert(ird_get_irg_link(current_ir_graph));
2203 dump_graph_from_list(f, current_ir_graph);
2204 DEL_ARR_F(ird_get_irg_link(current_ir_graph));
2208 set_interprocedural_view(rem_view);
2211 /*---------------------------------------------------------------------*/
2212 /* the following routines dumps type information without any ir nodes. */
2213 /*---------------------------------------------------------------------*/
2216 dump_type_graph (ir_graph *irg, const char *suffix)
2220 rem = current_ir_graph;
2222 /* if a filter is set, dump only the irg's that match the filter */
2223 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg)))) return;
2225 current_ir_graph = irg;
2227 f = vcg_open(irg, suffix, "-type");
2228 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
2230 /* walk over the blocks in the graph */
2231 type_walk_irg(irg, dump_type_info, NULL, f);
2232 /* The walker for the const code can be called several times for the
2233 same (sub) expression. So that no nodes are dumped several times
2234 we decrease the visited flag of the corresponding graph after each
2235 walk. So now increase it finally. */
2236 inc_irg_visited(get_const_code_irg());
2239 current_ir_graph = rem;
2243 dump_all_types (const char *suffix)
2245 FILE *f = vcg_open_name("All_types", suffix);
2246 dump_vcg_header(f, "All_types", NULL);
2247 type_walk(dump_type_info, NULL, f);
2248 inc_irg_visited(get_const_code_irg());
2253 dump_class_hierarchy (bool entities, const char *suffix)
2255 FILE *f = vcg_open_name("class_hierarchy", suffix);
2259 dump_vcg_header(f, "class_hierarchy", NULL);
2264 type_walk(dump_class_hierarchy_node, NULL, &env);
2268 /*---------------------------------------------------------------------*/
2269 /* dumps all graphs with the graph-dumper passed. Possible dumpers: */
2271 /* dump_ir_block_graph */
2273 /* dump_type_graph */
2274 /* dump_ir_graph_w_types */
2275 /*---------------------------------------------------------------------*/
2277 void dump_all_ir_graphs(dump_graph_func *dmp_grph, const char *suffix) {
2278 int i, n_irgs = get_irp_n_irgs();
2279 for (i = 0; i < n_irgs; ++i) {
2280 dmp_grph(get_irp_irg(i), suffix);
2285 /*--------------------------------------------------------------------------------*
2286 * Dumps a stand alone loop graph with firm nodes which belong to one loop node *
2287 * packed together in one subgraph/box *
2288 *--------------------------------------------------------------------------------*/
2290 void dump_loops_standalone(FILE *F, ir_loop *loop) {
2291 int i = 0, loop_node_started = 0, son_number = 0, first = 0;
2293 ir_loop *son = NULL;
2295 /* Dump a new loop node. */
2296 dump_loop_node(F, loop);
2298 /* Dump the loop elements. */
2300 for(i = 0; i < get_loop_n_elements(loop); i++) {
2301 le = get_loop_element(loop, i);
2303 if (get_kind(son) == k_ir_loop) {
2305 /* We are a loop son -> Recurse */
2307 if(loop_node_started) { /* Close the "firm-nodes" node first if we started one. */
2308 fprintf(F, "\" }\n");
2309 fprintf (F, "edge: {sourcename: \"");
2311 fprintf (F, "\" targetname: \"");
2313 fprintf (F, "-%d-nodes\" label:\"%d...%d\"}\n", first, first, i-1);
2314 loop_node_started = 0;
2316 dump_loop_son_edge(F, loop, son_number++);
2317 dump_loops_standalone(F, son);
2318 } else if (get_kind(son) == k_ir_node) {
2319 /* We are a loop node -> Collect firm nodes */
2321 ir_node *n = le.node;
2324 if (!loop_node_started) {
2325 /* Start a new node which contains all firm nodes of the current loop */
2326 fprintf (F, "node: { title: \"");
2328 fprintf (F, "-%d-nodes\" color: lightyellow label: \"", i);
2329 loop_node_started = 1;
2335 bad |= dump_node_label(F, n);
2336 /* Causes indeterministic output: if (is_Block(n)) fprintf (F, "\t ->%d", (int)get_irn_link(n)); */
2337 if (has_backedges(n)) fprintf(F, "\t loop head!");
2338 } else { /* for callgraph loop tree */
2340 assert(get_kind(son) == k_ir_graph);
2342 /* We are a loop node -> Collect firm graphs */
2343 n = (ir_graph *)le.node;
2344 if (!loop_node_started) {
2345 /* Start a new node which contains all firm nodes of the current loop */
2346 fprintf (F, "node: { title: \"");
2348 fprintf (F, "-%d-nodes\" color: lightyellow label: \"", i);
2349 loop_node_started = 1;
2354 fprintf (F, " %s", get_irg_dump_name(n));
2355 /* fprintf (F, " %s (depth %d)", get_irg_dump_name(n), n->callgraph_weighted_loop_depth); */
2359 if (loop_node_started) {
2360 fprintf(F, "\" }\n");
2361 fprintf (F, "edge: {sourcename: \"");
2363 fprintf (F, "\" targetname: \"");
2365 fprintf (F, "-%d-nodes\" label:\"%d...%d\"}\n", first, first, i-1);
2366 loop_node_started = 0;
2370 void dump_loop_tree(ir_graph *irg, const char *suffix)
2373 ir_graph *rem = current_ir_graph;
2374 int el_rem = edge_label;
2377 /* if a filter is set, dump only the irg's that match the filter */
2378 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg)))) return;
2380 current_ir_graph = irg;
2382 f = vcg_open(irg, suffix, "-looptree");
2383 dump_vcg_header(f, get_irg_dump_name(irg), "top_to_bottom");
2385 if (get_irg_loop(irg)) dump_loops_standalone(f, get_irg_loop(irg));
2389 edge_label = el_rem;
2390 current_ir_graph = rem;
2393 void dump_callgraph_loop_tree(const char *suffix) {
2395 F = vcg_open_name("Callgraph_looptree", suffix);
2396 dump_vcg_header(F, "callgraph looptree", "top_to_bottom");
2397 dump_loops_standalone(F, irp->outermost_cg_loop);
2402 /*-----------------------------------------------------------------------------*/
2403 /* Dumps the firm nodes in the loop tree to a graph along with the loop nodes. */
2404 /*-----------------------------------------------------------------------------*/
2406 void collect_nodeloop(FILE *F, ir_loop *loop, eset *loopnodes) {
2407 int i, son_number = 0, node_number = 0;
2409 if (dump_loop_information_flag) dump_loop_node(F, loop);
2411 for (i = 0; i < get_loop_n_elements(loop); i++) {
2412 loop_element le = get_loop_element(loop, i);
2413 if (*(le.kind) == k_ir_loop) {
2414 if (dump_loop_information_flag) dump_loop_son_edge(F, loop, son_number++);
2416 collect_nodeloop(F, le.son, loopnodes);
2418 if (dump_loop_information_flag) dump_loop_node_edge(F, loop, node_number++);
2419 eset_insert(loopnodes, le.node);
2424 void collect_nodeloop_external_nodes(ir_loop *loop, eset *loopnodes, eset *extnodes) {
2427 for(i = 0; i < get_loop_n_elements(loop); i++) {
2428 loop_element le = get_loop_element(loop, i);
2429 if (*(le.kind) == k_ir_loop) {
2431 collect_nodeloop_external_nodes(le.son, loopnodes, extnodes);
2433 if (is_Block(le.node)) start = 0; else start = -1;
2434 for (j = start; j < get_irn_arity(le.node); j++) {
2435 ir_node *pred = get_irn_n(le.node, j);
2436 if (!eset_contains(loopnodes, pred)) {
2437 eset_insert(extnodes, pred);
2438 if (!is_Block(pred)) {
2439 pred = get_nodes_block(pred);
2440 if (!eset_contains(loopnodes, pred)) eset_insert(extnodes, pred);
2448 void dump_loop(ir_loop *l, const char *suffix) {
2451 eset *loopnodes = eset_create();
2452 eset *extnodes = eset_create();
2455 snprintf(name, sizeof(name), "loop_%d", get_loop_loop_nr(l));
2456 F = vcg_open_name (name, suffix);
2457 dump_vcg_header(F, name, NULL);
2459 /* collect all nodes to dump */
2460 collect_nodeloop(F, l, loopnodes);
2461 collect_nodeloop_external_nodes(l, loopnodes, extnodes);
2463 /* build block lists */
2464 for (n = eset_first(loopnodes); n != NULL; n = eset_next(loopnodes))
2465 set_irn_link(n, NULL);
2466 for (n = eset_first(extnodes); n != NULL; n = eset_next(extnodes))
2467 set_irn_link(n, NULL);
2468 for (n = eset_first(loopnodes); n != NULL; n = eset_next(loopnodes))
2470 b = get_nodes_block(n);
2471 set_irn_link(n, get_irn_link(b));
2474 for (n = eset_first(extnodes); n != NULL; n = eset_next(extnodes))
2476 b = get_nodes_block(n);
2477 set_irn_link(n, get_irn_link(b));
2481 for (b = eset_first(loopnodes); b != NULL; b = eset_next(loopnodes))
2483 fprintf(F, "graph: { title: \"");
2485 fprintf(F, "\" label: \"");
2486 dump_node_opcode(F, b);
2487 fprintf (F, " %ld", get_irn_node_nr(b));
2488 fprintf(F, "\" status:clustered color:yellow\n");
2490 /* dump the blocks edges */
2491 dump_ir_data_edges(F, b);
2493 /* dump the nodes that go into the block */
2494 for (n = get_irn_link(b); n; n = get_irn_link(n)) {
2495 if (eset_contains(extnodes, n)) overrule_nodecolor = "lightblue";
2497 overrule_nodecolor = NULL;
2498 if (!eset_contains(extnodes, n)) dump_ir_data_edges(F, n);
2501 /* Close the vcg information for the block */
2503 dump_const_node_local(F, b);
2506 for (b = eset_first(extnodes); b != NULL; b = eset_next(extnodes))
2508 fprintf(F, "graph: { title: \"");
2510 fprintf(F, "\" label: \"");
2511 dump_node_opcode(F, b);
2512 fprintf (F, " %ld", get_irn_node_nr(b));
2513 fprintf(F, "\" status:clustered color:lightblue\n");
2515 /* dump the nodes that go into the block */
2516 for (n = get_irn_link(b); n; n = get_irn_link(n)) {
2517 if (!eset_contains(loopnodes, n)) overrule_nodecolor = "lightblue";
2519 overrule_nodecolor = NULL;
2520 if (eset_contains(loopnodes, n)) dump_ir_data_edges(F, n);
2523 /* Close the vcg information for the block */
2525 dump_const_node_local(F, b);
2529 eset_destroy(loopnodes);
2530 eset_destroy(extnodes);