some simple optimizations for execution speed
[libfirm] / ir / ir / irdump.c
index 28ac36c..8275388 100644 (file)
 # include "panic.h"
 # include "array.h"
 # include "pmap.h"
+# include "eset.h"
 
-# include "exc.h"
-
-/*define HEAPANAL */
+#undef HEAPANAL
 #ifdef HEAPANAL
 void dump_chi_term(FILE *FL, ir_node *n);
 void dump_state(FILE *FL, ir_node *n);
@@ -57,9 +56,9 @@ SeqNo get_Block_seqno(ir_node *n);
 #define DEFAULT_TYPE_ATTRIBUTE " "
 
 /* Attributes of edges between Firm nodes */
-#define BLOCK_EDGE_ATTR "class: 2 priority: 2 linestyle: dotted"
-#define CF_EDGE_ATTR    "color: red"
-#define MEM_EDGE_ATTR   "color: blue"
+#define BLOCK_EDGE_ATTR     "class: 2 priority: 2 linestyle: dotted"
+#define CF_EDGE_ATTR        "color: red"
+#define MEM_EDGE_ATTR       "color: blue"
 #define DOMINATOR_EDGE_ATTR "color: red"
 
 #define BACK_EDGE_ATTR "linestyle: dashed "
@@ -93,6 +92,7 @@ SeqNo get_Block_seqno(ir_node *n);
 #define PRINT_ENTID(X)  fprintf(F, "e%ld", get_entity_nr(X))
 #define PRINT_IRGID(X)  fprintf(F, "g%ld", get_irg_graph_nr(X))
 #define PRINT_CONSTID(X,Y) fprintf(F, "\"n%ldn%ld\"", get_irn_node_nr(X),get_irn_node_nr(Y))
+#define PRINT_LOOPID(X) fprintf(F, "l%d", get_loop_loop_nr(X))
 
 #else
 #define PRINT_NODEID(X) fprintf(F, "n%p", (void*) X)
@@ -100,6 +100,7 @@ SeqNo get_Block_seqno(ir_node *n);
 #define PRINT_ENTID(X)  fprintf(F, "e%p", (void*) X)
 #define PRINT_IRGID(X)  fprintf(F, "g%p",(void*) X)
 #define PRINT_CONSTID(X,Y) fprintf(F, "\"n%pn%p\"", (void*) X, (void*) Y)
+#define PRINT_LOOPID(X) fprintf(F, "l%p", (void *)X)
 #endif
 
 static void print_type_type_edge(FILE *F, type *S, type *T, const char *fmt, ...)
@@ -198,7 +199,7 @@ char *dump_file_suffix = "";
 static FILE *F;
 
 static void dump_whole_node(ir_node *n, void* env);
-static INLINE void dump_loop_info(ir_graph *irg);
+static INLINE void dump_loop_nodes_into_graph(ir_graph *irg);
 
 /*******************************************************************/
 /* Helper functions.                                                */
@@ -254,11 +255,16 @@ static int node_floats(ir_node *n) {
          (get_irg_pinned(current_ir_graph) == floats));
 }
 
-static ident *get_irg_dump_name (ir_graph *irg) {
+static const char *get_ent_dump_name (entity *ent) {
+  /* Don't use get_entity_ld_ident (ent) as it computes the mangled name! */
+  if (ent->ld_name) return get_id_str(ent->ld_name);
+  return get_id_str(ent->name);
+}
+
+static const char *get_irg_dump_name (ir_graph *irg) {
   /* Don't use get_entity_ld_ident (ent) as it computes the mangled name! */
   entity *ent = get_irg_ent(irg);
-  if (ent->ld_name) return ent->ld_name;
-  return ent->name;
+  return get_ent_dump_name(ent);
 }
 
 static void collect_node(ir_node * node, void *env) {
@@ -317,6 +323,8 @@ int dump_const_local = 0;
 bool opt_dump_analysed_type_info = 1;
 bool opt_dump_pointer_values_to_info = 0;  /* default off: for test compares!! */
 
+char* overrule_nodecolor = NULL;
+
 INLINE bool get_opt_dump_const_local(void) {
   if (!dump_out_edge_flag && !dump_loop_information_flag)
     return dump_const_local;
@@ -418,7 +426,7 @@ dump_node_opcode (ir_node *n)
 
   case iro_Start: {
     if (interprocedural_view) {
-      fprintf(F, "%s %s", get_irn_opname(n), get_entity_name(get_irg_ent(get_irn_irg(n))));
+      fprintf(F, "%s %s", get_irn_opname(n), get_ent_dump_name(get_irg_ent(get_irn_irg(n))));
       break;
     }
   } /* fall through */
@@ -477,7 +485,7 @@ dump_node_nodeattr (ir_node *n)
   switch (get_irn_opcode(n)) {
   case iro_Start:
     if (false && interprocedural_view) {
-      fprintf (F, "%s", get_entity_name(get_irg_ent(current_ir_graph)));
+      fprintf (F, "%s", get_ent_dump_name(get_irg_ent(current_ir_graph)));
     }
     break;
   case iro_Proj:
@@ -491,7 +499,7 @@ dump_node_nodeattr (ir_node *n)
     fprintf (F, "%ld", get_Filter_proj(n));
     break;
   case iro_Sel: {
-    fprintf (F, "%s", get_entity_name(get_Sel_entity(n)));
+    fprintf (F, "%s", get_ent_dump_name(get_Sel_entity(n)));
     } break;
   case iro_Cast: {
     fprintf (F, "(%s)", get_type_name(get_Cast_type(n)));
@@ -532,11 +540,14 @@ dump_node_vcgattr (ir_node *n)
   default:
     PRINT_DEFAULT_NODE_ATTR;
   }
+
+  if (overrule_nodecolor) fprintf(F, " color: %s", overrule_nodecolor);
 }
 
 static INLINE void
 dump_node_info (ir_node *n) {
   int i;
+  char comma;
   ir_graph *irg;
   fprintf (F, " info1: \"");
   if (opt_dump_pointer_values_to_info)
@@ -544,7 +555,19 @@ dump_node_info (ir_node *n) {
   fprintf (F, "visited: %ld \n", get_irn_visited(n));
   irg = get_irn_irg(n);
   if (irg != get_const_code_irg())
-    fprintf (F, "irg:     %s\n", get_entity_name(get_irg_entity(irg)));
+    fprintf (F, "irg:     %s\n", get_ent_dump_name(get_irg_entity(irg)));
+
+  fprintf(F, "arity: %d", get_irn_arity(n));
+  if ((get_irn_op(n) == op_Block) ||
+      (get_irn_op(n) == op_Phi) ||
+      ((get_irn_op(n) == op_Filter) && interprocedural_view)) {
+    fprintf(F, " backedges:");
+    comma = ' ';
+    for (i = 0; i < get_irn_arity(n); i++)
+      if (is_backedge(n, i)) { fprintf(F, "%c %d", comma, i); comma = ','; }
+  }
+  fprintf(F, "\n");
+
 
   /* Source types */
   switch (get_irn_opcode(n)) {
@@ -571,6 +594,29 @@ dump_node_info (ir_node *n) {
       fprintf(F, "  param %d type: %s \n", i, get_type_name(get_method_param_type(tp, i)));
     for (i = 0; i < get_method_n_ress(tp); ++i)
       fprintf(F, "  resul %d type: %s \n", i, get_type_name(get_method_res_type(tp, i)));
+    if (Call_has_callees(n)) {
+      fprintf(F, "possible callees: \n");
+      for (i = 0; i < get_Call_n_callees(n); i++) {
+       if (!get_Call_callee(n, i)) {
+         fprintf(F, "  %d external method\n", i);
+       } else {
+         fprintf(F, "  %d: %s\n", i, get_ent_dump_name(get_Call_callee(n, i)));
+       }
+      }
+    }
+  } break;
+  case iro_CallBegin: {
+    ir_node *call = get_CallBegin_call(n);
+    if (Call_has_callees(call)) {
+      fprintf(F, "possible callees: \n");
+      for (i = 0; i < get_Call_n_callees(call); i++) {
+       if (!get_Call_callee(call, i)) {
+         fprintf(F, "  %d external method\n", i);
+       } else {
+         fprintf(F, "  %d: %s\n", i, get_ent_dump_name(get_Call_callee(call, i)));
+       }
+      }
+    }
   } break;
   case iro_Return: {
     if (!interprocedural_view) {
@@ -598,7 +644,7 @@ dump_node_info (ir_node *n) {
       for (i = 0; i < get_irn_inter_arity(n); i++) {
        ir_node *pred = get_irn_inter_n(n, i);
        fprintf(F, "  %s%s %ld \tin graph %s\n", get_irn_opname(pred), get_irn_modename(pred),
-               get_irn_node_nr(pred), get_entity_name(get_irg_entity(get_irn_irg(pred))));
+               get_irn_node_nr(pred), get_ent_dump_name(get_irg_entity(get_irn_irg(pred))));
       }
     }
   } break;
@@ -881,9 +927,6 @@ dump_whole_block(ir_node *block) {
 
   /* dump the blocks edges */
   dump_ir_data_edges(block);
-#ifdef HEAPANAL
-  dump_chi_term(F, block);
-#endif
 
   /* dump the nodes that go into the block */
   for (node = ird_get_irn_link(block); node; node = ird_get_irn_link(node)) {
@@ -894,6 +937,9 @@ dump_whole_block(ir_node *block) {
   /* Close the vcg information for the block */
   fprintf(F, "}\n");
   dump_const_node_local(block);
+#ifdef HEAPANAL
+  dump_chi_term(F, block);
+#endif
   fprintf(F, "\n");
 }
 
@@ -919,7 +965,7 @@ dump_block_graph (ir_graph *irg) {
     }
   }
 
-  if (dump_loop_information_flag) dump_loop_info(irg);
+  if (dump_loop_information_flag) dump_loop_nodes_into_graph(irg);
 
   current_ir_graph = rem;
 }
@@ -932,7 +978,7 @@ static void dump_graph(ir_graph *irg) {
   fprintf(F, "graph: { title: \"");
   PRINT_IRGID(irg);
   fprintf(F, "\" label: \"%s\" status:clustered color:white \n",
-         get_entity_name(get_irg_ent(irg)));
+         get_ent_dump_name(get_irg_ent(irg)));
 
   dump_block_graph (irg);
 
@@ -1079,7 +1125,7 @@ void dump_entity_node(entity *ent)
   PRINT_ENTID(ent); fprintf(F, "\"");
   fprintf (F, DEFAULT_TYPE_ATTRIBUTE);
   fprintf (F, "label: ");
-  fprintf (F, "\"ent %s\" " ENTITY_NODE_ATTR , get_entity_name(ent));
+  fprintf (F, "\"ent %s\" " ENTITY_NODE_ATTR , get_ent_dump_name(ent));
   fprintf (F, "\n info1: \"\nid: "); PRINT_ENTID(ent);
 
   fprintf (F, "\nallocation:  ");
@@ -1113,7 +1159,7 @@ void dump_entity_node(entity *ent)
 
   fprintf(F, "\npeculiarity: %s", get_peculiarity_string(get_entity_peculiarity(ent)));
   fprintf(F, "\nname:    %s\nld_name: %s",
-         get_entity_name(ent), ent->ld_name ? get_entity_ld_name(ent) : "no yet set");
+         get_ent_dump_name(ent), ent->ld_name ? get_entity_ld_name(ent) : "no yet set");
   fprintf(F, "\noffset:  %d", get_entity_offset(ent));
   if (is_method_type(get_entity_type(ent))) {
     if (get_entity_irg(ent))   /* can be null */
@@ -1318,10 +1364,39 @@ dump_out_edge (ir_node *n, void* env) {
   }
 }
 
+static INLINE void
+dump_loop_label(ir_loop *loop) {
+  fprintf (F, "loop %d, %d sons, %d nodes",
+          get_loop_depth(loop), get_loop_n_sons(loop), get_loop_n_nodes(loop));
+}
+
+static INLINE void dump_loop_info(ir_loop *loop) {
+  fprintf (F, " info1: \"");
+  fprintf (F, " loop nr: %d", get_loop_loop_nr(loop));
+#if DEBUG_libfirm   /* GL @@@ debug analyses */
+  fprintf (F, "\n The loop was analyzed %d times.", (int)get_loop_link(loop));
+#endif
+  fprintf (F, "\"");
+}
+
+static INLINE void
+dump_loop_node(ir_loop *loop) {
+  fprintf (F, "node: {title: \"");
+  PRINT_LOOPID(loop);
+  fprintf (F, "\" label: \"");
+  dump_loop_label(loop);
+  fprintf (F, "\" ");
+  dump_loop_info(loop);
+  fprintf (F, "}\n");
+
+}
+
 static INLINE void
 dump_loop_node_edge (ir_loop *loop, int i) {
   assert(loop);
-  fprintf (F, "edge: {sourcename: \"%p\" targetname: \"", (void*) loop);
+  fprintf (F, "edge: {sourcename: \"");
+  PRINT_LOOPID(loop);
+  fprintf (F, "\" targetname: \"");
   PRINT_NODEID(get_loop_node(loop, i));
   fprintf (F, "\" color: green");
   fprintf (F, "}\n");
@@ -1330,16 +1405,20 @@ dump_loop_node_edge (ir_loop *loop, int i) {
 static INLINE void
 dump_loop_son_edge (ir_loop *loop, int i) {
   assert(loop);
-  fprintf (F, "edge: {sourcename: \"%p\" targetname: \"%p\" color: darkgreen}\n",
-          (void *)loop, (void *)get_loop_son(loop, i));
+  fprintf (F, "edge: {sourcename: \"");
+  PRINT_LOOPID(loop);
+  fprintf (F, "\" targetname: \"");
+  PRINT_LOOPID(get_loop_son(loop, i));
+  fprintf (F, "\" color: darkgreen label: \"%d\"}\n",
+          get_loop_element_pos(loop, get_loop_son(loop, i)));
 }
 
 static
 void dump_loops (ir_loop *loop) {
   int i;
   /* dump this loop node */
-  fprintf (F, "node: {title: \"%p\" label: \"loop %d, %d sons, %d nodes\" }\n",
-           (void*)loop, get_loop_depth(loop), get_loop_n_sons(loop), get_loop_n_nodes(loop));
+  dump_loop_node(loop);
+
   /* dump edges to nodes in loop -- only if it is a real loop */
   if (get_loop_depth(loop) != 0) {
     for (i = 0; i < get_loop_n_nodes(loop); i++) {
@@ -1353,7 +1432,7 @@ void dump_loops (ir_loop *loop) {
 }
 
 static INLINE
-void dump_loop_info(ir_graph *irg) {
+void dump_loop_nodes_into_graph(ir_graph *irg) {
   ir_graph *rem = current_ir_graph;
   current_ir_graph = irg;
 
@@ -1368,14 +1447,17 @@ void dump_loop_info(ir_graph *irg) {
 /************************************************************************/
 
 static INLINE void
-dump_vcg_header(const char *name) {
+dump_vcg_header(const char *name, const char *orientation) {
   char *label;
+
   if (edge_label) {
     label = "yes";
   } else {
     label = "no";
   }
 
+  if (!orientation) orientation = "bottom_to_top";
+
   /* print header */
   fprintf (F,
           "graph: { title: \"ir graph of %s\"\n"
@@ -1383,7 +1465,7 @@ dump_vcg_header(const char *name) {
           "layoutalgorithm: mindepth\n"
           "manhattan_edges: yes\n"
           "port_sharing: no\n"
-          "orientation: bottom_to_top\n"
+          "orientation: %s\n"
           "classname 1: \"Data\"\n"
           "classname 2: \"Block\"\n"
           "classname 3: \"Entity type\"\n"
@@ -1396,14 +1478,14 @@ dump_vcg_header(const char *name) {
           "classname 10: \"Array Element Type\"\n"
           "classname 11: \"Overwrites\"\n"
           "classname 12: \"Member\"\n",
-          name, label);
+          name, label, orientation);
 
   fprintf (F, "\n");           /* a separator */
 }
 
 static void vcg_open (ir_graph *irg, char * suffix1, char *suffix2) {
-  ident *id = get_irg_dump_name(irg);
-  int len = get_id_strlen(id);
+  const char *nm = get_irg_dump_name(irg);
+  int len = strlen(nm);
   char *fname;  /* filename to put the vcg information in */
 
   if (!suffix1) suffix1 = "";
@@ -1411,7 +1493,7 @@ static void vcg_open (ir_graph *irg, char * suffix1, char *suffix2) {
 
   /** open file for vcg graph */
   fname = malloc (len + strlen(suffix1) + strlen(suffix2) + 5);
-  strncpy (fname, get_id_str(id), len);      /* copy the filename */
+  strncpy (fname, nm, len);      /* copy the filename */
   fname[len] = '\0';
   strcat (fname, suffix1);  /* append file suffix */
   strcat (fname, suffix2);  /* append file suffix */
@@ -1421,8 +1503,6 @@ static void vcg_open (ir_graph *irg, char * suffix1, char *suffix2) {
     panic ("cannot open %s for writing (%m)", fname);  /* not reached */
   }
   free(fname);
-
-  dump_vcg_header(get_id_str(id));
 }
 
 static void vcg_open_name (const char *name, char *suffix) {
@@ -1439,14 +1519,16 @@ static void vcg_open_name (const char *name, char *suffix) {
   if (!F) {
     panic ("cannot open %s for writing (%m)", fname);  /* not reached */
   }
-
   free(fname);
-  dump_vcg_header(name);
+}
+
+static INLINE void dump_vcg_footer (void) {
+  fprintf (F, "}\n");
 }
 
 static void
 vcg_close (void) {
-  fprintf (F, "}\n");  /* print footer */
+  dump_vcg_footer();    /* print footer */
   fclose (F);           /* close vcg file */
 }
 
@@ -1473,6 +1555,7 @@ dump_ir_graph (ir_graph *irg)
   if (interprocedural_view) suffix = "-pure-ip";
   else                      suffix = "-pure";
   vcg_open (irg, dump_file_suffix, suffix);
+  dump_vcg_header(get_irg_dump_name(irg), NULL);
 
   /* walk over the graph */
   /* dump_whole_node must be called in post visiting predecessors */
@@ -1498,6 +1581,7 @@ dump_ir_block_graph (ir_graph *irg)
   if (interprocedural_view) suffix = "-ip";
   else                      suffix = "";
   vcg_open (irg, dump_file_suffix, suffix);
+  dump_vcg_header(get_irg_dump_name(irg), NULL);
 
   construct_block_lists(irg);
 
@@ -1524,6 +1608,7 @@ dump_ir_graph_w_types (ir_graph *irg)
   if (interprocedural_view) suffix = "-pure-wtypes-ip";
   else                      suffix = "-pure-wtypes";
   vcg_open (irg, dump_file_suffix, suffix);
+  dump_vcg_header(get_irg_dump_name(irg), NULL);
 
   /* dump common ir graph */
   irg_walk(get_irg_end(irg), NULL, dump_whole_node, NULL);
@@ -1547,6 +1632,7 @@ dump_ir_block_graph_w_types (ir_graph *irg)
   if (interprocedural_view) suffix = "-wtypes-ip";
   else                      suffix = "-wtypes";
   vcg_open (irg, dump_file_suffix, suffix);
+  dump_vcg_header(get_irg_dump_name(irg), NULL);
 
   /* dump common blocked ir graph */
   construct_block_lists(irg);
@@ -1621,6 +1707,7 @@ dump_cfg (ir_graph *irg)
   current_ir_graph = irg;
 
   vcg_open (irg, dump_file_suffix, "-cfg");
+  dump_vcg_header(get_irg_dump_name(irg), NULL);
 
   if (interprocedural_view) {
     printf("Warning: dumping cfg not in interprocedural view!\n");
@@ -1649,6 +1736,7 @@ void dump_all_cg_block_graph(void) {
   interprocedural_view = 1;
 
   vcg_open_name ("All_graphs", dump_file_suffix);
+  dump_vcg_header("All_graphs", NULL);
 
   /* collect nodes in all irgs reachable in call graph*/
   for (i = 0; i < get_irp_n_irgs(); i++)
@@ -1680,6 +1768,7 @@ dump_type_graph (ir_graph *irg)
   current_ir_graph = irg;
 
   vcg_open (irg, dump_file_suffix, "-type");
+  dump_vcg_header(get_irg_dump_name(irg), NULL);
 
   /* walk over the blocks in the graph */
   type_walk_irg(irg, dump_type_info, NULL, NULL);
@@ -1697,6 +1786,7 @@ void
 dump_all_types (void)
 {
   vcg_open_name ("All_types", dump_file_suffix);
+  dump_vcg_header("All_types", NULL);
   type_walk(dump_type_info, NULL, NULL);
   inc_irg_visited(get_const_code_irg());
   vcg_close();
@@ -1706,6 +1796,7 @@ void
 dump_class_hierarchy (bool entities)
 {
   vcg_open_name ("class_hierarchy", dump_file_suffix);
+  dump_vcg_header("class_hierarchy", NULL);
   if (entities)
     type_walk(dump_class_hierarchy_node, NULL, (void *)1);
   else
@@ -1728,3 +1819,232 @@ void dump_all_ir_graphs (dump_graph_func *dmp_grph) {
     dmp_grph(get_irp_irg(i));
   }
 }
+
+
+/**********************************************************************************
+ * Dumps a stand alone loop graph with firm nodes which belong to one loop nodes  *
+ * packed together in one subgraph                                                *
+ **********************************************************************************/
+
+
+
+void dump_loops_standalone (ir_loop *loop) {
+  int i, loop_node_started = 0, son_number = 0, first;
+  loop_element le;
+
+  /* Dump a new loop node. */
+  dump_loop_node(loop);
+
+  /* Dump the loop elements. */
+  for(i = 0; i < get_loop_n_elements(loop); i++)
+    {
+      le = get_loop_element(loop, i);
+
+      ir_loop *son = le.son;
+      if (get_kind(son) == k_ir_loop)
+       {
+         /* We are a loop son -> Recurse */
+
+         if(loop_node_started) /* Close the "firm-nodes" node first if we started one. */
+           {
+             fprintf(F, "\" }\n");
+             fprintf (F, "edge: {sourcename: \"");
+             PRINT_LOOPID(loop);
+             fprintf (F, "\" targetname: \"");
+             PRINT_LOOPID(loop);
+             fprintf (F, "-%d-nodes\" label:\"%d...%d\"}\n", first, first, i-1);
+             loop_node_started = 0;
+           }
+         dump_loop_son_edge(loop, son_number++);
+         dump_loops_standalone(son);
+       }
+      else
+       {
+         /* We are a loop node -> Collect firm nodes */
+
+         ir_node *n = le.node;
+
+         if (!loop_node_started)
+           {
+             /* Start a new node which contains all firm nodes of the current loop */
+             fprintf (F, "node: { title: \"");
+             PRINT_LOOPID(loop);
+             fprintf (F, "-%d-nodes\" color: lightyellow label: \"", i);
+             loop_node_started = 1;
+             first = i;
+           }
+         else
+           fprintf(F, "\n");
+
+         dump_node_opcode(n);
+         dump_node_mode (n);
+         dump_node_typeinfo(n);
+         fprintf (F, " ");
+         dump_node_nodeattr(n);
+         fprintf (F, " %ld", get_irn_node_nr(n));
+
+       }
+    }
+
+  if(loop_node_started)
+    {
+      fprintf(F, "\" }\n");
+      fprintf (F, "edge: {sourcename: \"");
+      PRINT_LOOPID(loop);
+      fprintf (F, "\" targetname: \"");
+      PRINT_LOOPID(loop);
+      fprintf (F, "-%d-nodes\" label:\"%d...%d\"}\n", first, first, i-1);
+      loop_node_started = 0;
+    }
+}
+
+void dump_loop_tree(ir_graph *irg, char *suffix)
+{
+  ir_graph *rem = current_ir_graph;
+  int el_rem = edge_label;
+  edge_label = 1;
+
+  current_ir_graph = irg;
+
+  vcg_open(irg, suffix, "-looptree");
+  dump_vcg_header(get_irg_dump_name(irg), "top_to_bottom");
+
+  if (get_irg_loop(irg)) dump_loops_standalone(get_irg_loop(irg));
+
+  vcg_close();
+
+  edge_label = el_rem;
+  current_ir_graph = rem;
+}
+
+
+/*******************************************************************************/
+/* Dumps the firm nodes in the loop tree to a graph along with the loop nodes. */
+/*******************************************************************************/
+
+void collect_nodeloop(ir_loop *loop, eset *loopnodes) {
+  int i, son_number = 0, node_number = 0;
+
+  if (dump_loop_information_flag) dump_loop_node(loop);
+
+  for (i = 0; i < get_loop_n_elements(loop); i++) {
+    loop_element le = get_loop_element(loop, i);
+    if (*(le.kind) == k_ir_loop) {
+      if (dump_loop_information_flag) dump_loop_son_edge(loop, son_number++);
+      /* Recur */
+      collect_nodeloop(le.son, loopnodes);
+    } else {
+      if (dump_loop_information_flag) dump_loop_node_edge(loop, node_number++);
+      eset_insert(loopnodes, le.node);
+    }
+  }
+}
+
+void collect_nodeloop_external_nodes(ir_loop *loop, eset *loopnodes, eset *extnodes) {
+  int i, j, start;
+
+  for(i = 0; i < get_loop_n_elements(loop); i++) {
+    loop_element le = get_loop_element(loop, i);
+    if (*(le.kind) == k_ir_loop) {
+      /* Recur */
+      collect_nodeloop_external_nodes(le.son, loopnodes, extnodes);
+    } else {
+      if (is_Block(le.node)) start = 0; else start = -1;
+      for (j = start; j < get_irn_arity(le.node); j++) {
+       ir_node *pred = get_irn_n(le.node, j);
+       if (!eset_contains(loopnodes, pred)) {
+         eset_insert(extnodes, pred);
+         if (!is_Block(pred)) {
+           pred = get_nodes_block(pred);
+           if (!eset_contains(loopnodes, pred)) eset_insert(extnodes, pred);
+          }
+       }
+      }
+    }
+  }
+}
+
+void dump_loop (ir_loop *l, char *suffix) {
+  char name[50];
+  eset *loopnodes = eset_create();
+  eset *extnodes = eset_create();
+  ir_node *n, *b;
+
+  sprintf(name, "loop_%d", get_loop_loop_nr(l));
+  vcg_open_name (name, suffix);
+  dump_vcg_header(name, NULL);
+
+  /* collect all nodes to dump */
+  collect_nodeloop(l, loopnodes);
+  collect_nodeloop_external_nodes(l, loopnodes, extnodes);
+
+  /* build block lists */
+  for (n = eset_first(loopnodes); n != NULL; n = eset_next(loopnodes))
+    set_irn_link(n, NULL);
+  for (n = eset_first(extnodes); n != NULL; n = eset_next(extnodes))
+    set_irn_link(n, NULL);
+  for (n = eset_first(loopnodes); n != NULL; n = eset_next(loopnodes))
+    if (!is_Block(n)) {
+      b = get_nodes_block(n);
+      set_irn_link(n, get_irn_link(b));
+      set_irn_link(b, n);
+    }
+  for (n = eset_first(extnodes); n != NULL; n = eset_next(extnodes))
+    if (!is_Block(n)) {
+      b = get_nodes_block(n);
+      set_irn_link(n, get_irn_link(b));
+      set_irn_link(b, n);
+    }
+
+  for (b = eset_first(loopnodes); b != NULL; b = eset_next(loopnodes))
+    if (is_Block(b)) {
+      fprintf(F, "graph: { title: \"");
+      PRINT_NODEID(b);
+      fprintf(F, "\"  label: \"");
+      dump_node_opcode(b);
+      fprintf (F, " %ld", get_irn_node_nr(b));
+      fprintf(F, "\" status:clustered color:yellow\n");
+
+      /* dump the blocks edges */
+      dump_ir_data_edges(b);
+
+      /* dump the nodes that go into the block */
+      for (n = get_irn_link(b); n; n = get_irn_link(n)) {
+       if (eset_contains(extnodes, n)) overrule_nodecolor = "lightblue";
+       dump_node(n);
+       overrule_nodecolor = NULL;
+       if (!eset_contains(extnodes, n)) dump_ir_data_edges(n);
+      }
+
+      /* Close the vcg information for the block */
+      fprintf(F, "}\n");
+      dump_const_node_local(b);
+      fprintf(F, "\n");
+    }
+  for (b = eset_first(extnodes); b != NULL; b = eset_next(extnodes))
+    if (is_Block(b)) {
+      fprintf(F, "graph: { title: \"");
+      PRINT_NODEID(b);
+      fprintf(F, "\"  label: \"");
+      dump_node_opcode(b);
+      fprintf (F, " %ld", get_irn_node_nr(b));
+      fprintf(F, "\" status:clustered color:lightblue\n");
+
+      /* dump the nodes that go into the block */
+      for (n = get_irn_link(b); n; n = get_irn_link(n)) {
+       if (!eset_contains(loopnodes, n)) overrule_nodecolor = "lightblue";
+       dump_node(n);
+       overrule_nodecolor = NULL;
+       if (eset_contains(loopnodes, n)) dump_ir_data_edges(n);
+      }
+
+      /* Close the vcg information for the block */
+      fprintf(F, "}\n");
+      dump_const_node_local(b);
+      fprintf(F, "\n");
+    }
+
+  eset_destroy(loopnodes);
+  eset_destroy(extnodes);
+  vcg_close();
+}