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.
18 #include "firm_common_t.h"
21 #include "irgraph_t.h"
32 #include "type_or_entity.h"
36 #include "callgraph.h"
46 void dump_chi_term(FILE *FL, ir_node *n);
47 void dump_state(FILE *FL, ir_node *n);
48 int get_opt_dump_abstvals(void);
49 typedef unsigned long SeqNo;
50 SeqNo get_Block_seqno(ir_node *n);
53 /* basis for a color range for vcg */
54 static int n_colors = 0;
55 static int base_color = 0;
57 static const char *get_mode_name_ex(ir_mode *mode, int *bad)
60 return get_mode_name(mode);
65 static const char *get_type_name_ex(type *tp, int *bad)
68 return get_type_name(tp);
73 static void print_type_type_edge(FILE *F, type *S, type *T, const char *fmt, ...)
78 fprintf(F, "edge: { sourcename: "); PRINT_TYPEID(S);
79 fprintf(F, " targetname: "); PRINT_TYPEID(T);
85 static void print_type_ent_edge(FILE *F, type *T, entity *E, const char *fmt, ...)
90 fprintf(F, "edge: { sourcename: "); PRINT_TYPEID(T);
91 fprintf(F, " targetname: \""); PRINT_ENTID(E); fprintf(F, "\"");
97 static void print_ent_ent_edge(FILE *F, entity *E, entity *T, int backedge, const char *fmt, ...)
103 fprintf(F, "backedge: { sourcename: \"");
105 fprintf(F, "edge: { sourcename: \"");
107 fprintf(F, "\" targetname: \""); PRINT_ENTID(T); fprintf(F, "\"");
108 vfprintf(F, fmt, ap);
113 static void print_ent_type_edge(FILE *F, entity *E, type *T, const char *fmt, ...)
118 fprintf(F, "edge: { sourcename: \""); PRINT_ENTID(E);
119 fprintf(F, "\" targetname: "); PRINT_TYPEID(T);
120 vfprintf(F, fmt, ap);
125 static void print_node_type_edge(FILE *F, const ir_node *N, type *T, const char *fmt, ...)
130 fprintf(F, "edge: { sourcename: \""); PRINT_NODEID(N);
131 fprintf(F, "\" targetname: "); PRINT_TYPEID(T);
132 vfprintf(F, fmt, ap);
137 static void print_node_ent_edge(FILE *F, const ir_node *N, entity *E, const char *fmt, ...)
142 fprintf(F, "edge: { sourcename: \""); PRINT_NODEID(N);
143 fprintf(F, "\" targetname: \""); PRINT_ENTID(E);
145 vfprintf(F, fmt, ap);
150 static void print_ent_node_edge(FILE *F, entity *E, const ir_node *N, const char *fmt, ...)
155 fprintf(F, "edge: { sourcename: \""); PRINT_ENTID(E);
156 fprintf(F, "\" targetname: \""); PRINT_NODEID(N); fprintf(F, "\"");
157 vfprintf(F, fmt, ap);
162 static void print_enum_item_edge(FILE *F, type *E, int item, const char *fmt, ...)
167 fprintf(F, "edge: { sourcename: "); PRINT_TYPEID(E);
168 fprintf(F, " targetname: \""); PRINT_ITEMID(E, item); fprintf(F, "\" ");
169 vfprintf(F, fmt, ap);
174 /*******************************************************************/
175 /* global and ahead declarations */
176 /*******************************************************************/
178 static void dump_whole_node(ir_node *n, void *env);
179 static INLINE void dump_loop_nodes_into_graph(FILE *F, ir_graph *irg);
181 /*******************************************************************/
182 /* Helper functions. */
183 /*******************************************************************/
185 /* Use private link attr to be able to call dumper anywhere without
186 destroying link fields. */
188 static pmap *irdump_link_map = NULL;
190 static void init_irdump(void) {
191 /* We need a new, empty map. */
192 if (irdump_link_map) pmap_destroy(irdump_link_map);
193 irdump_link_map = pmap_create();
197 void *ird_get_irn_link(ir_node *n) {
199 if (!irdump_link_map) return NULL;
201 if (pmap_contains(irdump_link_map, (void *)n))
202 res = pmap_get(irdump_link_map, (void *)n);
206 void ird_set_irn_link(ir_node *n, void *x) {
207 if (!irdump_link_map) init_irdump();
208 pmap_insert(irdump_link_map, (void *)n, x);
211 void *ird_get_irg_link(ir_graph *irg) {
213 if (!irdump_link_map) return NULL;
215 if (pmap_contains(irdump_link_map, (void *)irg))
216 res = pmap_get(irdump_link_map, (void *)irg);
220 void ird_set_irg_link(ir_graph *irg, void *x) {
221 if (!irdump_link_map) init_irdump();
222 pmap_insert(irdump_link_map, (void *)irg, x);
225 static void clear_link(ir_node * node, void * env) {
226 ird_set_irn_link(node, NULL);
230 static int node_floats(ir_node *n) {
231 return ((get_irn_pinned(n) == op_pin_state_floats) &&
232 (get_irg_pinned(current_ir_graph) == op_pin_state_floats));
235 const char *get_ent_dump_name(entity *ent) {
237 return "<NULL entity>";
238 /* Don't use get_entity_ld_ident (ent) as it computes the mangled name! */
239 if (ent->ld_name) return get_id_str(ent->ld_name);
240 return get_id_str(ent->name);
243 const char *get_irg_dump_name(ir_graph *irg) {
244 /* Don't use get_entity_ld_ident (ent) as it computes the mangled name! */
245 entity *ent = get_irg_entity(irg);
246 return get_ent_dump_name(ent);
249 static void collect_node(ir_node * node, void *env) {
252 || get_irn_op(node) == op_Bad
253 || get_irn_op(node) == op_Unknown
254 || get_irn_op(node) == op_NoMem) {
255 ir_node ** arr = (ir_node **) ird_get_irg_link(get_irn_irg(node));
256 if (!arr) arr = NEW_ARR_F(ir_node *, 0);
257 ARR_APP1(ir_node *, arr, node);
258 ird_set_irg_link(get_irn_irg(node), arr); /* arr is an l-value, APP_ARR might change it! */
260 ir_node * block = get_nodes_block(node);
261 ird_set_irn_link(node, ird_get_irn_link(block));
262 ird_set_irn_link(block, node);
266 /** Construct lists to walk ir block-wise.
268 * Collects all blocks, nodes not op_pin_state_pinned,
269 * Bad, NoMem and Unknown into a flexible array in link field of
270 * irg they belong to. Sets the irg link field to NULL in all
271 * graphs not visited.
272 * Free the list with DEL_ARR_F. */
273 static ir_node ** construct_block_lists(ir_graph *irg) {
274 int i, rem_view = get_interprocedural_view();
275 ir_graph *rem = current_ir_graph;
276 current_ir_graph = irg;
278 for (i = 0; i < get_irp_n_irgs(); i++)
279 ird_set_irg_link(get_irp_irg(i), NULL);
281 irg_walk_graph(current_ir_graph, clear_link, collect_node, current_ir_graph);
283 /* Collect also EndReg and EndExcept. We do not want to change the walker. */
284 set_interprocedural_view(false);
285 set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph)-1);
286 irg_walk(get_irg_end_reg(current_ir_graph), clear_link, collect_node, current_ir_graph);
287 set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph)-1);
288 irg_walk(get_irg_end_except(current_ir_graph), clear_link, collect_node, current_ir_graph);
289 set_interprocedural_view(rem_view);
291 current_ir_graph = rem;
292 return ird_get_irg_link(irg);
295 /*******************************************************************/
296 /* flags to steer output */
297 /*******************************************************************/
299 const char *dump_file_filter = "";
301 /* A compiler option to turn off edge labels */
303 /* A compiler option to turn off dumping values of constant entities */
304 int const_entities = 1;
305 /* A compiler option to dump the keep alive edges */
306 int dump_keepalive = 0;
307 /* Compiler options to dump analysis information in dump_ir_graph */
308 int dump_out_edge_flag = 0;
309 int dump_dominator_information_flag = 0;
310 int dump_loop_information_flag = 0;
311 int dump_backedge_information_flag = 1;
312 int dump_const_local = 0;
313 bool opt_dump_analysed_type_info = 1;
314 bool opt_dump_pointer_values_to_info = 0; /* default off: for test compares!! */
316 char* overrule_nodecolor = NULL;
318 INLINE bool get_opt_dump_const_local(void) {
319 if (!dump_out_edge_flag && !dump_loop_information_flag)
320 return dump_const_local;
325 void only_dump_method_with_name(ident *name) {
326 dump_file_filter = get_id_str(name);
330 /* To turn off display of edge labels. Edge labels offen cause xvcg to
331 abort with a segmentation fault. */
332 void turn_off_edge_labels(void) {
336 void dump_consts_local(bool b) {
337 dump_const_local = b;
340 void turn_off_constant_entity_values(void) {
344 void dump_keepalive_edges(bool b) {
348 bool get_opt_dump_keepalive_edges(void) {
349 return dump_keepalive;
352 void dump_out_edges(void) {
353 dump_out_edge_flag = 1;
356 void dump_dominator_information(void) {
357 dump_dominator_information_flag = 1;
360 void dump_loop_information(void) {
361 dump_loop_information_flag = 1;
364 void dont_dump_loop_information(void) {
365 dump_loop_information_flag = 0;
368 void dump_backedge_information(bool b) {
369 dump_backedge_information_flag = b;
372 /* Dump the information of type field specified in ana/irtypeinfo.h.
373 * If the flag is set, the type name is output in [] in the node label,
374 * else it is output as info.
376 void dump_analysed_type_info(bool b) {
377 opt_dump_analysed_type_info = b;
380 void dump_pointer_values_to_info(bool b) {
381 opt_dump_pointer_values_to_info = b;
384 /*-----------------------------------------------------------------*/
385 /* Routines to dump information about a single ir node. */
386 /*-----------------------------------------------------------------*/
389 dump_node_opcode(FILE *F, ir_node *n)
393 switch(get_irn_opcode(n)) {
398 res = tarval_snprintf(buf, sizeof(buf), get_Const_tarval(n));
399 assert(res < sizeof(buf) && "buffer to small for tarval_snprintf");
404 if (get_SymConst_kind(n) == symconst_addr_name) {
405 /* don't use get_SymConst_ptr_info as it mangles the name. */
406 fprintf (F, "SymC %s", get_id_str(get_SymConst_name(n)));
407 } else if (get_SymConst_kind(n) == symconst_addr_ent) {
408 assert(get_SymConst_entity(n));
409 assert(is_entity(get_SymConst_entity(n)));
410 fprintf (F, "SymC &%s", get_entity_name(get_SymConst_entity(n)));
412 assert(get_kind(get_SymConst_type(n)) == k_type);
413 assert(get_type_ident(get_SymConst_type(n)));
414 fprintf (F, "SymC %s ", get_type_name_ex(get_SymConst_type(n), &bad));
415 if (get_SymConst_kind(n) == symconst_type_tag)
423 if (!get_interprocedural_view())
430 ir_node *pred = get_Proj_pred(n);
432 if (get_irn_opcode(pred) == iro_Cond
433 && get_Proj_proj(n) == get_Cond_defaultProj(pred)
434 && get_irn_mode(get_Cond_selector(pred)) != mode_b)
435 fprintf (F, "defProj");
437 * else if (get_irn_opcode(pred) == iro_Proj && get_irn_opcode(get_Proj_pred(pred)) == iro_Start)
438 * fprintf (F, "Arg");
447 if (get_interprocedural_view()) {
448 fprintf(F, "%s %s", get_irn_opname(n), get_ent_dump_name(get_irg_entity(get_irn_irg(n))));
453 case iro_CallBegin: {
454 ir_node *addr = get_CallBegin_ptr(n);
456 if (get_irn_op(addr) == op_Sel)
457 ent = get_Sel_entity(addr);
458 else if ((get_irn_op(addr) == op_SymConst) && (get_SymConst_kind(addr) == symconst_addr_ent))
459 ent = get_SymConst_entity(addr);
460 fprintf (F, "%s", get_irn_opname(n));
461 if (ent) fprintf (F, " %s", get_entity_name(ent));
465 fprintf (F, "%s[%s]", get_irn_opname(n), get_mode_name_ex(get_Load_mode(n), &bad));
470 fprintf (F, "%s", get_irn_opname(n));
478 dump_node_mode(FILE *F, ir_node *n)
481 opcode iro = get_irn_opcode(n);
494 ir_mode *mode = get_irn_mode(n);
496 if (mode && mode != mode_BB && mode != mode_ANY && mode != mode_BAD &&
497 (mode != mode_T || iro == iro_Proj))
498 fprintf(F, "%s", get_mode_name_ex(mode, &bad));
505 static int dump_node_typeinfo(FILE *F, ir_node *n) {
508 if (opt_dump_analysed_type_info) {
509 if (get_irg_typeinfo_state(current_ir_graph) == irg_typeinfo_consistent ||
510 get_irg_typeinfo_state(current_ir_graph) == irg_typeinfo_inconsistent) {
511 type *tp = get_irn_typeinfo_type(n);
513 fprintf(F, " [%s]", get_type_name_ex(tp, &bad));
522 dump_node_nodeattr(FILE *F, ir_node *n)
526 switch (get_irn_opcode(n)) {
528 if (false && get_interprocedural_view()) {
529 fprintf (F, "%s", get_ent_dump_name(get_irg_entity(current_ir_graph)));
533 if (get_irn_opcode(get_Proj_pred(n)) == iro_Cmp) {
534 fprintf (F, "%s", get_pnc_string(get_Proj_proj(n)));
536 fprintf (F, "%ld", get_Proj_proj(n));
540 fprintf (F, "%ld", get_Filter_proj(n));
543 fprintf (F, "%s", get_ent_dump_name(get_Sel_entity(n)));
546 fprintf (F, "(%s)", get_type_name_ex(get_Cast_type(n), &bad));
549 fprintf (F, "%s", get_pnc_string(get_Confirm_cmp(n)));
559 static INLINE void dump_node_vcgattr(FILE *F, ir_node *n, int bad)
562 fprintf(F, "color: red");
565 switch (get_irn_opcode(n)) {
572 fprintf (F, "color: blue");
575 fprintf (F, "color: lightyellow");
578 fprintf (F, "color: green");
584 fprintf (F, "color: yellow");
587 PRINT_DEFAULT_NODE_ATTR;
590 if (overrule_nodecolor) fprintf(F, " color: %s", overrule_nodecolor);
593 static INLINE int dump_node_info(FILE *F, ir_node *n)
599 fprintf (F, " info1: \"");
600 if (opt_dump_pointer_values_to_info)
601 fprintf (F, "addr: %p \n", (void *)n);
602 fprintf (F, "mode: %s\n", get_mode_name(get_irn_mode(n)));
603 fprintf (F, "visited: %ld \n", get_irn_visited(n));
604 irg = get_irn_irg(n);
605 if (irg != get_const_code_irg())
606 fprintf (F, "irg: %s\n", get_ent_dump_name(get_irg_entity(irg)));
608 if (get_irn_pinned(n) == op_pin_state_floats &&
609 get_irg_pinned(get_irn_irg(n)) == op_pin_state_floats) {
610 fprintf(F, "node was pinned in ");
611 dump_node_opcode(F, get_nodes_block(n));
612 fprintf(F, " %ld\n", get_irn_node_nr(get_nodes_block(n)));
616 /* show all predecessor nodes */
617 fprintf(F, "pred nodes: \n");
620 dump_node_opcode(F, get_nodes_block(n));
621 fprintf(F, " %ld\n", get_irn_node_nr(get_nodes_block(n)));
623 for ( i = 0; i < get_irn_arity(n); ++i) {
624 fprintf(F, " %d: ", i);
625 dump_node_opcode(F, get_irn_n(n, i));
626 fprintf(F, " %ld\n", get_irn_node_nr(get_irn_n(n, i)));
630 fprintf(F, "arity: %d", get_irn_arity(n));
631 if ((get_irn_op(n) == op_Block) ||
632 (get_irn_op(n) == op_Phi) ||
633 ((get_irn_op(n) == op_Filter) && get_interprocedural_view())) {
634 fprintf(F, " backedges:");
636 for (i = 0; i < get_irn_arity(n); i++)
637 if (is_backedge(n, i)) { fprintf(F, "%c %d", comma, i); comma = ','; }
641 /* Loop node Someone else please tell me what's wrong ...
642 if (get_irn_loop(n)) {
643 ir_loop *loop = get_irn_loop(n);
645 fprintf(F, " in loop %d with depth %d\n",
646 get_loop_loop_nr(loop), get_loop_depth(loop));
651 switch (get_irn_opcode(n)) {
653 type *tp = get_entity_type(get_irg_entity(get_irn_irg(n)));
654 fprintf(F, "start of method of type %s \n", get_type_name_ex(tp, &bad));
655 for (i = 0; i < get_method_n_params(tp); ++i)
656 fprintf(F, " param %d type: %s \n", i, get_type_name_ex(get_method_param_type(tp, i), &bad));
657 if ((get_irp_ip_view_state() == ip_view_valid) && !get_interprocedural_view()) {
658 ir_node *sbl = get_nodes_block(n);
659 int i, n_cfgpreds = get_Block_cg_n_cfgpreds(sbl);
660 fprintf(F, "graph has %d interprocedural predecessors:\n", n_cfgpreds);
661 for (i = 0; i < n_cfgpreds; ++i) {
662 ir_node *cfgpred = get_Block_cg_cfgpred(sbl, i);
663 fprintf(F, " %d: Call %ld in graph %s\n", i, get_irn_node_nr(cfgpred),
664 get_irg_dump_name(get_irn_irg(cfgpred)));
669 fprintf(F, "allocating entity of type %s \n", get_type_name_ex(get_Alloc_type(n), &bad));
672 fprintf(F, "freeing entity of type %s \n", get_type_name_ex(get_Free_type(n), &bad));
675 entity *ent = get_Sel_entity(n);
678 fprintf(F, "Selecting entity of type %s\n", get_type_name_ex(get_entity_type(ent), &bad));
679 fprintf(F, " from entity of type %s\n", get_type_name_ex(get_entity_owner(ent), &bad));
682 fprintf(F, "<NULL entity>\n");
687 type *tp = get_Call_type(n);
688 fprintf(F, "calling method of type %s \n", get_type_name_ex(tp, &bad));
689 if(get_unknown_type() != tp) {
690 for (i = 0; i < get_method_n_params(tp); ++i)
691 fprintf(F, " param %d type: %s \n", i, get_type_name_ex(get_method_param_type(tp, i), &bad));
692 for (i = 0; i < get_method_n_ress(tp); ++i)
693 fprintf(F, " resul %d type: %s \n", i, get_type_name_ex(get_method_res_type(tp, i), &bad));
695 if (Call_has_callees(n)) {
696 fprintf(F, "possible callees: \n");
697 for (i = 0; i < get_Call_n_callees(n); i++) {
698 fprintf(F, " %d: %s\n", i, get_ent_dump_name(get_Call_callee(n, i)));
702 case iro_CallBegin: {
703 ir_node *call = get_CallBegin_call(n);
704 if (Call_has_callees(call)) {
705 fprintf(F, "possible callees: \n");
706 for (i = 0; i < get_Call_n_callees(call); i++) {
707 fprintf(F, " %d: %s\n", i, get_ent_dump_name(get_Call_callee(call, i)));
712 if (!get_interprocedural_view()) {
713 type *tp = get_entity_type(get_irg_entity(get_irn_irg(n)));
714 fprintf(F, "return in method of type %s \n", get_type_name_ex(tp, &bad));
715 for (i = 0; i < get_method_n_ress(tp); ++i)
716 fprintf(F, " res %d type: %s \n", i, get_type_name_ex(get_method_res_type(tp, i), &bad));
720 type *tp = get_Const_type(n);
721 assert(tp != none_type);
722 fprintf(F, "Const of type %s \n", get_type_name_ex(get_Const_type(n), &bad));
725 switch(get_SymConst_kind(n)) {
726 case symconst_addr_name:
727 fprintf(F, "kind addr_name\n");
729 case symconst_addr_ent:
730 fprintf(F, "kind addr_ent\n");
731 dump_entity_to_file(F, get_SymConst_entity(n), dump_verbosity_onlynames);
733 case symconst_type_tag:
734 fprintf(F, "kind type_tag\n");
737 fprintf(F, "kind size\n");
740 fprintf(F, "SymConst of type %s \n", get_type_name_ex(get_SymConst_value_type(n), &bad));
744 if (get_interprocedural_view()) {
745 fprintf(F, "intra predecessor nodes:\n");
746 for (i = 0; i < get_irn_intra_arity(n); i++) {
747 ir_node *pred = get_irn_intra_n(n, i);
748 fprintf(F, " %s%s %ld\n", get_irn_opname(pred), get_irn_modename(pred), get_irn_node_nr(pred));
751 fprintf(F, "inter predecessor nodes:\n");
752 for (i = 0; i < get_irn_inter_arity(n); i++) {
753 ir_node *pred = get_irn_inter_n(n, i);
754 fprintf(F, " %s%s %ld \tin graph %s\n", get_irn_opname(pred), get_irn_modename(pred),
755 get_irn_node_nr(pred), get_ent_dump_name(get_irg_entity(get_irn_irg(pred))));
760 fprintf(F, "volatility: %s\n", get_volatility_name(get_Load_volatility(n)));
763 fprintf(F, "volatility: %s\n", get_volatility_name(get_Store_volatility(n)));
769 if (get_irg_typeinfo_state(get_irn_irg(n)) == irg_typeinfo_consistent ||
770 get_irg_typeinfo_state(get_irn_irg(n)) == irg_typeinfo_inconsistent )
771 if (get_irn_typeinfo_type(n) != none_type)
772 fprintf (F, "\nAnalysed type: %s", get_type_name_ex(get_irn_typeinfo_type(n), &bad));
780 * checks wheater a node is "constant-like", ie can be treated "block-less"
783 bool is_constlike_node(ir_node *n) {
784 ir_op *op = get_irn_op(n);
785 return (op == op_Const || op == op_Bad || op == op_NoMem || op == op_SymConst || op == op_Unknown);
789 /* outputs the predecessors of n, that are constants, local. I.e.,
790 generates a copy of the constant predecessors for each node called with. */
791 static void dump_const_node_local(FILE *F, ir_node *n) {
793 if (!get_opt_dump_const_local()) return;
795 /* Use visited flag to avoid outputting nodes twice.
796 initialize it first. */
797 for (i = 0; i < get_irn_arity(n); i++) {
798 ir_node *con = get_irn_n(n, i);
799 if (is_constlike_node(con)) {
800 set_irn_visited(con, get_irg_visited(current_ir_graph) - 1);
804 for (i = 0; i < get_irn_arity(n); i++) {
805 ir_node *con = get_irn_n(n, i);
806 if (is_constlike_node(con) && irn_not_visited(con)) {
809 mark_irn_visited(con);
810 /* Generate a new name for the node by appending the names of
812 fprintf(F, "node: {title: "); PRINT_CONSTID(n, con);
813 fprintf(F, " label: \"");
814 bad |= dump_node_opcode(F, con);
815 bad |= dump_node_mode(F, con);
816 bad |= dump_node_typeinfo(F, con);
818 bad |= dump_node_nodeattr(F, con);
819 fprintf(F, " %ld", get_irn_node_nr(con));
821 bad |= dump_node_info(F, con);
822 dump_node_vcgattr(F, con, bad);
828 static void INLINE print_node_error(FILE *F, const char *p)
833 fprintf (F, " info2: \"%s\"", p);
836 static void dump_node(FILE *F, ir_node *n)
841 if (get_opt_dump_const_local() && is_constlike_node(n)) return;
843 fprintf(F, "node: {title: \""); PRINT_NODEID(n); fprintf(F, "\" label: \"");
845 bad = ! irn_vrfy_irg_dump(n, current_ir_graph, &p);
846 bad |= dump_node_opcode(F, n);
847 bad |= dump_node_mode(F, n);
848 bad |= dump_node_typeinfo(F, n);
850 bad |= dump_node_nodeattr(F, n);
851 fprintf(F, " %ld", get_irn_node_nr(n));
853 bad |= dump_node_info(F, n);
854 print_node_error(F, p);
855 dump_node_vcgattr(F, n, bad);
857 dump_const_node_local(F, n);
864 /* dump the edge to the block this node belongs to */
866 dump_ir_block_edge(FILE *F, ir_node *n) {
867 if (get_opt_dump_const_local() && is_constlike_node(n)) return;
868 if (is_no_Block(n)) {
869 ir_node *block = get_nodes_block(n);
871 fprintf (F, "edge: { sourcename: \"");
873 fprintf (F, "\" targetname: ");
874 fprintf(F, "\""); PRINT_NODEID(block); fprintf(F, "\"");
875 fprintf (F, " " BLOCK_EDGE_ATTR "}\n");
880 print_data_edge_vcgattr(FILE *F, ir_node *from, int to) {
881 if (get_nodes_block(from) == get_nodes_block(get_irn_n(from, to)))
882 fprintf (F, INTRA_DATA_EDGE_ATTR);
884 fprintf (F, INTER_DATA_EDGE_ATTR);
888 print_mem_edge_vcgattr(FILE *F, ir_node *from, int to) {
889 if (get_nodes_block(from) == get_nodes_block(get_irn_n(from, to)))
890 fprintf (F, INTRA_MEM_EDGE_ATTR);
892 fprintf (F, INTER_MEM_EDGE_ATTR);
896 print_edge_vcgattr(FILE *F, ir_node *from, int to) {
899 if (dump_backedge_information_flag && is_backedge(from, to))
900 fprintf (F, BACK_EDGE_ATTR);
902 switch (get_irn_opcode(from)) {
904 fprintf (F, CF_EDGE_ATTR);
906 case iro_Start: break;
909 if (get_irn_mode(get_End_keepalive(from, to)) == mode_BB)
910 fprintf (F, CF_EDGE_ATTR);
911 if (get_irn_mode(get_End_keepalive(from, to)) == mode_X)
912 fprintf (F, INTER_MEM_EDGE_ATTR);
920 print_data_edge_vcgattr(F, from, to);
925 print_mem_edge_vcgattr(F, from, to);
927 print_data_edge_vcgattr(F, from, to);
931 print_data_edge_vcgattr(F, from, to);
936 print_mem_edge_vcgattr(F, from, to);
938 print_data_edge_vcgattr(F, from, to);
945 print_data_edge_vcgattr(F, from, to);
952 print_mem_edge_vcgattr(F, from, to);
954 print_data_edge_vcgattr(F, from, to);
966 print_data_edge_vcgattr(F, from, to);
969 if (get_irn_modecode(from) == irm_M)
970 fprintf (F, INTER_MEM_EDGE_ATTR);
972 print_data_edge_vcgattr(F, from, to);
979 print_mem_edge_vcgattr(F, from, to);
981 print_data_edge_vcgattr(F, from, to);
984 print_mem_edge_vcgattr(F, from, to);
986 case iro_Tuple: break;
989 switch (get_irn_modecode(from)) {
991 fprintf (F, CF_EDGE_ATTR);
994 fprintf (F, INTER_MEM_EDGE_ATTR);
997 print_data_edge_vcgattr(F, from, to);
1001 case iro_Bad: break;
1002 case iro_Unknown: break;
1004 switch (get_irn_modecode(from)) {
1006 fprintf (F, INTRA_MEM_EDGE_ATTR);
1009 fprintf (F, CF_EDGE_ATTR);
1012 print_data_edge_vcgattr(F, from, to);
1020 /* dump edges to our inputs */
1022 dump_ir_data_edges(FILE *F, ir_node *n) {
1023 int i, visited = get_irn_visited(n);
1025 if ((get_irn_op(n) == op_End) && (!dump_keepalive))
1028 for (i = 0; i < get_irn_arity(n); i++) {
1029 ir_node * pred = get_irn_n(n, i);
1032 if ((get_interprocedural_view() && get_irn_visited(pred) < visited))
1033 continue; /* pred not dumped */
1035 if (dump_backedge_information_flag && is_backedge(n, i))
1036 fprintf (F, "backedge: {sourcename: \"");
1038 fprintf (F, "edge: {sourcename: \"");
1040 fprintf (F, "\" targetname: ");
1041 if ((get_opt_dump_const_local()) && is_constlike_node(pred)) {
1042 PRINT_CONSTID(n, pred);
1044 fprintf(F, "\""); PRINT_NODEID(pred); fprintf(F, "\"");
1046 fprintf (F, " label: \"%d\" ", i);
1047 print_edge_vcgattr(F, n, i);
1052 /** Dumps a node and its edges but not the block edge
1055 dump_node_wo_blockedge (ir_node *n, void *env) {
1058 dump_ir_data_edges(F, n);
1061 /** Dumps a node and its edges.
1064 dump_whole_node (ir_node *n, void *env) {
1066 dump_node_wo_blockedge(n, env);
1067 if (!node_floats(n)) dump_ir_block_edge(F, n);
1071 dump_const_node(ir_node *n, void *env) {
1072 if (is_Block(n)) return;
1073 dump_node_wo_blockedge(n, env);
1076 /***********************************************************************/
1077 /* the following routines dump the nodes/irgs bracketed to graphs. */
1078 /***********************************************************************/
1080 /** Dumps a constant expression as entity initializer, array bound ...
1082 static void dump_const_expression(FILE *F, ir_node *value) {
1083 ir_graph *rem = current_ir_graph;
1084 int rem_dump_const_local = dump_const_local;
1085 dump_const_local = 0;
1086 current_ir_graph = get_const_code_irg();
1087 irg_walk(value, dump_const_node, NULL, F);
1088 /* Decrease visited flag so that we walk with the same flag for the next
1089 expresssion. This guarantees that we don't dump the same node twice,
1090 as for const expressions cse is performed to save memory. */
1091 set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph) -1);
1092 current_ir_graph = rem;
1093 dump_const_local = rem_dump_const_local;
1096 /** Dump a block as graph containing its nodes.
1098 * Expects to find nodes belonging to the block as list in its
1100 * Dumps the edges of all nodes including itself. */
1102 dump_whole_block(FILE *F, ir_node *block) {
1104 assert(is_Block(block));
1106 fprintf(F, "graph: { title: \"");
1107 PRINT_NODEID(block);
1108 fprintf(F, "\" label: \"");
1109 dump_node_opcode(F, block);
1110 fprintf (F, " %ld", get_irn_node_nr(block));
1112 if (get_opt_dump_abstvals())
1113 fprintf (F, " seqno: %d", (int)get_Block_seqno(block));
1115 fprintf(F, "\" status:clustered color:%s \n",
1116 get_Block_matured(block) ? "yellow" : "red");
1118 /* dump the blocks edges */
1119 dump_ir_data_edges(F, block);
1121 /* dump the nodes that go into the block */
1122 for (node = ird_get_irn_link(block); node; node = ird_get_irn_link(node)) {
1124 dump_ir_data_edges(F, node);
1127 /* Close the vcg information for the block */
1129 dump_const_node_local(F, block);
1131 dump_chi_term(F, block);
1136 /** dumps a graph block-wise. Expects all blockless nodes in arr in irgs link.
1137 * The outermost nodes: blocks and nodes not op_pin_state_pinned, Bad, Unknown. */
1139 dump_block_graph(FILE *F, ir_graph *irg) {
1141 ir_graph *rem = current_ir_graph;
1142 ir_node **arr = ird_get_irg_link(irg);
1143 current_ir_graph = irg;
1145 for (i = ARR_LEN(arr) - 1; i >= 0; --i) {
1146 ir_node * node = arr[i];
1147 if (is_Block(node)) {
1148 /* Dumps the block and all the nodes in the block, which are to
1149 be found in Block->link. */
1150 dump_whole_block(F, node);
1152 /* Nodes that are not in a Block. */
1154 dump_ir_data_edges(F, node);
1158 if (dump_loop_information_flag && (get_irg_loopinfo_state(irg) & loopinfo_valid))
1159 dump_loop_nodes_into_graph(F, irg);
1161 current_ir_graph = rem;
1164 /** Dumps an irg as a graph.
1165 * If interprocedural view edges can point to nodes out of this graph.
1167 static void dump_graph(FILE *F, ir_graph *irg) {
1169 fprintf(F, "graph: { title: \"");
1171 fprintf(F, "\" label: \"%s\" status:clustered color:white \n",
1172 get_ent_dump_name(get_irg_entity(irg)));
1174 dump_block_graph(F, irg);
1176 /* Close the vcg information for the irg */
1177 fprintf(F, "}\n\n");
1180 /*******************************************************************/
1181 /* Basic type and entity nodes and edges. */
1182 /*******************************************************************/
1184 /** dumps the edges between nodes and their type or entity attributes. */
1185 static void dump_node2type_edges(ir_node *n, void *env)
1190 switch (get_irn_opcode(n)) {
1192 /* @@@ some consts have an entity */
1195 if ( (get_SymConst_kind(n) ==symconst_type_tag)
1196 || (get_SymConst_kind(n) ==symconst_size))
1198 print_node_type_edge(F,n,get_SymConst_type(n),NODE2TYPE_EDGE_ATTR);
1202 print_node_ent_edge(F,n,get_Sel_entity(n),NODE2TYPE_EDGE_ATTR);
1205 print_node_type_edge(F,n,get_Call_type(n),NODE2TYPE_EDGE_ATTR);
1208 print_node_type_edge(F,n,get_Alloc_type(n),NODE2TYPE_EDGE_ATTR);
1211 print_node_type_edge(F,n,get_Free_type(n),NODE2TYPE_EDGE_ATTR);
1214 print_node_type_edge(F,n,get_Cast_type(n),NODE2TYPE_EDGE_ATTR);
1222 static int print_type_info(FILE *F, type *tp) {
1225 if (get_type_state(tp) == layout_undefined) {
1226 fprintf(F, "state: layout_undefined\n");
1228 fprintf(F, "state: layout_fixed,\n");
1230 if (get_type_mode(tp))
1231 fprintf(F, "mode: %s,\n", get_mode_name_ex(get_type_mode(tp), &bad));
1232 fprintf(F, "size: %db,\n", get_type_size_bits(tp));
1237 static void print_typespecific_info(FILE *F, type *tp) {
1238 switch (get_type_tpop_code(tp)) {
1241 fprintf(F, "peculiarity: %s\n", get_peculiarity_string(get_class_peculiarity(tp)));
1248 fprintf(F, "variadicity: %s\n", get_variadicity_name(get_method_variadicity(tp)));
1249 fprintf(F, "params: %d\n", get_method_n_params(tp));
1250 fprintf(F, "results: %d\n", get_method_n_ress(tp));
1258 case tpo_enumeration:
1272 static void print_typespecific_vcgattr(FILE *F, type *tp) {
1273 switch (get_type_tpop_code(tp)) {
1276 if (peculiarity_existent == get_class_peculiarity(tp))
1277 fprintf (F, " " TYPE_CLASS_NODE_ATTR);
1279 fprintf (F, " " TYPE_DESCRIPTION_NODE_ATTR);
1283 fprintf (F, " " TYPE_METH_NODE_ATTR);
1294 case tpo_enumeration:
1307 static int print_type_node(FILE *F, type *tp)
1311 fprintf (F, "node: {title: ");
1313 fprintf (F, " label: \"%s %s\"", get_type_tpop_name(tp), get_type_name_ex(tp, &bad));
1314 fprintf (F, " info1: \"");
1315 bad |= print_type_info(F, tp);
1316 print_typespecific_info(F, tp);
1318 print_typespecific_vcgattr(F, tp);
1324 #define X(a) case a: fprintf(F, #a); break
1325 void dump_entity_node(FILE *F, entity *ent, int color)
1327 fprintf (F, "node: {title: \"");
1328 PRINT_ENTID(ent); fprintf(F, "\"");
1329 fprintf (F, DEFAULT_TYPE_ATTRIBUTE);
1330 fprintf (F, "label: ");
1331 fprintf (F, "\"ent %s\" ", get_ent_dump_name(ent));
1333 fprintf(F, "color: %d", color);
1335 fprintf (F, ENTITY_NODE_ATTR);
1336 fprintf (F, "\n info1: \"");
1338 dump_entity_to_file(F, ent, dump_verbosity_entattrs | dump_verbosity_entconsts);
1340 fprintf(F, "\"\n}\n");
1344 static void dump_enum_item(FILE *F, type *tp, int pos)
1347 ident *id = get_enumeration_nameid(tp, pos);
1348 tarval *tv = get_enumeration_enum(tp, pos);
1350 tarval_snprintf(buf, sizeof(buf), tv);
1351 fprintf (F, "node: {title: \"");
1352 PRINT_ITEMID(tp, pos); fprintf(F, "\"");
1353 fprintf (F, DEFAULT_ENUM_ITEM_ATTRIBUTE);
1354 fprintf (F, "label: ");
1355 fprintf (F, "\"enum item %s\" " ENUM_ITEM_NODE_ATTR, get_id_str(id));
1356 fprintf (F, "\n info1: \"value: %s\"}\n", buf);
1359 /* dumps a type or entity and it's edges. */
1361 dump_type_info(type_or_ent *tore, void *env) {
1363 int i = 0; /* to shutup gcc */
1365 /* dump this type or entity */
1367 switch (get_kind(tore)) {
1370 entity *ent = (entity *)tore;
1373 dump_entity_node(F, ent, 0);
1375 /* skip this to reduce graph. Member edge of type is parallel to this edge. *
1376 fprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
1377 ENT_OWN_EDGE_ATTR "}\n", ent, get_entity_owner(ent));*/
1378 print_ent_type_edge(F,ent, get_entity_type(ent), ENT_TYPE_EDGE_ATTR);
1379 if(is_class_type(get_entity_owner(ent))) {
1380 for(i = 0; i < get_entity_n_overwrites(ent); i++)
1381 print_ent_ent_edge(F,ent, get_entity_overwrites(ent, i), 0, ENT_OVERWRITES_EDGE_ATTR);
1383 /* attached subgraphs */
1384 if (const_entities && (get_entity_variability(ent) != variability_uninitialized)) {
1385 if (is_atomic_entity(ent)) {
1386 value = get_atomic_ent_value(ent);
1388 print_ent_node_edge(F, ent, value, ENT_VALUE_EDGE_ATTR, i);
1389 /* DDMN(value); $$$ */
1390 dump_const_expression(F, value);
1393 if (is_compound_entity(ent)) {
1394 for (i = 0; i < get_compound_ent_n_values(ent); i++) {
1395 value = get_compound_ent_value(ent, i);
1397 print_ent_node_edge(F, ent, value, ENT_VALUE_EDGE_ATTR, i);
1398 dump_const_expression(F, value);
1399 print_ent_ent_edge(F, ent, get_compound_ent_value_member(ent, i), 0, ENT_CORR_EDGE_ATTR, i);
1401 fprintf (F, "edge: { sourcename: \"%p\" targetname: \"%p\" "
1402 ENT_CORR_EDGE_ATTR "}\n", GET_ENTID(ent),
1403 get_compound_ent_value_member(ent, i), i);
1412 type *tp = (type *)tore;
1413 print_type_node(F, tp);
1414 /* and now the edges */
1415 switch (get_type_tpop_code(tp)) {
1418 for (i=0; i < get_class_n_supertypes(tp); i++)
1419 print_type_type_edge(F, tp,get_class_supertype(tp, i),TYPE_SUPER_EDGE_ATTR);
1420 for (i=0; i < get_class_n_members(tp); i++)
1421 print_type_ent_edge(F,tp,get_class_member(tp, i),TYPE_MEMBER_EDGE_ATTR);
1425 for (i=0; i < get_struct_n_members(tp); i++)
1426 print_type_ent_edge(F,tp,get_struct_member(tp, i),TYPE_MEMBER_EDGE_ATTR);
1430 for (i = 0; i < get_method_n_params(tp); i++)
1431 print_type_type_edge(F,tp,get_method_param_type(tp, i),METH_PAR_EDGE_ATTR,i);
1432 for (i = 0; i < get_method_n_ress(tp); i++)
1433 print_type_type_edge(F,tp,get_method_res_type(tp, i),METH_RES_EDGE_ATTR,i);
1437 for (i = 0; i < get_union_n_members(tp); i++)
1438 print_type_ent_edge(F,tp,get_union_member(tp, i),UNION_EDGE_ATTR);
1442 print_type_type_edge(F,tp,get_array_element_type(tp),ARR_ELT_TYPE_EDGE_ATTR);
1443 print_type_ent_edge(F,tp,get_array_element_entity(tp),ARR_ENT_EDGE_ATTR);
1444 for (i = 0; i < get_array_n_dimensions(tp); i++) {
1445 ir_node *upper = get_array_upper_bound(tp, i);
1446 ir_node *lower = get_array_lower_bound(tp, i);
1447 print_node_type_edge(F, upper, tp, "label: \"upper %d\"", get_array_order(tp, i));
1448 print_node_type_edge(F, lower, tp, "label: \"lower %d\"", get_array_order(tp, i));
1449 dump_const_expression(F, upper);
1450 dump_const_expression(F, lower);
1454 case tpo_enumeration:
1456 for (i = 0; i < get_enumeration_n_enums(tp); ++i) {
1457 dump_enum_item(F, tp, i);
1458 print_enum_item_edge(F, tp, i, "label: \"item %d\"", i);
1463 print_type_type_edge(F,tp,get_pointer_points_to_type(tp), PTR_PTS_TO_EDGE_ATTR);
1471 break; /* case k_type */
1474 printf(" *** irdump, dump_type_info(l.%i), faulty type.\n", __LINE__);
1476 } /* switch kind_or_entity */
1479 typedef struct _h_env {
1484 /** For dumping class hierarchies.
1485 * Dumps a class type node and a superclass edge.
1486 * If env->dump_ent dumps entities of classes and overwrites edges.
1489 dump_class_hierarchy_node (type_or_ent *tore, void *ctx) {
1492 int i = 0; /* to shutup gcc */
1494 /* dump this type or entity */
1495 switch (get_kind(tore)) {
1497 entity *ent = (entity *)tore;
1498 if (get_entity_owner(ent) == get_glob_type()) break;
1499 if (!is_method_type(get_entity_type(ent))) break; /* GL */
1500 if (env->dump_ent && is_class_type(get_entity_owner(ent))) {
1502 dump_entity_node(F, ent, 0);
1504 print_type_ent_edge(F,get_entity_owner(ent),ent,TYPE_MEMBER_EDGE_ATTR);
1505 for(i = 0; i < get_entity_n_overwrites(ent); i++)
1506 print_ent_ent_edge(F, get_entity_overwrites(ent, i), ent, 0, ENT_OVERWRITES_EDGE_ATTR);
1508 } break; /* case k_entity */
1511 type *tp = (type *)tore;
1512 if (tp == get_glob_type()) break;
1513 switch (get_type_tpop_code(tp)) {
1515 print_type_node(F, tp);
1516 /* and now the edges */
1517 for (i=0; i < get_class_n_supertypes(tp); i++)
1519 print_type_type_edge(F,tp,get_class_supertype(tp, i),TYPE_SUPER_EDGE_ATTR);
1525 break; /* case k_type */
1528 printf(" *** irdump, dump_class_hierarchy_node(l.%i), faulty type.\n", __LINE__);
1530 } /* switch kind_or_entity */
1533 /*******************************************************************/
1534 /* dump analysis information that is expressed in graph terms. */
1535 /*******************************************************************/
1537 /* dump out edges */
1539 dump_out_edge(ir_node *n, void *env) {
1542 for (i = 0; i < get_irn_n_outs(n); i++) {
1543 assert(get_irn_out(n, i));
1544 fprintf (F, "edge: {sourcename: \"");
1546 fprintf (F, "\" targetname: \"");
1547 PRINT_NODEID(get_irn_out(n, i));
1548 fprintf (F, "\" color: red linestyle: dashed");
1554 dump_loop_label(FILE *F, ir_loop *loop) {
1555 fprintf (F, "loop %d, %d sons, %d nodes",
1556 get_loop_depth(loop), get_loop_n_sons(loop), get_loop_n_nodes(loop));
1559 static INLINE void dump_loop_info(FILE *F, ir_loop *loop) {
1560 fprintf (F, " info1: \"");
1561 fprintf (F, " loop nr: %d", get_loop_loop_nr(loop));
1562 #if DEBUG_libfirm /* GL @@@ debug analyses */
1563 fprintf (F, "\n The loop was analyzed %d times.", (int)get_loop_link(loop));
1569 dump_loop_node(FILE *F, ir_loop *loop) {
1570 fprintf (F, "node: {title: \"");
1572 fprintf (F, "\" label: \"");
1573 dump_loop_label(F, loop);
1575 dump_loop_info(F, loop);
1581 dump_loop_node_edge(FILE *F, ir_loop *loop, int i) {
1583 fprintf (F, "edge: {sourcename: \"");
1585 fprintf (F, "\" targetname: \"");
1586 PRINT_NODEID(get_loop_node(loop, i));
1587 fprintf (F, "\" color: green");
1592 dump_loop_son_edge(FILE *F, ir_loop *loop, int i) {
1594 fprintf (F, "edge: {sourcename: \"");
1596 fprintf (F, "\" targetname: \"");
1597 PRINT_LOOPID(get_loop_son(loop, i));
1598 fprintf (F, "\" color: darkgreen label: \"%d\"}\n",
1599 get_loop_element_pos(loop, get_loop_son(loop, i)));
1603 void dump_loops(FILE *F, ir_loop *loop) {
1605 /* dump this loop node */
1606 dump_loop_node(F, loop);
1608 /* dump edges to nodes in loop -- only if it is a real loop */
1609 if (get_loop_depth(loop) != 0) {
1610 for (i = 0; i < get_loop_n_nodes(loop); i++) {
1611 dump_loop_node_edge(F, loop, i);
1614 for (i = 0; i < get_loop_n_sons(loop); i++) {
1615 dump_loops(F, get_loop_son(loop, i));
1616 dump_loop_son_edge(F, loop, i);
1621 void dump_loop_nodes_into_graph(FILE *F, ir_graph *irg) {
1622 ir_graph *rem = current_ir_graph;
1623 current_ir_graph = irg;
1625 if (get_irg_loop(irg)) dump_loops(F, get_irg_loop(irg));
1627 current_ir_graph = rem;
1632 * dumps the VCG header
1634 INLINE void dump_vcg_header(FILE *F, const char *name, const char *orientation) {
1643 if (!orientation) orientation = "bottom_to_top";
1647 "graph: { title: \"ir graph of %s\"\n"
1648 "display_edge_labels: %s\n"
1649 "layoutalgorithm: mindepth\n"
1650 "manhattan_edges: yes\n"
1651 "port_sharing: no\n"
1653 "classname 1: \"intrablock Data\"\n"
1654 "classname 16: \"interblock Data\"\n"
1655 "classname 2: \"Block\"\n"
1656 "classname 13: \"Control Flow\"\n"
1657 "classname 18: \"Exception Control Flow for Interval Analysis\"\n"
1658 "classname 14: \"intrablock Memory\"\n"
1659 "classname 17: \"interblock Memory\"\n"
1660 "classname 15: \"Dominators\"\n"
1661 "classname 3: \"Entity type\"\n"
1662 "classname 4: \"Entity owner\"\n"
1663 "classname 5: \"Method Param\"\n"
1664 "classname 6: \"Method Res\"\n"
1665 "classname 7: \"Super\"\n"
1666 "classname 8: \"Union\"\n"
1667 "classname 9: \"Points-to\"\n"
1668 "classname 10: \"Array Element Type\"\n"
1669 "classname 11: \"Overwrites\"\n"
1670 "classname 12: \"Member\"\n"
1671 "infoname 1: \"Attribute\"\n"
1672 "infoname 2: \"Verification errors\"\n",
1673 name, label, orientation);
1675 /* don't use all, the range is too whith/black. */
1679 "colorentry 100: 0 0 0\n"
1680 "colorentry 101: 20 0 0\n"
1681 "colorentry 102: 40 0 0\n"
1682 "colorentry 103: 60 0 0\n"
1683 "colorentry 104: 80 0 0\n"
1684 "colorentry 105: 100 0 0\n"
1685 "colorentry 106: 120 0 0\n"
1686 "colorentry 107: 140 0 0\n"
1687 "colorentry 108: 150 0 0\n"
1688 "colorentry 109: 180 0 0\n"
1689 "colorentry 110: 200 0 0\n"
1690 "colorentry 111: 220 0 0\n"
1691 "colorentry 112: 240 0 0\n"
1692 "colorentry 113: 255 0 0\n"
1693 "colorentry 113: 255 20 20\n"
1694 "colorentry 114: 255 40 40\n"
1695 "colorentry 115: 255 60 60\n"
1696 "colorentry 116: 255 80 80\n"
1697 "colorentry 117: 255 100 100\n"
1698 "colorentry 118: 255 120 120\n"
1699 "colorentry 119: 255 140 140\n"
1700 "colorentry 120: 255 150 150\n"
1701 "colorentry 121: 255 180 180\n"
1702 "colorentry 122: 255 200 200\n"
1703 "colorentry 123: 255 220 220\n"
1704 "colorentry 124: 255 240 240\n"
1705 "colorentry 125: 255 250 250\n"
1708 fprintf (F, "\n"); /* a separator */
1714 * @param irg The graph to be dumped
1715 * @param suffix1 first filename suffix
1716 * @param suffix2 second filename suffix
1718 FILE *vcg_open (ir_graph *irg, const char * suffix1, const char *suffix2) {
1720 const char *nm = get_irg_dump_name(irg);
1721 int len = strlen(nm), i, j;
1722 char *fname; /* filename to put the vcg information in */
1724 if (!suffix1) suffix1 = "";
1725 if (!suffix2) suffix2 = "";
1727 /* open file for vcg graph */
1728 fname = malloc (len * 2 + strlen(suffix1) + strlen(suffix2) + 5);
1730 /* strncpy (fname, nm, len); */ /* copy the filename */
1732 for (i = 0; i < len; ++i) { /* replase '/' in the name: escape by @. */
1734 fname[j] = '@'; j++; fname[j] = '1'; j++;
1735 } else if (nm[i] == '@') {
1736 fname[j] = '@'; j++; fname[j] = '2'; j++;
1738 fname[j] = nm[i]; j++;
1742 strcat (fname, suffix1); /* append file suffix */
1743 strcat (fname, suffix2); /* append file suffix */
1744 strcat (fname, ".vcg"); /* append the .vcg suffix */
1745 F = fopen (fname, "w"); /* open file for writing */
1747 panic("cannot open %s for writing (%m)", fname); /* not reached */
1757 * @param irg The graph to be dumped
1758 * @param suffix filename suffix
1760 static FILE *vcg_open_name (const char *name, const char *suffix) {
1762 char *fname; /* filename to put the vcg information in */
1763 int i, j, len = strlen(name);
1765 if (!suffix) suffix = "";
1767 /** open file for vcg graph */
1768 fname = malloc (len * 2 + 5 + strlen(suffix));
1769 /* strcpy (fname, name);*/ /* copy the filename */
1771 for (i = 0; i < len; ++i) { /* replase '/' in the name: escape by @. */
1772 if (name[i] == '/') {
1773 fname[j] = '@'; j++; fname[j] = '1'; j++;
1774 } else if (name[i] == '@') {
1775 fname[j] = '@'; j++; fname[j] = '2'; j++;
1777 fname[j] = name[i]; j++;
1781 strcat (fname, suffix);
1782 strcat (fname, ".vcg"); /* append the .vcg suffix */
1783 F = fopen (fname, "w"); /* open file for writing */
1785 panic ("cannot open %s for writing (%m)", fname); /* not reached */
1793 * Dumps the vcg file footer
1795 static INLINE void dump_vcg_footer (FILE *F) {
1800 * close the vcg file
1802 void vcg_close (FILE *F) {
1803 dump_vcg_footer(F); /* print footer */
1804 fclose (F); /* close vcg file */
1807 /************************************************************************/
1808 /************************************************************************/
1809 /* Routines that dump all or parts of the firm representation to a file */
1810 /************************************************************************/
1811 /************************************************************************/
1813 /************************************************************************/
1814 /* Dump ir graphs, differnt formats and additional information. */
1815 /************************************************************************/
1817 /** Routine to dump a graph, blocks as conventional nodes.
1820 dump_ir_graph (ir_graph *irg, const char *suffix )
1825 rem = current_ir_graph;
1827 if (strncmp(get_entity_name(get_irg_entity(irg)), dump_file_filter, strlen(dump_file_filter)) != 0) return;
1828 current_ir_graph = irg;
1829 if (get_interprocedural_view()) suffix1 = "-pure-ip";
1830 else suffix1 = "-pure";
1831 f = vcg_open(irg, suffix, suffix1);
1832 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1834 /* walk over the graph */
1835 /* dump_whole_node must be called in post visiting predecessors */
1836 irg_walk(get_irg_end(irg), NULL, dump_whole_node, f);
1838 /* dump the out edges in a separate walk */
1839 if ((dump_out_edge_flag) && (get_irg_outs_state(irg) != outs_none)) {
1840 irg_out_walk(get_irg_start(irg), dump_out_edge, NULL, NULL);
1845 current_ir_graph = rem;
1850 dump_ir_block_graph (ir_graph *irg, const char *suffix)
1856 if (strncmp(get_entity_name(get_irg_entity(irg)), dump_file_filter, strlen(dump_file_filter)) != 0)
1859 if (get_interprocedural_view()) suffix1 = "-ip";
1861 f = vcg_open(irg, suffix, suffix1);
1862 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1864 construct_block_lists(irg);
1866 for (i = 0; i < get_irp_n_irgs(); i++) {
1867 ir_node **arr = ird_get_irg_link(get_irp_irg(i));
1869 dump_graph(f, get_irp_irg(i));
1877 /** dumps a graph with type information
1880 dump_ir_graph_w_types (ir_graph *irg, const char *suffix)
1883 ir_graph *rem = current_ir_graph;
1886 /* if a filter is set, dump only the irg's that match the filter */
1887 if (strncmp(get_entity_name(get_irg_entity(irg)), dump_file_filter, strlen(dump_file_filter)) != 0)
1890 current_ir_graph = irg;
1892 if (get_interprocedural_view()) suffix1 = "-pure-wtypes-ip";
1893 else suffix1 = "-pure-wtypes";
1894 f = vcg_open(irg,suffix, suffix1);
1895 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1897 /* dump common ir graph */
1898 irg_walk(get_irg_end(irg), NULL, dump_whole_node, f);
1899 /* dump type info */
1900 type_walk_irg(irg, dump_type_info, NULL, f);
1901 inc_irg_visited(get_const_code_irg());
1902 /* dump edges from graph to type info */
1903 irg_walk(get_irg_end(irg), dump_node2type_edges, NULL, f);
1906 current_ir_graph = rem;
1910 dump_ir_block_graph_w_types (ir_graph *irg, const char *suffix)
1915 ir_graph *rem = current_ir_graph;
1917 /* if a filter is set, dump only the irg's that match the filter */
1918 if (strncmp(get_entity_name(get_irg_entity(irg)), dump_file_filter, strlen(dump_file_filter)) != 0)
1921 if (get_interprocedural_view()) suffix1 = "-wtypes-ip";
1922 else suffix1 = "-wtypes";
1923 f = vcg_open(irg, suffix, suffix1);
1924 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
1926 /* dump common blocked ir graph */
1927 construct_block_lists(irg);
1929 for (i = 0; i < get_irp_n_irgs(); i++) {
1930 ir_node **arr = ird_get_irg_link(get_irp_irg(i));
1932 dump_graph(f, get_irp_irg(i));
1937 /* dump type info */
1938 current_ir_graph = irg;
1939 type_walk_irg(irg, dump_type_info, NULL, f);
1940 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);
1945 current_ir_graph = rem;
1949 /*---------------------------------------------------------------------*/
1950 /* The following routines dump a control flow graph. */
1951 /*---------------------------------------------------------------------*/
1954 dump_block_to_cfg(ir_node *block, void *env) {
1959 if (is_Block(block)) {
1960 /* This is a block. Dump a node for the block. */
1961 fprintf (F, "node: {title: \""); PRINT_NODEID(block);
1962 fprintf (F, "\" label: \"");
1963 if (block == get_irg_start_block(get_irn_irg(block)))
1964 fprintf(F, "Start ");
1965 if (block == get_irg_end_block(get_irn_irg(block)))
1968 fprintf (F, "%s ", get_op_name(get_irn_op(block)));
1969 PRINT_NODEID(block);
1971 fprintf(F, "info1:\"");
1972 if (dump_dominator_information_flag)
1973 fprintf(F, "dom depth %d\n", get_Block_dom_depth(block));
1975 /* show arity and possible Bad predecessors of the block */
1976 fprintf(F, "arity: %d\n", get_Block_n_cfgpreds(block));
1977 for (fl = i = 0; i < get_Block_n_cfgpreds(block); ++i) {
1978 ir_node *pred = get_Block_cfgpred(block, i);
1981 fprintf(F, "Bad pred at pos: ");
1982 fprintf(F, "%d ", i);
1989 fprintf (F, "\""); /* closing quote of info */
1991 if ((block == get_irg_start_block(get_irn_irg(block))) ||
1992 (block == get_irg_end_block(get_irn_irg(block))) )
1993 fprintf(F, " color:blue ");
1995 fprintf(F, " color:yellow ");
1998 /* Dump the edges */
1999 for ( i = 0; i < get_Block_n_cfgpreds(block); i++)
2000 if (get_irn_op(skip_Proj(get_Block_cfgpred(block, i))) != op_Bad) {
2001 pred = get_nodes_block(skip_Proj(get_Block_cfgpred(block, i)));
2002 fprintf (F, "edge: { sourcename: \"");
2003 PRINT_NODEID(block);
2004 fprintf (F, "\" targetname: \"");
2006 fprintf (F, "\"}\n");
2009 /* Dump dominator edge */
2010 if (dump_dominator_information_flag && get_Block_idom(block)) {
2011 pred = get_Block_idom(block);
2012 fprintf (F, "edge: { sourcename: \"");
2013 PRINT_NODEID(block);
2014 fprintf (F, "\" targetname: \"");
2016 fprintf (F, "\" " DOMINATOR_EDGE_ATTR "}\n");
2022 dump_cfg (ir_graph *irg, const char *suffix)
2025 ir_graph *rem = current_ir_graph;
2026 int ddif = dump_dominator_information_flag;
2027 int ipv = get_interprocedural_view();
2029 /* if a filter is set, dump only the irg's that match the filter */
2030 if (strncmp(get_entity_name(get_irg_entity(irg)), dump_file_filter, strlen(dump_file_filter)) != 0)
2033 current_ir_graph = irg;
2035 f = vcg_open(irg, suffix, "-cfg");
2036 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
2039 printf("Warning: dumping cfg not in interprocedural view!\n");
2040 set_interprocedural_view(false);
2043 if (get_irg_dom_state(irg) != dom_consistent)
2044 dump_dominator_information_flag = 0;
2046 /* walk over the blocks in the graph */
2047 irg_block_walk(get_irg_end(irg), dump_block_to_cfg, NULL, f);
2048 dump_node(f, get_irg_bad(irg));
2050 dump_dominator_information_flag = ddif;
2051 set_interprocedural_view(ipv);
2053 current_ir_graph = rem;
2056 static int weight_overall(int rec, int loop) {
2057 return 2*rec + loop;
2060 static int compute_color (int my, int max) {
2065 /* if small, scale to the full color range. */
2067 my = my * (n_colors/max);
2069 int step = 1 + (max / n_colors);
2073 return base_color + n_colors - color;
2076 static int get_entity_color(entity *ent) {
2077 assert(get_entity_irg(ent));
2078 ir_graph *irg = get_entity_irg(ent);
2080 int rec_depth = get_irg_recursion_depth(irg);
2081 int loop_depth = get_irg_loop_depth(irg);
2082 int overall_depth = weight_overall(rec_depth, loop_depth);
2084 int max_rec_depth = irp->max_callgraph_recursion_depth;
2085 int max_loop_depth = irp->max_callgraph_loop_depth;
2086 int max_overall_depth = weight_overall(max_rec_depth, max_loop_depth);
2088 /* int my_rec_color = compute_color(rec_depth, max_rec_depth); */
2089 /* int my_loop_color = compute_color(loop_depth, max_loop_depth); */
2090 int my_overall_color = compute_color(overall_depth, max_overall_depth);;
2092 return my_overall_color;
2095 void dump_callgraph(const char *suffix) {
2097 int i, n_irgs = get_irp_n_irgs();
2098 int rem = edge_label;
2100 //ident *prefix = new_id_from_str("java/");
2102 F = vcg_open_name("Callgraph", suffix);
2103 dump_vcg_header(F, "Callgraph", NULL);
2105 for (i = 0; i < n_irgs; ++i) {
2106 ir_graph *irg = get_irp_irg(i);
2107 entity *ent = get_irg_entity(irg);
2108 int j, n_callees = get_irg_n_callees(irg);
2110 /* Do not dump runtime system. */
2111 //if (id_is_prefix(prefix, get_entity_ld_ident(ent))) continue;
2113 dump_entity_node(F, ent, get_entity_color(ent));
2114 for (j = 0; j < n_callees; ++j) {
2115 entity *c = get_irg_entity(get_irg_callee(irg, j));
2116 //if (id_is_prefix(prefix, get_entity_ld_ident(c))) continue;
2117 int be = is_irg_callee_backedge(irg, j);
2120 "label:\"recursion %d\" color: %d" :
2121 "label:\"calls %d\" color: %d";
2122 print_ent_ent_edge(F, ent, c, be, attr, get_irg_callee_loop_depth(irg, j), get_entity_color(ent));
2130 /* Dump all irgs in interprocedural view to a single file. */
2131 void dump_all_cg_block_graph(const char *suffix) {
2134 int rem_view = get_interprocedural_view();
2135 set_interprocedural_view(true);
2137 f = vcg_open_name("All_graphs", suffix);
2138 dump_vcg_header(f, "All_graphs", NULL);
2140 /* collect nodes in all irgs reachable in call graph*/
2141 for (i = 0; i < get_irp_n_irgs(); i++)
2142 ird_set_irg_link(get_irp_irg(i), NULL);
2144 cg_walk(clear_link, collect_node, NULL);
2146 /* dump all graphs */
2147 for (i = 0; i < get_irp_n_irgs(); i++) {
2148 current_ir_graph = get_irp_irg(i);
2149 assert(ird_get_irg_link(current_ir_graph));
2150 dump_graph(f, current_ir_graph);
2151 DEL_ARR_F(ird_get_irg_link(current_ir_graph));
2155 set_interprocedural_view(rem_view);
2158 /***********************************************************************/
2159 /* the following routines dumps type information without any ir nodes. */
2160 /***********************************************************************/
2163 dump_type_graph (ir_graph *irg, const char *suffix)
2167 rem = current_ir_graph;
2169 /* if a filter is set, dump only the irg's that match the filter */
2170 if (strncmp(get_entity_name(get_irg_entity(irg)), dump_file_filter, strlen(dump_file_filter)) != 0) return;
2172 current_ir_graph = irg;
2174 f = vcg_open(irg, suffix, "-type");
2175 dump_vcg_header(f, get_irg_dump_name(irg), NULL);
2177 /* walk over the blocks in the graph */
2178 type_walk_irg(irg, dump_type_info, NULL, f);
2179 /* The walker for the const code can be called several times for the
2180 same (sub) experssion. So that no nodes are dumped several times
2181 we decrease the visited flag of the corresponding graph after each
2182 walk. So now increase it finally. */
2183 inc_irg_visited(get_const_code_irg());
2186 current_ir_graph = rem;
2190 dump_all_types (const char *suffix)
2192 FILE *f = vcg_open_name("All_types", suffix);
2193 dump_vcg_header(f, "All_types", NULL);
2194 type_walk(dump_type_info, NULL, f);
2195 inc_irg_visited(get_const_code_irg());
2200 dump_class_hierarchy (bool entities, const char *suffix)
2202 FILE *f = vcg_open_name("class_hierarchy", suffix);
2206 dump_vcg_header(f, "class_hierarchy", NULL);
2211 type_walk(dump_class_hierarchy_node, NULL, &env);
2215 /***********************************************************************/
2216 /* dumps all graphs with the graph-dumper passed. Possible dumpers: */
2218 /* dump_ir_block_graph */
2220 /* dump_type_graph */
2221 /* dump_ir_graph_w_types */
2222 /***********************************************************************/
2224 void dump_all_ir_graphs(dump_graph_func *dmp_grph, const char *suffix) {
2225 int i, n_irgs = get_irp_n_irgs();
2226 for (i = 0; i < n_irgs; ++i) {
2227 dmp_grph(get_irp_irg(i), suffix);
2232 /**********************************************************************************
2233 * Dumps a stand alone loop graph with firm nodes which belong to one loop node *
2234 * packed together in one subgraph/box *
2235 **********************************************************************************/
2237 void dump_loops_standalone(FILE *F, ir_loop *loop) {
2238 int i = 0, loop_node_started = 0, son_number = 0, first = 0;
2240 ir_loop *son = NULL;
2242 /* Dump a new loop node. */
2243 dump_loop_node(F, loop);
2245 /* Dump the loop elements. */
2247 for(i = 0; i < get_loop_n_elements(loop); i++) {
2248 le = get_loop_element(loop, i);
2250 if (get_kind(son) == k_ir_loop) {
2252 /* We are a loop son -> Recurse */
2254 if(loop_node_started) { /* Close the "firm-nodes" node first if we started one. */
2255 fprintf(F, "\" }\n");
2256 fprintf (F, "edge: {sourcename: \"");
2258 fprintf (F, "\" targetname: \"");
2260 fprintf (F, "-%d-nodes\" label:\"%d...%d\"}\n", first, first, i-1);
2261 loop_node_started = 0;
2263 dump_loop_son_edge(F, loop, son_number++);
2264 dump_loops_standalone(F, son);
2265 } else if (get_kind(son) == k_ir_node) {
2266 /* We are a loop node -> Collect firm nodes */
2268 ir_node *n = le.node;
2271 if (!loop_node_started) {
2272 /* Start a new node which contains all firm nodes of the current loop */
2273 fprintf (F, "node: { title: \"");
2275 fprintf (F, "-%d-nodes\" color: lightyellow label: \"", i);
2276 loop_node_started = 1;
2282 bad |= dump_node_opcode(F, n);
2283 bad |= dump_node_mode(F, n);
2284 bad |= dump_node_typeinfo(F, n);
2286 bad |= dump_node_nodeattr(F, n);
2287 fprintf (F, " %ld", get_irn_node_nr(n));
2288 if (is_Block(n)) fprintf (F, "\t ->%d", (int)get_irn_link(n));
2289 if (has_backedges(n)) fprintf(F, "\t loop head!");
2290 } else { /* for callgraph loop tree */
2291 assert(get_kind(son) == k_ir_graph);
2292 /* We are a loop node -> Collect firm graphs */
2293 ir_graph *n = (ir_graph *)le.node;
2294 if (!loop_node_started) {
2295 /* Start a new node which contains all firm nodes of the current loop */
2296 fprintf (F, "node: { title: \"");
2298 fprintf (F, "-%d-nodes\" color: lightyellow label: \"", i);
2299 loop_node_started = 1;
2304 fprintf (F, " %s", get_irg_dump_name(n));
2305 /* fprintf (F, " %s (depth %d)", get_irg_dump_name(n), n->callgraph_weighted_loop_depth); */
2309 if (loop_node_started) {
2310 fprintf(F, "\" }\n");
2311 fprintf (F, "edge: {sourcename: \"");
2313 fprintf (F, "\" targetname: \"");
2315 fprintf (F, "-%d-nodes\" label:\"%d...%d\"}\n", first, first, i-1);
2316 loop_node_started = 0;
2320 void dump_loop_tree(ir_graph *irg, const char *suffix)
2323 ir_graph *rem = current_ir_graph;
2324 int el_rem = edge_label;
2327 /* if a filter is set, dump only the irg's that match the filter */
2328 if (strncmp(get_entity_name(get_irg_entity(irg)), dump_file_filter, strlen(dump_file_filter)) != 0)
2331 current_ir_graph = irg;
2333 f = vcg_open(irg, suffix, "-looptree");
2334 dump_vcg_header(f, get_irg_dump_name(irg), "top_to_bottom");
2336 if (get_irg_loop(irg)) dump_loops_standalone(f, get_irg_loop(irg));
2340 edge_label = el_rem;
2341 current_ir_graph = rem;
2344 void dump_callgraph_loop_tree(const char *suffix) {
2346 F = vcg_open_name("Callgraph_looptree", suffix);
2347 dump_vcg_header(F, "callgraph looptree", "top_to_bottom");
2348 dump_loops_standalone(F, irp->outermost_cg_loop);
2353 /*******************************************************************************/
2354 /* Dumps the firm nodes in the loop tree to a graph along with the loop nodes. */
2355 /*******************************************************************************/
2357 void collect_nodeloop(FILE *F, ir_loop *loop, eset *loopnodes) {
2358 int i, son_number = 0, node_number = 0;
2360 if (dump_loop_information_flag) dump_loop_node(F, loop);
2362 for (i = 0; i < get_loop_n_elements(loop); i++) {
2363 loop_element le = get_loop_element(loop, i);
2364 if (*(le.kind) == k_ir_loop) {
2365 if (dump_loop_information_flag) dump_loop_son_edge(F, loop, son_number++);
2367 collect_nodeloop(F, le.son, loopnodes);
2369 if (dump_loop_information_flag) dump_loop_node_edge(F, loop, node_number++);
2370 eset_insert(loopnodes, le.node);
2375 void collect_nodeloop_external_nodes(ir_loop *loop, eset *loopnodes, eset *extnodes) {
2378 for(i = 0; i < get_loop_n_elements(loop); i++) {
2379 loop_element le = get_loop_element(loop, i);
2380 if (*(le.kind) == k_ir_loop) {
2382 collect_nodeloop_external_nodes(le.son, loopnodes, extnodes);
2384 if (is_Block(le.node)) start = 0; else start = -1;
2385 for (j = start; j < get_irn_arity(le.node); j++) {
2386 ir_node *pred = get_irn_n(le.node, j);
2387 if (!eset_contains(loopnodes, pred)) {
2388 eset_insert(extnodes, pred);
2389 if (!is_Block(pred)) {
2390 pred = get_nodes_block(pred);
2391 if (!eset_contains(loopnodes, pred)) eset_insert(extnodes, pred);
2399 void dump_loop(ir_loop *l, const char *suffix) {
2402 eset *loopnodes = eset_create();
2403 eset *extnodes = eset_create();
2406 snprintf(name, sizeof(name), "loop_%d", get_loop_loop_nr(l));
2407 F = vcg_open_name (name, suffix);
2408 dump_vcg_header(F, name, NULL);
2410 /* collect all nodes to dump */
2411 collect_nodeloop(F, l, loopnodes);
2412 collect_nodeloop_external_nodes(l, loopnodes, extnodes);
2414 /* build block lists */
2415 for (n = eset_first(loopnodes); n != NULL; n = eset_next(loopnodes))
2416 set_irn_link(n, NULL);
2417 for (n = eset_first(extnodes); n != NULL; n = eset_next(extnodes))
2418 set_irn_link(n, NULL);
2419 for (n = eset_first(loopnodes); n != NULL; n = eset_next(loopnodes))
2421 b = get_nodes_block(n);
2422 set_irn_link(n, get_irn_link(b));
2425 for (n = eset_first(extnodes); n != NULL; n = eset_next(extnodes))
2427 b = get_nodes_block(n);
2428 set_irn_link(n, get_irn_link(b));
2432 for (b = eset_first(loopnodes); b != NULL; b = eset_next(loopnodes))
2434 fprintf(F, "graph: { title: \"");
2436 fprintf(F, "\" label: \"");
2437 dump_node_opcode(F, b);
2438 fprintf (F, " %ld", get_irn_node_nr(b));
2439 fprintf(F, "\" status:clustered color:yellow\n");
2441 /* dump the blocks edges */
2442 dump_ir_data_edges(F, b);
2444 /* dump the nodes that go into the block */
2445 for (n = get_irn_link(b); n; n = get_irn_link(n)) {
2446 if (eset_contains(extnodes, n)) overrule_nodecolor = "lightblue";
2448 overrule_nodecolor = NULL;
2449 if (!eset_contains(extnodes, n)) dump_ir_data_edges(F, n);
2452 /* Close the vcg information for the block */
2454 dump_const_node_local(F, b);
2457 for (b = eset_first(extnodes); b != NULL; b = eset_next(extnodes))
2459 fprintf(F, "graph: { title: \"");
2461 fprintf(F, "\" label: \"");
2462 dump_node_opcode(F, b);
2463 fprintf (F, " %ld", get_irn_node_nr(b));
2464 fprintf(F, "\" status:clustered color:lightblue\n");
2466 /* dump the nodes that go into the block */
2467 for (n = get_irn_link(b); n; n = get_irn_link(n)) {
2468 if (!eset_contains(loopnodes, n)) overrule_nodecolor = "lightblue";
2470 overrule_nodecolor = NULL;
2471 if (eset_contains(loopnodes, n)) dump_ir_data_edges(F, n);
2474 /* Close the vcg information for the block */
2476 dump_const_node_local(F, b);
2480 eset_destroy(loopnodes);
2481 eset_destroy(extnodes);