little optimization
[libfirm] / ir / ana / irscc.c
index 1331d02..b9add05 100644 (file)
 
 #include "irdump.h"
 
-ir_graph *outermost_ir_graph;      /* The outermost graph the scc is computed
+/* A variant of the loop tree that avoids loops without head.
+   This reduces the depth of the loop tree. */
+#define NO_LOOPS_WITHOUT_HEAD 1
+
+
+INLINE void add_loop_son(ir_loop *loop, ir_loop *son);
+
+INLINE void add_loop_node(ir_loop *loop, ir_node *n);
+
+static ir_graph *outermost_ir_graph;      /* The outermost graph the scc is computed
                       for */
 static ir_loop *current_loop;      /* Current loop construction is working
                       on. */
@@ -48,9 +57,6 @@ ir_node *get_projx_link(ir_node *cb_projx);
 /* Node attributes                                                   **/
 /**********************************************************************/
 
-/* A map to get from irnodes to loop nodes. */
-static pmap *node_loop_map = NULL;
-
 /**********************************************************************/
 /* Node attributes needed for the construction.                      **/
 /**********************************************************************/
@@ -129,28 +135,7 @@ get_irn_dfn (ir_node *n) {
   return ((scc_info *)n->link)->dfn;
 }
 
-#if 0
-/* Replaced node loop map by real field as hash access dominates runtime
- * of the algorithm. ! */
-/* Uses temporary information to set the loop */
-INLINE void
-set_irn_loop (ir_node *n, ir_loop* loop) {
-  assert(node_loop_map && "not initialized!");
-  pmap_insert(node_loop_map, (void *)n, (void *)loop);
-}
-
-/* Uses temporary information to get the loop */
-INLINE ir_loop *
-get_irn_loop (ir_node *n) {
-  ir_loop *res = NULL;
-  if (!node_loop_map) return NULL;
-
-  if (pmap_contains(node_loop_map, (void *)n))
-    res = (ir_loop *) pmap_get(node_loop_map, (void *)n);
 
-  return res;
-}
-#else
 INLINE void
 set_irn_loop (ir_node *n, ir_loop* loop) {
   n->loop = loop;
@@ -161,7 +146,6 @@ INLINE ir_loop *
 get_irn_loop (ir_node *n) {
   return n->loop;
 }
-#endif
 
 
 #if 0
@@ -440,7 +424,7 @@ add_loop_node(ir_loop *loop, ir_node *n) {
   loop_element ln;
   ln.node = n;
   assert(loop && loop->kind == k_ir_loop);
-  assert(get_kind(n) == k_ir_node);
+  assert(get_kind(n) == k_ir_node || get_kind(n) == k_ir_graph);  /* used in callgraph.c */
   ARR_APP1 (loop_element, loop->children, ln);
   loop->n_nodes++;
 }
@@ -543,7 +527,7 @@ init_node (ir_node *n, void *env) {
     (get_irn_op(cb) == op_EndReg) ||
     (get_irn_op(cb) == op_EndExcept)) {
       init_node(cb, NULL);
-      init_node(get_nodes_Block(cb), NULL);
+      init_node(get_nodes_block(cb), NULL);
     }
   }
 #endif
@@ -553,7 +537,6 @@ static INLINE void
 init_scc_common (void) {
   current_dfn = 1;
   loop_node_cnt = 0;
-  if (!node_loop_map) node_loop_map = pmap_create();
   init_stack();
 }
 
@@ -583,7 +566,7 @@ static bool is_outermost_Start(ir_node *n) {
   if ((get_irn_op(n) == op_Block)     &&
       (get_Block_n_cfgpreds(n) == 1)  &&
       (get_irn_op(skip_Proj(get_Block_cfgpred(n, 0))) == op_Start) &&
-      (get_nodes_Block(skip_Proj(get_Block_cfgpred(n, 0))) == n)) {
+      (get_nodes_block(skip_Proj(get_Block_cfgpred(n, 0))) == n)) {
     return true;
   }
 #if 0
@@ -617,8 +600,8 @@ get_start_index(ir_node *n) {
   if (get_irn_op(n) == op_Phi   ||
       get_irn_op(n) == op_Block ||
       (get_irn_op(n) == op_Filter && interprocedural_view) ||
-      (get_irg_pinned(get_irn_irg(n)) == floats &&
-       get_op_pinned(get_irn_op(n)) == floats))
+      (get_irg_pinned(get_irn_irg(n)) == op_pin_state_floats &&
+       get_op_pinned(get_irn_op(n)) == op_pin_state_floats))
     // Here we could test for backedge at -1 which is illegal
     return 0;
   else
@@ -810,7 +793,7 @@ find_tail (ir_node *n) {
        if (res_index == -2)  /* no smallest dfn pred found. */
          res_index = largest_dfn_pred (m);
 
-       if ((m == n) && (res_index == -2)) {
+       if ((m == n) && (res_index == -2)) {  /* dont walk past loop head. */
          i = -1;
        }
        break;
@@ -889,7 +872,8 @@ int search_endproj_in_stack(ir_node *start_block)
          int arity = get_irn_arity(start_block);
          for(j = 0; j < arity; j++)
            {
-             ir_node *begin_projx = get_Block_cfgpred(get_irg_start_block(get_irn_irg(end_projx)), get_Proj_proj(end_projx));
+             ir_node *begin_projx = get_Block_cfgpred(get_irg_start_block(get_irn_irg(end_projx)),
+                                                      get_Proj_proj(end_projx));
              DDMN(begin_projx);
              if(get_irn_n(start_block, j) == begin_projx)
                {
@@ -906,11 +890,13 @@ int search_endproj_in_stack(ir_node *start_block)
 static pmap *projx_link = NULL;
 
 void link_to_reg_end (ir_node *n, void *env) {
-  if(get_irn_op(n) == op_Proj && get_irn_mode(n) == mode_X && get_irn_op(get_irn_n(n, 0)) == op_EndReg)
-    {
+  if(get_irn_op(n) == op_Proj &&
+     get_irn_mode(n) == mode_X &&
+     get_irn_op(get_irn_n(n, 0)) == op_EndReg) {
       /* Reg End Projx -> Find the CallBegin Projx and hash it */
       ir_node *end_projx = n;
-      ir_node *begin_projx = get_Block_cfgpred(get_irg_start_block(get_irn_irg(end_projx)), get_Proj_proj(end_projx));
+      ir_node *begin_projx = get_Block_cfgpred(get_irg_start_block(get_irn_irg(end_projx)),
+                                              get_Proj_proj(end_projx));
       printf("Linked the following ProjxNodes:\n");
       DDMN(begin_projx);
       DDMN(end_projx);
@@ -932,6 +918,10 @@ ir_node *get_projx_link(ir_node *cb_projx)
 
 #endif
 
+INLINE static int
+is_outermost_loop(ir_loop *l) {
+  return l == get_loop_outer_loop(l);
+}
 
 
 /*-----------------------------------------------------------*
@@ -958,59 +948,120 @@ static void scc (ir_node *n) {
   if (!is_outermost_Start(n)) {
     int arity = get_irn_arity(n);
 
-#if EXPERIMENTAL_LOOP_TREE
+    for (i = get_start_index(n); i < arity; i++) {
+      ir_node *m;
+      if (is_backedge(n, i)) continue;
+      m = get_irn_n(n, i); /* get_irn_ip_pred(n, i); */
+      /* if ((!m) || (get_irn_op(m) == op_Unknown)) continue; */
+      scc (m);
+      if (irn_is_in_stack(m)) {
+       /* Uplink of m is smaller if n->m is a backedge.
+          Propagate the uplink to mark the loop. */
+       if (get_irn_uplink(m) < get_irn_uplink(n))
+         set_irn_uplink(n, get_irn_uplink(m));
+      }
+    }
+  }
 
-    /* This is meant to be used with the experimenatl code above.
-       If the above code is not used any more, this can be deleted, too.... */
+  if (get_irn_dfn(n) == get_irn_uplink(n)) {
+    /* This condition holds for
+       1) the node with the incoming backedge.
+          That is: We found a loop!
+       2) Straight line code, because no uplink has been propagated, so the
+          uplink still is the same as the dfn.
 
-    if(interprocedural_view &&
-       is_Block(n) &&
-       get_irn_op(get_irn_n(n, 0)) == op_Proj &&
-       get_irn_op(get_irn_n(get_irn_n(n, 0), 0)) == op_CallBegin)
-      {
-       /* We are at the start node of a function:
-          Walk to the callers in the correct order! */
-       DDMN(n);
-       DDMN(get_irn_n(get_irn_n(n, 0), 0));
-       for(i = 0; i < arity; i++)
-         {
-           int pred_nr;
-           ir_node *m;
-
-           pred_nr = search_endproj_in_stack(n);
-           assert(pred_nr >= 0);
-           if(is_backedge(n, pred_nr))
-             continue;
-           m = get_irn_n(n, pred_nr);
-           scc(m);
-
-           if (irn_is_in_stack(m)) {
-             /* Uplink of m is smaller if n->m is a backedge.
-                Propagate the uplink to mark the loop. */
-             if (get_irn_uplink(m) < get_irn_uplink(n))
-               set_irn_uplink(n, get_irn_uplink(m));
-           }
-         }
-      }
-    else
+       But n might not be a proper loop head for the analysis. Proper loop
+       heads are Block and Phi nodes. find_tail searches the stack for
+       Block's and Phi's and takes those nodes as loop heads for the current
+       loop instead and marks the incoming edge as backedge. */
+
+    ir_node *tail = find_tail(n);
+    if (tail) {
+      /* We have a loop, that is no straight line code,
+        because we found a loop head!
+        Next actions: Open a new loop on the loop tree and
+                      try to find inner loops */
+
+#if NO_LOOPS_WITHOUT_HEAD
+      /* This is an adaption of the algorithm from fiasco / optscc to
+       * avoid loops without Block or Phi as first node.  This should
+       * severely reduce the number of evaluations of nodes to detect
+       * a fixpoint in the heap analysis.
+       * Further it avoids loops without firm nodes that cause errors
+       * in the heap analyses.
+       * But attention:  don't do it for the outermost loop:  This loop
+       * is not iterated.  A first block can be a loop head in case of
+       * an endless recursion. */
 
+      ir_loop *l;
+      int close;
+      if ((get_loop_n_elements(current_loop) > 0) || (is_outermost_loop(current_loop))) {
+       l = new_loop();
+       close = 1;
+      } else {
+       l = current_loop;
+       close = 0;
+      }
+#else
+      ir_loop *l = new_loop();
 #endif
 
+      /* Remove the loop from the stack ... */
+      pop_scc_unmark_visit (n);
+
+      /* The current backedge has been marked, that is temporarily eliminated,
+        by find tail. Start the scc algorithm
+        anew on the subgraph thats left (the current loop without the backedge)
+        in order to find more inner loops. */
+      scc (tail);
+
+      assert (irn_visited(n));
+#if NO_LOOPS_WITHOUT_HEAD
+      if (close)
+#endif
+       close_loop(l);
+    }
+    else
       {
-       for (i = get_start_index(n); i < arity; i++) {
-         ir_node *m;
-         if (is_backedge(n, i)) continue;
-         m = get_irn_n(n, i); /* get_irn_ip_pred(n, i); */
-         /* if ((!m) || (get_irn_op(m) == op_Unknown)) continue; */
-         scc (m);
-         if (irn_is_in_stack(m)) {
-           /* Uplink of m is smaller if n->m is a backedge.
-              Propagate the uplink to mark the loop. */
-           if (get_irn_uplink(m) < get_irn_uplink(n))
-             set_irn_uplink(n, get_irn_uplink(m));
-         }
-       }
+       /* No loop head was found, that is we have straightline code.
+          Pop all nodes from the stack to the current loop. */
+      pop_scc_to_loop(n);
+    }
+  }
+}
+
+static void my_scc (ir_node *n) {
+  int i;
+  if (irn_visited(n)) return;
+  mark_irn_visited(n);
+
+  /* Initialize the node */
+  set_irn_dfn(n, current_dfn);      /* Depth first number for this node */
+  set_irn_uplink(n, current_dfn);   /* ... is default uplink. */
+  set_irn_loop(n, NULL);
+  current_dfn ++;
+  push(n);
+
+  /* AS: get_start_index might return -1 for Control Flow Nodes, and thus a negative
+     array index would be passed to is_backedge(). But CFG Nodes dont't have a backedge array,
+     so is_backedge does not access array[-1] but correctly returns false! */
+
+  if (!is_outermost_Start(n)) {
+    int arity = get_irn_arity(n);
+
+    for (i = get_start_index(n); i < arity; i++) {
+      ir_node *m;
+      if (is_backedge(n, i)) continue;
+      m = get_irn_n(n, i); /* get_irn_ip_pred(n, i); */
+      /* if ((!m) || (get_irn_op(m) == op_Unknown)) continue; */
+      my_scc (m);
+      if (irn_is_in_stack(m)) {
+       /* Uplink of m is smaller if n->m is a backedge.
+          Propagate the uplink to mark the loop. */
+       if (get_irn_uplink(m) < get_irn_uplink(n))
+         set_irn_uplink(n, get_irn_uplink(m));
       }
+    }
   }
 
   if (get_irn_dfn(n) == get_irn_uplink(n)) {
@@ -1032,10 +1083,7 @@ static void scc (ir_node *n) {
         Next actions: Open a new loop on the loop tree and
                       try to find inner loops */
 
-
-#define NO_LOOPS_WITHOUT_HEAD 1
 #if NO_LOOPS_WITHOUT_HEAD
-
       /* This is an adaption of the algorithm from fiasco / optscc to
        * avoid loops without Block or Phi as first node.  This should
        * severely reduce the number of evaluations of nodes to detect
@@ -1045,33 +1093,25 @@ static void scc (ir_node *n) {
 
       ir_loop *l;
       int close;
-      if (get_loop_n_elements(current_loop) > 0) {
+      if ((get_loop_n_elements(current_loop) > 0) || (is_outermost_loop(current_loop))) {
        l = new_loop();
        close = 1;
       } else {
        l = current_loop;
        close = 0;
       }
-
 #else
-
       ir_loop *l = new_loop();
-
 #endif
 
       /* Remove the loop from the stack ... */
       pop_scc_unmark_visit (n);
 
-      /*  GL @@@ remove experimental stuff rem = find_irg_on_stack(tail); */
-
       /* The current backedge has been marked, that is temporarily eliminated,
         by find tail. Start the scc algorithm
         anew on the subgraph thats left (the current loop without the backedge)
         in order to find more inner loops. */
-
-      scc (tail);
-
-      /*  GL @@@ remove experimental stuff current_ir_graph = rem; */
+      my_scc (tail);
 
       assert (irn_visited(n));
 #if NO_LOOPS_WITHOUT_HEAD
@@ -1081,8 +1121,8 @@ static void scc (ir_node *n) {
     }
     else
       {
-       /* AS: No loop head was found, that is we have straightline code.
-              Pop all nodes from the stack to the current loop. */
+       /* No loop head was found, that is we have straightline code.
+          Pop all nodes from the stack to the current loop. */
       pop_scc_to_loop(n);
     }
   }
@@ -1097,7 +1137,7 @@ void construct_backedges(ir_graph *irg) {
   assert(!interprocedural_view &&
      "not implemented, use construct_ip_backedges");
 
-  current_ir_graph = irg;
+  current_ir_graph   = irg;
   outermost_ir_graph = irg;
 
   init_scc(current_ir_graph);
@@ -1106,17 +1146,10 @@ void construct_backedges(ir_graph *irg) {
   new_loop();  /* sets current_loop */
   head_rem = current_loop; /* Just for assertion */
 
-  if (interprocedural_view) {
-    set_irg_visited(current_ir_graph, inc_max_irg_visited());
-    init_ip_walk ();
-  } else {
-    inc_irg_visited(current_ir_graph);
-  }
+  inc_irg_visited(current_ir_graph);
 
   scc(get_irg_end(current_ir_graph));
 
-  if (interprocedural_view) finish_ip_walk();
-
   assert(head_rem == current_loop);
   set_irg_loop(current_ir_graph, current_loop);
   set_irg_loopinfo_state(current_ir_graph, loopinfo_consistent);
@@ -1158,7 +1191,7 @@ void construct_ip_backedges (void) {
     /* Find real entry points */
     sb = get_irg_start_block(current_ir_graph);
     if ((get_Block_n_cfgpreds(sb) > 1) ||
-    (get_nodes_Block(get_Block_cfgpred(sb, 0)) != sb)) continue;
+    (get_nodes_block(get_Block_cfgpred(sb, 0)) != sb)) continue;
     /* Compute scc for this graph */
     outermost_ir_graph = current_ir_graph;
     set_irg_visited(outermost_ir_graph, get_max_irg_visited());
@@ -1243,6 +1276,73 @@ void construct_ip_backedges (void) {
   interprocedural_view = rem_ipv;
 }
 #endif
+void my_construct_ip_backedges (void) {
+  ir_graph *rem = current_ir_graph;
+  int rem_ipv = interprocedural_view;
+  int i;
+
+  assert(get_irp_ip_view_state() == ip_view_valid);
+
+  outermost_ir_graph = get_irp_main_irg();
+
+  init_ip_scc();
+
+  current_loop = NULL;
+  new_loop();  /* sets current_loop */
+  interprocedural_view = 1;
+
+  inc_max_irg_visited();
+  for (i = 0; i < get_irp_n_irgs(); i++)
+    set_irg_visited(get_irp_irg(i), get_max_irg_visited());
+
+  /** We have to start the walk at the same nodes as cg_walk. **/
+  /* Walk starting at unreachable procedures. Only these
+   * have End blocks visible in interprocedural view. */
+  for (i = 0; i < get_irp_n_irgs(); i++) {
+    ir_node *sb;
+    current_ir_graph = get_irp_irg(i);
+
+    sb = get_irg_start_block(current_ir_graph);
+
+    if ((get_Block_n_cfgpreds(sb) > 1) ||
+    (get_nodes_block(get_Block_cfgpred(sb, 0)) != sb)) continue;
+
+    my_scc(get_irg_end(current_ir_graph));
+  }
+
+  /* Check whether we walked all procedures: there could be procedures
+     with cyclic calls but no call from the outside. */
+  for (i = 0; i < get_irp_n_irgs(); i++) {
+    ir_node *sb;
+    current_ir_graph = get_irp_irg(i);
+
+    /* Test start block: if inner procedure end and end block are not
+     * visible and therefore not marked. */
+    sb = get_irg_start_block(current_ir_graph);
+    if (get_irn_visited(sb) < get_irg_visited(current_ir_graph)) scc(sb);
+  }
+
+  /* Walk all endless loops in inner procedures.
+   * We recognize an inner procedure if the End node is not visited. */
+  for (i = 0; i < get_irp_n_irgs(); i++) {
+    ir_node *e;
+    current_ir_graph = get_irp_irg(i);
+
+    e = get_irg_end(current_ir_graph);
+    if (get_irn_visited(e) < get_irg_visited(current_ir_graph)) {
+      int j;
+      /* Don't visit the End node. */
+      for (j = 0; j < get_End_n_keepalives(e); j++) scc(get_End_keepalive(e, j));
+    }
+  }
+
+  set_irg_loop(outermost_ir_graph, current_loop);
+  set_irg_loopinfo_state(current_ir_graph, loopinfo_ip_consistent);
+  assert(get_irg_loop(outermost_ir_graph)->kind == k_ir_loop);
+
+  current_ir_graph = rem;
+  interprocedural_view = rem_ipv;
+}
 
 static void reset_backedges(ir_node *n) {
   if (is_possible_loop_head(n)) {
@@ -1296,8 +1396,6 @@ void free_all_loop_information (void) {
   for (i = 0; i < get_irp_n_irgs(); i++) {
     free_loop_information(get_irp_irg(i));
   }
-  pmap_destroy(node_loop_map);
-  node_loop_map = NULL;
   interprocedural_view = rem;
 }