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 #include "execution_frequency.h"
676 #include "callgraph.h"
678 void dump_node_ana_vals(FILE *F, ir_node *n) {
680 fprintf(F, " %lf*(%2.0lf + %2.0lf) = %2.0lf ",
681 get_irn_exec_freq(n),
682 get_irg_method_execution_frequency(get_irn_irg(n)),
683 pow(5, get_irg_recursion_depth(get_irn_irg(n))),
684 get_irn_exec_freq(n) * (get_irg_method_execution_frequency(get_irn_irg(n)) + pow(5, get_irg_recursion_depth(get_irn_irg(n))))
689 /* Dumps a node label without the enclosing ". */
690 int dump_node_label(FILE *F, ir_node *n) {
693 bad |= dump_node_opcode(F, n);
694 bad |= dump_node_mode(F, n);
696 bad |= dump_node_typeinfo(F, n);
697 bad |= dump_node_nodeattr(F, n);
698 fprintf(F, "%ld", get_irn_node_nr(n));
705 * Dumps the attributes of a node n into the file F.
706 * Currently this is only the color of a node.
708 static void dump_node_vcgattr(FILE *F, ir_node *node, ir_node *local, int bad)
713 fprintf(F, "color: red");
717 if (dump_node_vcgattr_hook)
718 if (dump_node_vcgattr_hook(F, node, local))
721 n = local ? local : node;
723 switch (get_irn_opcode(n)) {
730 fprintf (F, "color: blue");
733 if (is_Block_dead(n))
734 fprintf (F, "color: lightred");
736 fprintf (F, "color: lightyellow");
739 fprintf (F, "color: green");
745 fprintf (F, "color: yellow");
748 PRINT_DEFAULT_NODE_ATTR;
751 if (overrule_nodecolor) fprintf(F, " color: %s", overrule_nodecolor);
756 * Dump the node information of a node n to a file F.
758 static INLINE int dump_node_info(FILE *F, ir_node *n)
760 fprintf (F, " info1: \"");
761 bad = dump_irnode_to_file(F, n);
767 * checks wheater a node is "constant-like", ie can be treated "block-less"
770 bool is_constlike_node(ir_node *n) {
771 ir_op *op = get_irn_op(n);
772 return (op == op_Const || op == op_Bad || op == op_NoMem || op == op_SymConst || op == op_Unknown);
776 /** outputs the predecessors of n, that are constants, local. I.e.,
777 generates a copy of the constant predecessors for each node called with. */
778 static void dump_const_node_local(FILE *F, ir_node *n) {
780 if (!get_opt_dump_const_local()) return;
782 /* Use visited flag to avoid outputting nodes twice.
783 initialize it first. */
784 for (i = 0; i < get_irn_arity(n); i++) {
785 ir_node *con = get_irn_n(n, i);
786 if (is_constlike_node(con)) {
787 set_irn_visited(con, get_irg_visited(current_ir_graph) - 1);
791 for (i = 0; i < get_irn_arity(n); i++) {
792 ir_node *con = get_irn_n(n, i);
793 if (is_constlike_node(con) && irn_not_visited(con)) {
796 mark_irn_visited(con);
797 /* Generate a new name for the node by appending the names of
799 fprintf(F, "node: {title: "); PRINT_CONSTID(n, con);
800 fprintf(F, " label: \"");
801 bad |= dump_node_label(F, con);
803 bad |= dump_node_info(F, con);
804 dump_node_vcgattr(F, n, con, bad);
810 /** If the block of an edge is a const_like node, dump it local with an edge */
811 static void dump_const_block_local(FILE *F, ir_node *n) {
814 if (!get_opt_dump_const_local()) return;
816 blk = get_nodes_block(n);
817 if (is_constlike_node(blk)) {
820 /* Generate a new name for the node by appending the names of
822 fprintf(F, "node: {title: \""); PRINT_CONSTBLKID(n, blk);
823 fprintf(F, "\" label: \"");
824 bad |= dump_node_label(F, blk);
826 bad |= dump_node_info(F, blk);
827 dump_node_vcgattr(F, n, blk, bad);
830 fprintf (F, "edge: { sourcename: \"");
832 fprintf (F, "\" targetname: \""); PRINT_CONSTBLKID(n,blk);
833 fprintf (F, "\" " BLOCK_EDGE_ATTR "}\n");
838 * prints the error message of a node to a file F as info2.
840 static void INLINE print_node_error(FILE *F, const char *err_msg)
845 fprintf (F, " info2: \"%s\"", err_msg);
851 static void dump_node(FILE *F, ir_node *n)
856 if (get_opt_dump_const_local() && is_constlike_node(n))
860 fprintf(F, "node: {title: \""); PRINT_NODEID(n); fprintf(F, "\" label: \"");
862 bad = ! irn_vrfy_irg_dump(n, current_ir_graph, &p);
863 bad |= dump_node_label(F, n);
864 dump_node_ana_vals(F, n);
865 //dump_node_ana_info(F, n);
867 bad |= dump_node_info(F, n);
868 print_node_error(F, p);
869 dump_node_vcgattr(F, n, NULL, bad);
871 dump_const_node_local(F, n);
873 dump_irn_chi_term(F, n);
874 dump_irn_state(F, n);
878 /** dump the edge to the block this node belongs to */
880 dump_ir_block_edge(FILE *F, ir_node *n) {
881 if (get_opt_dump_const_local() && is_constlike_node(n)) return;
882 if (is_no_Block(n)) {
883 ir_node *block = get_nodes_block(n);
885 if (get_opt_dump_const_local() && is_constlike_node(block)) {
886 dump_const_block_local(F, n);
889 fprintf (F, "edge: { sourcename: \"");
891 fprintf (F, "\" targetname: ");
892 fprintf(F, "\""); PRINT_NODEID(block); fprintf(F, "\"");
893 fprintf (F, " " BLOCK_EDGE_ATTR "}\n");
899 print_data_edge_vcgattr(FILE *F, ir_node *from, int to) {
900 if (get_nodes_block(from) == get_nodes_block(get_irn_n(from, to)))
901 fprintf (F, INTRA_DATA_EDGE_ATTR);
903 fprintf (F, INTER_DATA_EDGE_ATTR);
907 print_mem_edge_vcgattr(FILE *F, ir_node *from, int to) {
908 if (get_nodes_block(from) == get_nodes_block(get_irn_n(from, to)))
909 fprintf (F, INTRA_MEM_EDGE_ATTR);
911 fprintf (F, INTER_MEM_EDGE_ATTR);
915 print_edge_vcgattr(FILE *F, ir_node *from, int to) {
918 if (dump_backedge_information_flag && is_backedge(from, to))
919 fprintf (F, BACK_EDGE_ATTR);
921 switch (get_irn_opcode(from)) {
923 fprintf (F, CF_EDGE_ATTR);
925 case iro_Start: break;
928 if (get_irn_mode(get_End_keepalive(from, to)) == mode_BB)
929 fprintf (F, CF_EDGE_ATTR);
930 if (get_irn_mode(get_End_keepalive(from, to)) == mode_X)
931 fprintf (F, INTER_MEM_EDGE_ATTR);
939 print_data_edge_vcgattr(F, from, to);
944 print_mem_edge_vcgattr(F, from, to);
946 print_data_edge_vcgattr(F, from, to);
950 print_data_edge_vcgattr(F, from, to);
955 print_mem_edge_vcgattr(F, from, to);
957 print_data_edge_vcgattr(F, from, to);
964 print_data_edge_vcgattr(F, from, to);
971 print_mem_edge_vcgattr(F, from, to);
973 print_data_edge_vcgattr(F, from, to);
985 print_data_edge_vcgattr(F, from, to);
988 if (get_irn_modecode(from) == irm_M)
989 fprintf (F, INTER_MEM_EDGE_ATTR);
991 print_data_edge_vcgattr(F, from, to);
998 print_mem_edge_vcgattr(F, from, to);
1000 print_data_edge_vcgattr(F, from, to);
1003 print_mem_edge_vcgattr(F, from, to);
1005 case iro_Tuple: break;
1008 switch (get_irn_modecode(from)) {
1010 fprintf (F, CF_EDGE_ATTR);
1013 fprintf (F, INTER_MEM_EDGE_ATTR);
1016 print_data_edge_vcgattr(F, from, to);
1020 case iro_Bad: break;
1021 case iro_Unknown: break;
1023 switch (get_irn_modecode(from)) {
1025 fprintf (F, INTRA_MEM_EDGE_ATTR);
1028 fprintf (F, CF_EDGE_ATTR);
1031 print_data_edge_vcgattr(F, from, to);
1039 /* dump edges to our inputs */
1041 dump_ir_data_edges(FILE *F, ir_node *n) {
1043 unsigned long visited = get_irn_visited(n);
1045 if ((get_irn_op(n) == op_End) && (!dump_keepalive))
1048 for (i = 0; i < get_irn_arity(n); i++) {
1049 ir_node * pred = get_irn_n(n, i);
1052 if ((get_interprocedural_view() && get_irn_visited(pred) < visited))
1053 continue; /* pred not dumped */
1055 if (dump_backedge_information_flag && is_backedge(n, i))
1056 fprintf (F, "backedge: {sourcename: \"");
1058 fprintf (F, "edge: {sourcename: \"");
1060 fprintf (F, "\" targetname: ");
1061 if ((get_opt_dump_const_local()) && is_constlike_node(pred)) {
1062 PRINT_CONSTID(n, pred);
1064 fprintf(F, "\""); PRINT_NODEID(pred); fprintf(F, "\"");
1066 fprintf (F, " label: \"%d\" ", i);
1067 print_edge_vcgattr(F, n, i);
1072 /** Dumps a node and its edges but not the block edge
1075 dump_node_wo_blockedge (ir_node *n, void *env) {
1078 dump_ir_data_edges(F, n);
1081 /** Dumps a node and its edges.
1084 dump_whole_node (ir_node *n, void *env) {
1086 dump_node_wo_blockedge(n, env);
1087 if (!node_floats(n)) dump_ir_block_edge(F, n);
1091 dump_const_node(ir_node *n, void *env) {
1092 if (is_Block(n)) return;
1093 dump_node_wo_blockedge(n, env);
1096 /***********************************************************************/
1097 /* the following routines dump the nodes/irgs bracketed to graphs. */
1098 /***********************************************************************/
1100 /** Dumps a constant expression as entity initializer, array bound ...
1102 static void dump_const_expression(FILE *F, ir_node *value) {
1103 ir_graph *rem = current_ir_graph;
1104 int rem_dump_const_local = dump_const_local;
1105 dump_const_local = 0;
1106 current_ir_graph = get_const_code_irg();
1107 irg_walk(value, dump_const_node, NULL, F);
1108 /* Decrease visited flag so that we walk with the same flag for the next
1109 expresssion. This guarantees that we don't dump the same node twice,
1110 as for const expressions cse is performed to save memory. */
1111 set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph) -1);
1112 current_ir_graph = rem;
1113 dump_const_local = rem_dump_const_local;
1116 /** Dump a block as graph containing its nodes.
1118 * Expects to find nodes belonging to the block as list in its
1120 * Dumps the edges of all nodes including itself. */
1122 dump_whole_block(FILE *F, ir_node *block) {
1124 assert(is_Block(block));
1126 fprintf(F, "graph: { title: \"");
1127 PRINT_NODEID(block);
1128 fprintf(F, "\" label: \"");
1129 dump_node_label(F, block);
1131 if (get_opt_dump_abstvals())
1132 fprintf (F, " seqno: %d", (int)get_Block_seqno(block));
1134 fprintf(F, "\" status:clustered color:%s \n",
1135 get_Block_matured(block) ? "yellow" : "red");
1137 /* dump the blocks edges */
1138 dump_ir_data_edges(F, block);
1140 /* dump the nodes that go into the block */
1141 for (node = ird_get_irn_link(block); node; node = ird_get_irn_link(node)) {
1143 dump_ir_data_edges(F, node);
1146 /* Close the vcg information for the block */
1148 dump_const_node_local(F, block);
1150 dump_irn_chi_term(F, block);
1155 /** dumps a graph block-wise. Expects all blockless nodes in arr in irgs link.
1156 * The outermost nodes: blocks and nodes not op_pin_state_pinned, Bad, Unknown. */
1158 dump_block_graph(FILE *F, ir_graph *irg) {
1160 ir_graph *rem = current_ir_graph;
1161 ir_node **arr = ird_get_irg_link(irg);
1162 current_ir_graph = irg;
1164 for (i = ARR_LEN(arr) - 1; i >= 0; --i) {
1165 ir_node * node = arr[i];
1166 if (is_Block(node)) {
1167 /* Dumps the block and all the nodes in the block, which are to
1168 be found in Block->link. */
1169 dump_whole_block(F, node);
1171 /* Nodes that are not in a Block. */
1173 if (is_Bad(get_nodes_block(node)) && !node_floats(node)) {
1174 dump_const_block_local(F, node);
1176 dump_ir_data_edges(F, node);
1180 if (dump_loop_information_flag && (get_irg_loopinfo_state(irg) & loopinfo_valid))
1181 dump_loop_nodes_into_graph(F, irg);
1183 current_ir_graph = rem;
1186 /** Dumps an irg as a graph.
1187 * If interprocedural view edges can point to nodes out of this graph.
1189 static void dump_graph_from_list(FILE *F, ir_graph *irg) {
1191 fprintf(F, "graph: { title: \"");
1193 fprintf(F, "\" label: \"%s\" status:clustered color:white \n",
1194 get_ent_dump_name(get_irg_entity(irg)));
1196 dump_block_graph(F, irg);
1198 /* Close the vcg information for the irg */
1199 fprintf(F, "}\n\n");
1202 /*******************************************************************/
1203 /* Basic type and entity nodes and edges. */
1204 /*******************************************************************/
1206 /** dumps the edges between nodes and their type or entity attributes. */
1207 static void dump_node2type_edges(ir_node *n, void *env)
1212 switch (get_irn_opcode(n)) {
1214 /* @@@ some consts have an entity */
1217 if ( (get_SymConst_kind(n) ==symconst_type_tag)
1218 || (get_SymConst_kind(n) ==symconst_size))
1220 print_node_type_edge(F,n,get_SymConst_type(n),NODE2TYPE_EDGE_ATTR);
1224 print_node_ent_edge(F,n,get_Sel_entity(n),NODE2TYPE_EDGE_ATTR);
1227 print_node_type_edge(F,n,get_Call_type(n),NODE2TYPE_EDGE_ATTR);
1230 print_node_type_edge(F,n,get_Alloc_type(n),NODE2TYPE_EDGE_ATTR);
1233 print_node_type_edge(F,n,get_Free_type(n),NODE2TYPE_EDGE_ATTR);
1236 print_node_type_edge(F,n,get_Cast_type(n),NODE2TYPE_EDGE_ATTR);
1244 static int print_type_info(FILE *F, type *tp) {
1247 if (get_type_state(tp) == layout_undefined) {
1248 fprintf(F, "state: layout_undefined\n");
1250 fprintf(F, "state: layout_fixed,\n");
1252 if (get_type_mode(tp))
1253 fprintf(F, "mode: %s,\n", get_mode_name_ex(get_type_mode(tp), &bad));
1254 fprintf(F, "size: %db,\n", get_type_size_bits(tp));
1259 static void print_typespecific_info(FILE *F, type *tp) {
1260 switch (get_type_tpop_code(tp)) {
1263 fprintf(F, "peculiarity: %s\n", get_peculiarity_string(get_class_peculiarity(tp)));
1270 fprintf(F, "variadicity: %s\n", get_variadicity_name(get_method_variadicity(tp)));
1271 fprintf(F, "params: %d\n", get_method_n_params(tp));
1272 fprintf(F, "results: %d\n", get_method_n_ress(tp));
1280 case tpo_enumeration:
1294 static void print_typespecific_vcgattr(FILE *F, type *tp) {
1295 switch (get_type_tpop_code(tp)) {
1298 if (peculiarity_existent == get_class_peculiarity(tp))
1299 fprintf (F, " " TYPE_CLASS_NODE_ATTR);
1301 fprintf (F, " " TYPE_DESCRIPTION_NODE_ATTR);
1305 fprintf (F, " " TYPE_METH_NODE_ATTR);
1316 case tpo_enumeration:
1330 /* Why not dump_type_node as the others? */
1331 static int print_type_node(FILE *F, type *tp)
1335 fprintf (F, "node: {title: ");
1337 fprintf (F, " label: \"%s %s\"", get_type_tpop_name(tp), get_type_name_ex(tp, &bad));
1338 fprintf (F, " info1: \"");
1340 bad |= print_type_info(F, tp);
1341 print_typespecific_info(F, tp);
1343 dump_type_to_file(F, tp, dump_verbosity_max);
1346 print_typespecific_vcgattr(F, tp);
1352 int dump_type_node(FILE *F, type *tp) {
1353 return print_type_node(F, tp);
1357 #define X(a) case a: fprintf(F, #a); break
1358 void dump_entity_node(FILE *F, entity *ent, int color)
1360 fprintf (F, "node: {title: \"");
1361 PRINT_ENTID(ent); fprintf(F, "\"");
1362 fprintf (F, DEFAULT_TYPE_ATTRIBUTE);
1363 fprintf (F, "label: ");
1364 fprintf (F, "\"ent %s\" ", get_ent_dump_name(ent));
1366 fprintf(F, "color: %d", color);
1368 fprintf (F, ENTITY_NODE_ATTR);
1369 fprintf (F, "\n info1: \"");
1371 dump_entity_to_file(F, ent, dump_verbosity_entattrs | dump_verbosity_entconsts);
1373 fprintf(F, "\"\n}\n");
1377 static void dump_enum_item(FILE *F, type *tp, int pos)
1380 ident *id = get_enumeration_nameid(tp, pos);
1381 tarval *tv = get_enumeration_enum(tp, pos);
1383 tarval_snprintf(buf, sizeof(buf), tv);
1384 fprintf (F, "node: {title: \"");
1385 PRINT_ITEMID(tp, pos); fprintf(F, "\"");
1386 fprintf (F, DEFAULT_ENUM_ITEM_ATTRIBUTE);
1387 fprintf (F, "label: ");
1388 fprintf (F, "\"enum item %s\" " ENUM_ITEM_NODE_ATTR, get_id_str(id));
1389 fprintf (F, "\n info1: \"value: %s\"}\n", buf);
1392 /* dumps a type or entity and it's edges. */
1394 dump_type_info(type_or_ent *tore, void *env) {
1396 int i = 0; /* to shutup gcc */
1398 /* dump this type or entity */
1400 switch (get_kind(tore)) {
1403 entity *ent = (entity *)tore;
1406 dump_entity_node(F, ent, 0);
1408 /* skip this to reduce graph. Member edge of type is parallel to this edge. *
1409 fprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
1410 ENT_OWN_EDGE_ATTR "}\n", ent, get_entity_owner(ent));*/
1411 print_ent_type_edge(F,ent, get_entity_type(ent), ENT_TYPE_EDGE_ATTR);
1412 if (is_Class_type(get_entity_owner(ent))) {
1413 for(i = 0; i < get_entity_n_overwrites(ent); i++)
1414 print_ent_ent_edge(F,ent, get_entity_overwrites(ent, i), 0, ENT_OVERWRITES_EDGE_ATTR);
1416 /* attached subgraphs */
1417 if (const_entities && (get_entity_variability(ent) != variability_uninitialized)) {
1418 if (is_atomic_entity(ent)) {
1419 value = get_atomic_ent_value(ent);
1421 print_ent_node_edge(F, ent, value, ENT_VALUE_EDGE_ATTR, i);
1422 /* DDMN(value); $$$ */
1423 dump_const_expression(F, value);
1426 if (is_compound_entity(ent)) {
1427 for (i = 0; i < get_compound_ent_n_values(ent); i++) {
1428 value = get_compound_ent_value(ent, i);
1430 print_ent_node_edge(F, ent, value, ENT_VALUE_EDGE_ATTR, i);
1431 dump_const_expression(F, value);
1432 print_ent_ent_edge(F, ent, get_compound_ent_value_member(ent, i), 0, ENT_CORR_EDGE_ATTR, i);
1434 fprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
1435 ENT_CORR_EDGE_ATTR "}\n", GET_ENTID(ent),
1436 get_compound_ent_value_member(ent, i), i);
1445 type *tp = (type *)tore;
1446 print_type_node(F, tp);
1447 /* and now the edges */
1448 switch (get_type_tpop_code(tp)) {
1451 for (i=0; i < get_class_n_supertypes(tp); i++)
1452 print_type_type_edge(F, tp,get_class_supertype(tp, i),TYPE_SUPER_EDGE_ATTR);
1453 for (i=0; i < get_class_n_members(tp); i++)
1454 print_type_ent_edge(F,tp,get_class_member(tp, i),TYPE_MEMBER_EDGE_ATTR);
1458 for (i=0; i < get_struct_n_members(tp); i++)
1459 print_type_ent_edge(F,tp,get_struct_member(tp, i),TYPE_MEMBER_EDGE_ATTR);
1463 for (i = 0; i < get_method_n_params(tp); i++)
1464 print_type_type_edge(F,tp,get_method_param_type(tp, i),METH_PAR_EDGE_ATTR,i);
1465 for (i = 0; i < get_method_n_ress(tp); i++)
1466 print_type_type_edge(F,tp,get_method_res_type(tp, i),METH_RES_EDGE_ATTR,i);
1470 for (i = 0; i < get_union_n_members(tp); i++)
1471 print_type_ent_edge(F,tp,get_union_member(tp, i),UNION_EDGE_ATTR);
1475 print_type_type_edge(F,tp,get_array_element_type(tp),ARR_ELT_TYPE_EDGE_ATTR);
1476 print_type_ent_edge(F,tp,get_array_element_entity(tp),ARR_ENT_EDGE_ATTR);
1477 for (i = 0; i < get_array_n_dimensions(tp); i++) {
1478 ir_node *upper = get_array_upper_bound(tp, i);
1479 ir_node *lower = get_array_lower_bound(tp, i);
1480 print_node_type_edge(F, upper, tp, "label: \"upper %d\"", get_array_order(tp, i));
1481 print_node_type_edge(F, lower, tp, "label: \"lower %d\"", get_array_order(tp, i));
1482 dump_const_expression(F, upper);
1483 dump_const_expression(F, lower);
1487 case tpo_enumeration:
1489 for (i = 0; i < get_enumeration_n_enums(tp); ++i) {
1490 dump_enum_item(F, tp, i);
1491 print_enum_item_edge(F, tp, i, "label: \"item %d\"", i);
1496 print_type_type_edge(F,tp,get_pointer_points_to_type(tp), PTR_PTS_TO_EDGE_ATTR);
1504 break; /* case k_type */
1507 printf(" *** irdump, dump_type_info(l.%i), faulty type.\n", __LINE__);
1509 } /* switch kind_or_entity */
1512 typedef struct _h_env {
1517 /** For dumping class hierarchies.
1518 * Dumps a class type node and a superclass edge.
1519 * If env->dump_ent dumps entities of classes and overwrites edges.
1522 dump_class_hierarchy_node (type_or_ent *tore, void *ctx) {
1525 int i = 0; /* to shutup gcc */
1527 /* dump this type or entity */
1528 switch (get_kind(tore)) {
1530 entity *ent = (entity *)tore;
1531 if (get_entity_owner(ent) == get_glob_type()) break;
1532 if (!is_Method_type(get_entity_type(ent))) break; /* GL */
1533 if (env->dump_ent && is_Class_type(get_entity_owner(ent))) {
1535 dump_entity_node(F, ent, 0);
1537 print_type_ent_edge(F,get_entity_owner(ent),ent,TYPE_MEMBER_EDGE_ATTR);
1538 for(i = 0; i < get_entity_n_overwrites(ent); i++)
1539 print_ent_ent_edge(F, get_entity_overwrites(ent, i), ent, 0, ENT_OVERWRITES_EDGE_ATTR);
1541 } break; /* case k_entity */
1544 type *tp = (type *)tore;
1545 if (tp == get_glob_type()) break;
1546 switch (get_type_tpop_code(tp)) {
1548 print_type_node(F, tp);
1549 /* and now the edges */
1550 for (i=0; i < get_class_n_supertypes(tp); i++)
1552 print_type_type_edge(F,tp,get_class_supertype(tp, i),TYPE_SUPER_EDGE_ATTR);
1558 break; /* case k_type */
1561 printf(" *** irdump, dump_class_hierarchy_node(l.%i), faulty type.\n", __LINE__);
1563 } /* switch kind_or_entity */
1566 /*******************************************************************/
1567 /* dump analysis information that is expressed in graph terms. */
1568 /*******************************************************************/
1570 /* dump out edges */
1572 dump_out_edge(ir_node *n, void *env) {
1575 for (i = 0; i < get_irn_n_outs(n); i++) {
1576 assert(get_irn_out(n, i));
1577 fprintf (F, "edge: {sourcename: \"");
1579 fprintf (F, "\" targetname: \"");
1580 PRINT_NODEID(get_irn_out(n, i));
1581 fprintf (F, "\" color: red linestyle: dashed");
1587 dump_loop_label(FILE *F, ir_loop *loop) {
1588 fprintf (F, "loop %d, %d sons, %d nodes",
1589 get_loop_depth(loop), get_loop_n_sons(loop), get_loop_n_nodes(loop));
1592 static INLINE void dump_loop_info(FILE *F, ir_loop *loop) {
1593 fprintf (F, " info1: \"");
1594 fprintf (F, " loop nr: %d", get_loop_loop_nr(loop));
1595 #if DEBUG_libfirm /* GL @@@ debug analyses */
1596 fprintf (F, "\n The loop was analyzed %d times.", (int)get_loop_link(loop));
1602 dump_loop_node(FILE *F, ir_loop *loop) {
1603 fprintf (F, "node: {title: \"");
1605 fprintf (F, "\" label: \"");
1606 dump_loop_label(F, loop);
1608 dump_loop_info(F, loop);
1614 dump_loop_node_edge(FILE *F, ir_loop *loop, int i) {
1616 fprintf (F, "edge: {sourcename: \"");
1618 fprintf (F, "\" targetname: \"");
1619 PRINT_NODEID(get_loop_node(loop, i));
1620 fprintf (F, "\" color: green");
1625 dump_loop_son_edge(FILE *F, ir_loop *loop, int i) {
1627 fprintf (F, "edge: {sourcename: \"");
1629 fprintf (F, "\" targetname: \"");
1630 PRINT_LOOPID(get_loop_son(loop, i));
1631 fprintf (F, "\" color: darkgreen label: \"%d\"}\n",
1632 get_loop_element_pos(loop, get_loop_son(loop, i)));
1636 void dump_loops(FILE *F, ir_loop *loop) {
1638 /* dump this loop node */
1639 dump_loop_node(F, loop);
1641 /* dump edges to nodes in loop -- only if it is a real loop */
1642 if (get_loop_depth(loop) != 0) {
1643 for (i = 0; i < get_loop_n_nodes(loop); i++) {
1644 dump_loop_node_edge(F, loop, i);
1647 for (i = 0; i < get_loop_n_sons(loop); i++) {
1648 dump_loops(F, get_loop_son(loop, i));
1649 dump_loop_son_edge(F, loop, i);
1654 void dump_loop_nodes_into_graph(FILE *F, ir_graph *irg) {
1655 ir_graph *rem = current_ir_graph;
1656 current_ir_graph = irg;
1658 if (get_irg_loop(irg)) dump_loops(F, get_irg_loop(irg));
1660 current_ir_graph = rem;
1665 * dumps the VCG header
1667 INLINE void dump_vcg_header(FILE *F, const char *name, const char *orientation) {
1676 if (!orientation) orientation = "bottom_to_top";
1680 "graph: { title: \"ir graph of %s\"\n"
1681 "display_edge_labels: %s\n"
1682 "layoutalgorithm: mindepth\n"
1683 "manhattan_edges: yes\n"
1684 "port_sharing: no\n"
1686 "classname 1: \"intrablock Data\"\n"
1687 "classname 16: \"interblock Data\"\n"
1688 "classname 2: \"Block\"\n"
1689 "classname 13: \"Control Flow\"\n"
1690 "classname 18: \"Exception Control Flow for Interval Analysis\"\n"
1691 "classname 14: \"intrablock Memory\"\n"
1692 "classname 17: \"interblock Memory\"\n"
1693 "classname 15: \"Dominators\"\n"
1694 "classname 3: \"Entity type\"\n"
1695 "classname 4: \"Entity owner\"\n"
1696 "classname 5: \"Method Param\"\n"
1697 "classname 6: \"Method Res\"\n"
1698 "classname 7: \"Super\"\n"
1699 "classname 8: \"Union\"\n"
1700 "classname 9: \"Points-to\"\n"
1701 "classname 10: \"Array Element Type\"\n"
1702 "classname 11: \"Overwrites\"\n"
1703 "classname 12: \"Member\"\n"
1704 "infoname 1: \"Attribute\"\n"
1705 "infoname 2: \"Verification errors\"\n",
1706 name, label, orientation);
1708 /* don't use all, the range is too whith/black. */
1712 "colorentry 100: 0 0 0\n"
1713 "colorentry 101: 20 0 0\n"
1714 "colorentry 102: 40 0 0\n"
1715 "colorentry 103: 60 0 0\n"
1716 "colorentry 104: 80 0 0\n"
1717 "colorentry 105: 100 0 0\n"
1718 "colorentry 106: 120 0 0\n"
1719 "colorentry 107: 140 0 0\n"
1720 "colorentry 108: 150 0 0\n"
1721 "colorentry 109: 180 0 0\n"
1722 "colorentry 110: 200 0 0\n"
1723 "colorentry 111: 220 0 0\n"
1724 "colorentry 112: 240 0 0\n"
1725 "colorentry 113: 255 0 0\n"
1726 "colorentry 113: 255 20 20\n"
1727 "colorentry 114: 255 40 40\n"
1728 "colorentry 115: 255 60 60\n"
1729 "colorentry 116: 255 80 80\n"
1730 "colorentry 117: 255 100 100\n"
1731 "colorentry 118: 255 120 120\n"
1732 "colorentry 119: 255 140 140\n"
1733 "colorentry 120: 255 150 150\n"
1734 "colorentry 121: 255 180 180\n"
1735 "colorentry 122: 255 200 200\n"
1736 "colorentry 123: 255 220 220\n"
1737 "colorentry 124: 255 240 240\n"
1738 "colorentry 125: 255 250 250\n"
1741 fprintf (F, "\n"); /* a separator */
1747 * @param irg The graph to be dumped
1748 * @param suffix1 first filename suffix
1749 * @param suffix2 second filename suffix
1751 FILE *vcg_open (ir_graph *irg, const char * suffix1, const char *suffix2) {
1753 const char *nm = get_irg_dump_name(irg);
1754 int len = strlen(nm), i, j;
1755 char *fname; /* filename to put the vcg information in */
1757 if (!suffix1) suffix1 = "";
1758 if (!suffix2) suffix2 = "";
1760 /* open file for vcg graph */
1761 fname = malloc (len * 2 + strlen(suffix1) + strlen(suffix2) + 5);
1763 /* strncpy (fname, nm, len); */ /* copy the filename */
1765 for (i = 0; i < len; ++i) { /* replace '/' in the name: escape by @. */
1767 fname[j] = '@'; j++; fname[j] = '1'; j++;
1768 } else if (nm[i] == '@') {
1769 fname[j] = '@'; j++; fname[j] = '2'; j++;
1771 fname[j] = nm[i]; j++;
1775 strcat (fname, suffix1); /* append file suffix */
1776 strcat (fname, suffix2); /* append file suffix */
1777 strcat (fname, ".vcg"); /* append the .vcg suffix */
1779 /* vcg really expect only a <CR> at end of line, so
1780 * the "b"inary mode is what you mean (and even needed for Win32)
1782 F = fopen (fname, "wb"); /* open file for writing */
1784 panic("cannot open %s for writing (%m)", fname); /* not reached */
1794 * @param irg The graph to be dumped
1795 * @param suffix filename suffix
1797 FILE *vcg_open_name (const char *name, const char *suffix) {
1799 char *fname; /* filename to put the vcg information in */
1800 int i, j, len = strlen(name);
1802 if (!suffix) suffix = "";
1804 /** open file for vcg graph */
1805 fname = malloc (len * 2 + 5 + strlen(suffix));
1806 /* strcpy (fname, name);*/ /* copy the filename */
1808 for (i = 0; i < len; ++i) { /* replace '/' in the name: escape by @. */
1809 if (name[i] == '/') {
1810 fname[j] = '@'; j++; fname[j] = '1'; j++;
1811 } else if (name[i] == '@') {
1812 fname[j] = '@'; j++; fname[j] = '2'; j++;
1814 fname[j] = name[i]; j++;
1818 strcat (fname, suffix);
1819 strcat (fname, ".vcg"); /* append the .vcg suffix */
1821 /* vcg really expect only a <CR> at end of line, so
1822 * the "b"inary mode is what you mean (and even needed for Win32)
1824 F = fopen (fname, "wb"); /* open file for writing */
1826 panic ("cannot open %s for writing (%m)", fname); /* not reached */
1834 * Dumps the vcg file footer
1836 static INLINE void dump_vcg_footer (FILE *F) {
1841 * close the vcg file
1843 void vcg_close (FILE *F) {
1844 dump_vcg_footer(F); /* print footer */
1845 fclose (F); /* close vcg file */
1848 /************************************************************************/
1849 /************************************************************************/
1850 /* Routines that dump all or parts of the firm representation to a file */
1851 /************************************************************************/
1852 /************************************************************************/
1854 /************************************************************************/
1855 /* Dump ir graphs, different formats and additional information. */
1856 /************************************************************************/
1858 /** Routine to dump a graph, blocks as conventional nodes. */
1860 dump_ir_graph (ir_graph *irg, const char *suffix )
1865 rem = current_ir_graph;
1867 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg)))) return;
1869 current_ir_graph = irg;
1870 if (get_interprocedural_view()) suffix1 = "-pure-ip";
1871 else suffix1 = "-pure";
1872 f = vcg_open(irg, suffix, suffix1);
1873 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1875 /* walk over the graph */
1876 /* dump_whole_node must be called in post visiting predecessors */
1877 irg_walk(get_irg_end(irg), NULL, dump_whole_node, f);
1879 /* dump the out edges in a separate walk */
1880 if ((dump_out_edge_flag) && (get_irg_outs_state(irg) != outs_none)) {
1881 irg_out_walk(get_irg_start(irg), dump_out_edge, NULL, f);
1886 current_ir_graph = rem;
1891 dump_ir_block_graph (ir_graph *irg, const char *suffix)
1897 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg))))
1900 if (get_interprocedural_view()) suffix1 = "-ip";
1902 f = vcg_open(irg, suffix, suffix1);
1903 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1905 construct_block_lists(irg);
1907 for (i = 0; i < get_irp_n_irgs(); i++) {
1908 ir_node **arr = ird_get_irg_link(get_irp_irg(i));
1910 dump_graph_from_list(f, get_irp_irg(i));
1918 /** dumps a graph with type information */
1920 dump_ir_graph_w_types (ir_graph *irg, const char *suffix)
1923 ir_graph *rem = current_ir_graph;
1926 /* if a filter is set, dump only the irg's that match the filter */
1927 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg))))
1930 current_ir_graph = irg;
1932 if (get_interprocedural_view()) suffix1 = "-pure-wtypes-ip";
1933 else suffix1 = "-pure-wtypes";
1934 f = vcg_open(irg,suffix, suffix1);
1935 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1937 /* dump common ir graph */
1938 irg_walk(get_irg_end(irg), NULL, dump_whole_node, f);
1939 /* dump type info */
1940 type_walk_irg(irg, dump_type_info, NULL, f);
1941 inc_irg_visited(get_const_code_irg());
1942 /* dump edges from graph to type info */
1943 irg_walk(get_irg_end(irg), dump_node2type_edges, NULL, f);
1946 current_ir_graph = rem;
1950 dump_ir_block_graph_w_types (ir_graph *irg, const char *suffix)
1955 ir_graph *rem = current_ir_graph;
1957 /* if a filter is set, dump only the irg's that match the filter */
1958 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg))))
1961 if (get_interprocedural_view()) suffix1 = "-wtypes-ip";
1962 else suffix1 = "-wtypes";
1963 f = vcg_open(irg, suffix, suffix1);
1964 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1966 /* dump common blocked ir graph */
1967 construct_block_lists(irg);
1969 for (i = 0; i < get_irp_n_irgs(); i++) {
1970 ir_node **arr = ird_get_irg_link(get_irp_irg(i));
1972 dump_graph_from_list(f, get_irp_irg(i));
1977 /* dump type info */
1978 current_ir_graph = irg;
1979 type_walk_irg(irg, dump_type_info, NULL, f);
1980 inc_irg_visited(get_const_code_irg());
1982 /* dump edges from graph to type info */
1983 irg_walk(get_irg_end(irg), dump_node2type_edges, NULL, f);
1985 current_ir_graph = rem;
1989 /*---------------------------------------------------------------------*/
1990 /* The following routines dump a control flow graph. */
1991 /*---------------------------------------------------------------------*/
1994 dump_block_to_cfg(ir_node *block, void *env) {
1999 if (is_Block(block)) {
2000 /* This is a block. Dump a node for the block. */
2001 fprintf (F, "node: {title: \""); PRINT_NODEID(block);
2002 fprintf (F, "\" label: \"");
2003 if (block == get_irg_start_block(get_irn_irg(block)))
2004 fprintf(F, "Start ");
2005 if (block == get_irg_end_block(get_irn_irg(block)))
2008 fprintf (F, "%s ", get_op_name(get_irn_op(block)));
2009 PRINT_NODEID(block);
2011 fprintf(F, "info1:\"");
2014 if (dump_dominator_information_flag) {
2015 fprintf(F, "dom depth %d\n", get_Block_dom_depth(block));
2016 fprintf(F, "tree pre num %d\n", get_Block_dom_tree_pre_num(block));
2017 fprintf(F, "max subtree pre num %d\n", get_Block_dom_max_subtree_pre_num(block));
2020 /* show arity and possible Bad predecessors of the block */
2021 fprintf(F, "arity: %d\n", get_Block_n_cfgpreds(block));
2022 for (fl = i = 0; i < get_Block_n_cfgpreds(block); ++i) {
2023 ir_node *pred = get_Block_cfgpred(block, i);
2026 fprintf(F, "Bad pred at pos: ");
2027 fprintf(F, "%d ", i);
2034 /* the generic version. */
2035 dump_irnode_to_file(F, block);
2037 /* Check whether we have bad predecessors to color the block. */
2038 for (i = 0; i < get_Block_n_cfgpreds(block); ++i)
2039 if ((fl = is_Bad(get_Block_cfgpred(block, i))))
2043 fprintf (F, "\""); /* closing quote of info */
2045 if ((block == get_irg_start_block(get_irn_irg(block))) ||
2046 (block == get_irg_end_block(get_irn_irg(block))) )
2047 fprintf(F, " color:blue ");
2049 fprintf(F, " color:yellow ");
2052 /* Dump the edges */
2053 for ( i = 0; i < get_Block_n_cfgpreds(block); i++)
2054 if (get_irn_op(skip_Proj(get_Block_cfgpred(block, i))) != op_Bad) {
2055 pred = get_nodes_block(skip_Proj(get_Block_cfgpred(block, i)));
2056 fprintf (F, "edge: { sourcename: \"");
2057 PRINT_NODEID(block);
2058 fprintf (F, "\" targetname: \"");
2060 fprintf (F, "\"}\n");
2063 /* Dump dominator edge */
2064 if (dump_dominator_information_flag && get_Block_idom(block)) {
2065 pred = get_Block_idom(block);
2066 fprintf (F, "edge: { sourcename: \"");
2067 PRINT_NODEID(block);
2068 fprintf (F, "\" targetname: \"");
2070 fprintf (F, "\" " DOMINATOR_EDGE_ATTR "}\n");
2076 dump_cfg (ir_graph *irg, const char *suffix)
2079 ir_graph *rem = current_ir_graph;
2080 int ddif = dump_dominator_information_flag;
2081 int ipv = get_interprocedural_view();
2083 /* if a filter is set, dump only the irg's that match the filter */
2084 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg))))
2087 current_ir_graph = irg;
2089 f = vcg_open(irg, suffix, "-cfg");
2090 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
2093 printf("Warning: dumping cfg not in interprocedural view!\n");
2094 set_interprocedural_view(false);
2097 if (get_irg_dom_state(irg) != dom_consistent)
2098 dump_dominator_information_flag = 0;
2100 /* walk over the blocks in the graph */
2101 irg_block_walk(get_irg_end(irg), dump_block_to_cfg, NULL, f);
2102 dump_node(f, get_irg_bad(irg));
2104 dump_dominator_information_flag = ddif;
2105 set_interprocedural_view(ipv);
2107 current_ir_graph = rem;
2111 static void descend_and_dump(FILE *F, ir_node *n, int depth, pset *mark_set) {
2112 if (pset_find_ptr(mark_set, n)) return;
2114 pset_insert_ptr(mark_set, n);
2117 int i, start = is_Block(n) ? 0 : -1;
2118 dump_whole_node(n, F);
2119 for (i = start; i < get_irn_arity(n); ++i)
2120 descend_and_dump(F, get_irn_n(n, i), depth-1, mark_set);
2123 /* Don't dump edges to nodes further out. These might be edges to
2124 nodes we already dumped, if there is a shorter path to these. */
2128 static int subgraph_counter = 0;
2129 void dump_subgraph (ir_node *root, int depth, const char *suffix) {
2132 pset *mark_set = pset_new_ptr(1);
2133 sprintf(buf, "-subg_%03d", subgraph_counter++);
2134 F = vcg_open(get_irn_irg(root), suffix, buf);
2135 dump_vcg_header(F, get_irg_dump_name(get_irn_irg(root)), NULL);
2136 descend_and_dump(F, root, depth, mark_set);
2142 static int weight_overall(int rec, int loop) {
2143 return 2*rec + loop;
2146 static int compute_color (int my, int max) {
2153 /* if small, scale to the full color range. */
2155 my = my * (n_colors/max);
2157 step = 1 + (max / n_colors);
2161 return base_color + n_colors - color;
2164 static int get_entity_color(entity *ent) {
2165 ir_graph *irg = get_entity_irg(ent);
2169 int rec_depth = get_irg_recursion_depth(irg);
2170 int loop_depth = get_irg_loop_depth(irg);
2171 int overall_depth = weight_overall(rec_depth, loop_depth);
2173 int max_rec_depth = irp->max_callgraph_recursion_depth;
2174 int max_loop_depth = irp->max_callgraph_loop_depth;
2175 int max_overall_depth = weight_overall(max_rec_depth, max_loop_depth);
2177 /* int my_rec_color = compute_color(rec_depth, max_rec_depth); */
2178 /* int my_loop_color = compute_color(loop_depth, max_loop_depth); */
2179 int my_overall_color = compute_color(overall_depth, max_overall_depth);;
2181 return my_overall_color;
2185 void dump_callgraph(const char *suffix) {
2187 int i, n_irgs = get_irp_n_irgs();
2188 int rem = edge_label;
2190 //ident *prefix = new_id_from_str("java/");
2192 F = vcg_open_name("Callgraph", suffix);
2193 dump_vcg_header(F, "Callgraph", NULL);
2195 for (i = 0; i < n_irgs; ++i) {
2196 ir_graph *irg = get_irp_irg(i);
2197 entity *ent = get_irg_entity(irg);
2198 int j, n_callees = get_irg_n_callees(irg);
2200 /* Do not dump runtime system. */
2201 //if (id_is_prefix(prefix, get_entity_ld_ident(ent))) continue;
2203 dump_entity_node(F, ent, get_entity_color(ent));
2204 for (j = 0; j < n_callees; ++j) {
2205 entity *c = get_irg_entity(get_irg_callee(irg, j));
2206 //if (id_is_prefix(prefix, get_entity_ld_ident(c))) continue;
2207 int be = is_irg_callee_backedge(irg, j);
2210 "label:\"recursion %d\" color: %d" :
2211 "label:\"calls %d\" color: %d";
2212 print_ent_ent_edge(F, ent, c, be, attr, get_irg_callee_loop_depth(irg, j), get_entity_color(ent));
2220 /* Dump all irgs in interprocedural view to a single file. */
2221 void dump_all_cg_block_graph(const char *suffix) {
2224 int rem_view = get_interprocedural_view();
2225 set_interprocedural_view(true);
2227 f = vcg_open_name("All_graphs", suffix);
2228 dump_vcg_header(f, "All_graphs", NULL);
2230 /* collect nodes in all irgs reachable in call graph*/
2231 for (i = 0; i < get_irp_n_irgs(); i++)
2232 ird_set_irg_link(get_irp_irg(i), NULL);
2234 cg_walk(clear_link, collect_node, NULL);
2236 /* dump all graphs */
2237 for (i = 0; i < get_irp_n_irgs(); i++) {
2238 current_ir_graph = get_irp_irg(i);
2239 assert(ird_get_irg_link(current_ir_graph));
2240 dump_graph_from_list(f, current_ir_graph);
2241 DEL_ARR_F(ird_get_irg_link(current_ir_graph));
2245 set_interprocedural_view(rem_view);
2248 /*---------------------------------------------------------------------*/
2249 /* the following routines dumps type information without any ir nodes. */
2250 /*---------------------------------------------------------------------*/
2253 dump_type_graph (ir_graph *irg, const char *suffix)
2257 rem = current_ir_graph;
2259 /* if a filter is set, dump only the irg's that match the filter */
2260 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg)))) return;
2262 current_ir_graph = irg;
2264 f = vcg_open(irg, suffix, "-type");
2265 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
2267 /* walk over the blocks in the graph */
2268 type_walk_irg(irg, dump_type_info, NULL, f);
2269 /* The walker for the const code can be called several times for the
2270 same (sub) expression. So that no nodes are dumped several times
2271 we decrease the visited flag of the corresponding graph after each
2272 walk. So now increase it finally. */
2273 inc_irg_visited(get_const_code_irg());
2276 current_ir_graph = rem;
2280 dump_all_types (const char *suffix)
2282 FILE *f = vcg_open_name("All_types", suffix);
2283 dump_vcg_header(f, "All_types", NULL);
2284 type_walk(dump_type_info, NULL, f);
2285 inc_irg_visited(get_const_code_irg());
2290 dump_class_hierarchy (bool entities, const char *suffix)
2292 FILE *f = vcg_open_name("class_hierarchy", suffix);
2296 dump_vcg_header(f, "class_hierarchy", NULL);
2301 type_walk(dump_class_hierarchy_node, NULL, &env);
2305 /*---------------------------------------------------------------------*/
2306 /* dumps all graphs with the graph-dumper passed. Possible dumpers: */
2308 /* dump_ir_block_graph */
2310 /* dump_type_graph */
2311 /* dump_ir_graph_w_types */
2312 /*---------------------------------------------------------------------*/
2314 void dump_all_ir_graphs(dump_graph_func *dmp_grph, const char *suffix) {
2315 int i, n_irgs = get_irp_n_irgs();
2316 for (i = 0; i < n_irgs; ++i) {
2317 dmp_grph(get_irp_irg(i), suffix);
2322 /*--------------------------------------------------------------------------------*
2323 * Dumps a stand alone loop graph with firm nodes which belong to one loop node *
2324 * packed together in one subgraph/box *
2325 *--------------------------------------------------------------------------------*/
2327 void dump_loops_standalone(FILE *F, ir_loop *loop) {
2328 int i = 0, loop_node_started = 0, son_number = 0, first = 0;
2330 ir_loop *son = NULL;
2332 /* Dump a new loop node. */
2333 dump_loop_node(F, loop);
2335 /* Dump the loop elements. */
2337 for(i = 0; i < get_loop_n_elements(loop); i++) {
2338 le = get_loop_element(loop, i);
2340 if (get_kind(son) == k_ir_loop) {
2342 /* We are a loop son -> Recurse */
2344 if(loop_node_started) { /* Close the "firm-nodes" node first if we started one. */
2345 fprintf(F, "\" }\n");
2346 fprintf (F, "edge: {sourcename: \"");
2348 fprintf (F, "\" targetname: \"");
2350 fprintf (F, "-%d-nodes\" label:\"%d...%d\"}\n", first, first, i-1);
2351 loop_node_started = 0;
2353 dump_loop_son_edge(F, loop, son_number++);
2354 dump_loops_standalone(F, son);
2355 } else if (get_kind(son) == k_ir_node) {
2356 /* We are a loop node -> Collect firm nodes */
2358 ir_node *n = le.node;
2361 if (!loop_node_started) {
2362 /* Start a new node which contains all firm nodes of the current loop */
2363 fprintf (F, "node: { title: \"");
2365 fprintf (F, "-%d-nodes\" color: lightyellow label: \"", i);
2366 loop_node_started = 1;
2372 bad |= dump_node_label(F, n);
2373 /* Causes indeterministic output: if (is_Block(n)) fprintf (F, "\t ->%d", (int)get_irn_link(n)); */
2374 if (has_backedges(n)) fprintf(F, "\t loop head!");
2375 } else { /* for callgraph loop tree */
2377 assert(get_kind(son) == k_ir_graph);
2379 /* We are a loop node -> Collect firm graphs */
2380 n = (ir_graph *)le.node;
2381 if (!loop_node_started) {
2382 /* Start a new node which contains all firm nodes of the current loop */
2383 fprintf (F, "node: { title: \"");
2385 fprintf (F, "-%d-nodes\" color: lightyellow label: \"", i);
2386 loop_node_started = 1;
2391 fprintf (F, " %s", get_irg_dump_name(n));
2392 /* fprintf (F, " %s (depth %d)", get_irg_dump_name(n), n->callgraph_weighted_loop_depth); */
2396 if (loop_node_started) {
2397 fprintf(F, "\" }\n");
2398 fprintf (F, "edge: {sourcename: \"");
2400 fprintf (F, "\" targetname: \"");
2402 fprintf (F, "-%d-nodes\" label:\"%d...%d\"}\n", first, first, i-1);
2403 loop_node_started = 0;
2407 void dump_loop_tree(ir_graph *irg, const char *suffix)
2410 ir_graph *rem = current_ir_graph;
2411 int el_rem = edge_label;
2414 /* if a filter is set, dump only the irg's that match the filter */
2415 if (!is_filtered_dump_name(get_entity_ident(get_irg_entity(irg)))) return;
2417 current_ir_graph = irg;
2419 f = vcg_open(irg, suffix, "-looptree");
2420 dump_vcg_header(f, get_irg_dump_name(irg), "top_to_bottom");
2422 if (get_irg_loop(irg)) dump_loops_standalone(f, get_irg_loop(irg));
2426 edge_label = el_rem;
2427 current_ir_graph = rem;
2430 void dump_callgraph_loop_tree(const char *suffix) {
2432 F = vcg_open_name("Callgraph_looptree", suffix);
2433 dump_vcg_header(F, "callgraph looptree", "top_to_bottom");
2434 dump_loops_standalone(F, irp->outermost_cg_loop);
2439 /*-----------------------------------------------------------------------------*/
2440 /* Dumps the firm nodes in the loop tree to a graph along with the loop nodes. */
2441 /*-----------------------------------------------------------------------------*/
2443 void collect_nodeloop(FILE *F, ir_loop *loop, eset *loopnodes) {
2444 int i, son_number = 0, node_number = 0;
2446 if (dump_loop_information_flag) dump_loop_node(F, loop);
2448 for (i = 0; i < get_loop_n_elements(loop); i++) {
2449 loop_element le = get_loop_element(loop, i);
2450 if (*(le.kind) == k_ir_loop) {
2451 if (dump_loop_information_flag) dump_loop_son_edge(F, loop, son_number++);
2453 collect_nodeloop(F, le.son, loopnodes);
2455 if (dump_loop_information_flag) dump_loop_node_edge(F, loop, node_number++);
2456 eset_insert(loopnodes, le.node);
2461 void collect_nodeloop_external_nodes(ir_loop *loop, eset *loopnodes, eset *extnodes) {
2464 for(i = 0; i < get_loop_n_elements(loop); i++) {
2465 loop_element le = get_loop_element(loop, i);
2466 if (*(le.kind) == k_ir_loop) {
2468 collect_nodeloop_external_nodes(le.son, loopnodes, extnodes);
2470 if (is_Block(le.node)) start = 0; else start = -1;
2471 for (j = start; j < get_irn_arity(le.node); j++) {
2472 ir_node *pred = get_irn_n(le.node, j);
2473 if (!eset_contains(loopnodes, pred)) {
2474 eset_insert(extnodes, pred);
2475 if (!is_Block(pred)) {
2476 pred = get_nodes_block(pred);
2477 if (!eset_contains(loopnodes, pred)) eset_insert(extnodes, pred);
2485 void dump_loop(ir_loop *l, const char *suffix) {
2488 eset *loopnodes = eset_create();
2489 eset *extnodes = eset_create();
2492 snprintf(name, sizeof(name), "loop_%d", get_loop_loop_nr(l));
2493 F = vcg_open_name (name, suffix);
2494 dump_vcg_header(F, name, NULL);
2496 /* collect all nodes to dump */
2497 collect_nodeloop(F, l, loopnodes);
2498 collect_nodeloop_external_nodes(l, loopnodes, extnodes);
2500 /* build block lists */
2501 for (n = eset_first(loopnodes); n != NULL; n = eset_next(loopnodes))
2502 set_irn_link(n, NULL);
2503 for (n = eset_first(extnodes); n != NULL; n = eset_next(extnodes))
2504 set_irn_link(n, NULL);
2505 for (n = eset_first(loopnodes); n != NULL; n = eset_next(loopnodes))
2507 b = get_nodes_block(n);
2508 set_irn_link(n, get_irn_link(b));
2511 for (n = eset_first(extnodes); n != NULL; n = eset_next(extnodes))
2513 b = get_nodes_block(n);
2514 set_irn_link(n, get_irn_link(b));
2518 for (b = eset_first(loopnodes); b != NULL; b = eset_next(loopnodes))
2520 fprintf(F, "graph: { title: \"");
2522 fprintf(F, "\" label: \"");
2523 dump_node_opcode(F, b);
2524 fprintf (F, " %ld", get_irn_node_nr(b));
2525 fprintf(F, "\" status:clustered color:yellow\n");
2527 /* dump the blocks edges */
2528 dump_ir_data_edges(F, b);
2530 /* dump the nodes that go into the block */
2531 for (n = get_irn_link(b); n; n = get_irn_link(n)) {
2532 if (eset_contains(extnodes, n)) overrule_nodecolor = "lightblue";
2534 overrule_nodecolor = NULL;
2535 if (!eset_contains(extnodes, n)) dump_ir_data_edges(F, n);
2538 /* Close the vcg information for the block */
2540 dump_const_node_local(F, b);
2543 for (b = eset_first(extnodes); b != NULL; b = eset_next(extnodes))
2545 fprintf(F, "graph: { title: \"");
2547 fprintf(F, "\" label: \"");
2548 dump_node_opcode(F, b);
2549 fprintf (F, " %ld", get_irn_node_nr(b));
2550 fprintf(F, "\" status:clustered color:lightblue\n");
2552 /* dump the nodes that go into the block */
2553 for (n = get_irn_link(b); n; n = get_irn_link(n)) {
2554 if (!eset_contains(loopnodes, n)) overrule_nodecolor = "lightblue";
2556 overrule_nodecolor = NULL;
2557 if (eset_contains(loopnodes, n)) dump_ir_data_edges(F, n);
2560 /* Close the vcg information for the block */
2562 dump_const_node_local(F, b);
2566 eset_destroy(loopnodes);
2567 eset_destroy(extnodes);