RFC [cfg-branch] Loop representation

Zdenek Dvorak rakdver@atrey.karlin.mff.cuni.cz
Wed Jan 16 00:30:00 GMT 2002


Hello.

This is a loop discovery code modified for new representation of loops
(that should be more flexible than the old one). The representation
works as follows:

1) We merge loops with shared headers; then any two loops must be either
   disjoint or one of them must be subset of other one.
2) For each basic block we maintain the innermost loop it belongs to;
   we place a dummy loop around whole function so that this loop exists
   for every bb.
3) For each loop we maintain pointers to all loops containing him (ie.
   all his predecestors in loop tree). This enables us to respond queries
   on membership of bb in a loop in constant time; of course it also
   makes structure quadratic in worst case, but I think it is reasonable
   to suppose that maximum level of loops is small in practice.

Please note that (relatively large amount of) modifications outside
basic-block.h and cfgloop.c are left out from this patch.

Zdenek Dvorak

Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/basic-block.h,v
retrieving revision 1.127.2.10
diff -c -3 -p -r1.127.2.10 basic-block.h
*** basic-block.h	2002/01/10 10:04:46	1.127.2.10
--- basic-block.h	2002/01/16 01:58:11
*************** typedef struct basic_block_def {
*** 209,214 ****
--- 209,220 ----
    /* The loop depth of this block.  */
    int loop_depth;
  
+   /* Outermost loop containing the block.  */
+   struct loop *loop_father;
+ 
+   /* Immediate dominator.  */
+   struct basic_block_def *dominator;
+ 
    /* Expected number of executions: calculated in profile.c.  */
    gcov_type count;
  
*************** typedef struct basic_block_def {
*** 223,228 ****
--- 229,235 ----
  
  /* Masks for basic_block.flags.  */
  #define BB_REACHABLE		1
+ #define BB_VISITED		2
  
  /* Number of basic blocks in the current function.  */
  
*************** extern void free_basic_block_vars	PARAMS
*** 294,301 ****
  extern edge split_block			PARAMS ((basic_block, rtx));
  extern basic_block split_edge		PARAMS ((edge));
  extern void insert_insn_on_edge		PARAMS ((rtx, edge));
! extern void commit_edge_insertions	PARAMS ((void));
! extern void commit_edge_insertions_watch_calls	PARAMS ((void));
  extern void remove_fake_edges		PARAMS ((void));
  extern void add_noreturn_fake_exit_edges	PARAMS ((void));
  extern void connect_infinite_loops_to_exit	PARAMS ((void));
--- 301,311 ----
  extern edge split_block			PARAMS ((basic_block, rtx));
  extern basic_block split_edge		PARAMS ((edge));
  extern void insert_insn_on_edge		PARAMS ((rtx, edge));
! 
! extern void update_new_blocks           PARAMS ((basic_block, basic_block **,                                                 int *, int *));
! extern int commit_edge_insertions	PARAMS ((basic_block **));
! extern int commit_edge_insertions_watch_calls	PARAMS ((basic_block **));
! 
  extern void remove_fake_edges		PARAMS ((void));
  extern void add_noreturn_fake_exit_edges	PARAMS ((void));
  extern void connect_infinite_loops_to_exit	PARAMS ((void));
*************** struct loop
*** 348,364 ****
    /* Number of edges along the pre_header extended basic block trace.  */
    int num_pre_header_edges;
  
-   /* The first block in the loop.  This is not necessarily the same as
-      the loop header.  */
-   basic_block first;
- 
-   /* The last block in the loop.  This is not necessarily the same as
-      the loop latch.  */
-   basic_block last;
- 
-   /* Bitmap of blocks contained within the loop.  */
-   sbitmap nodes;
- 
    /* Number of blocks contained within the loop.  */
    int num_nodes;
  
--- 358,363 ----
*************** struct loop
*** 380,385 ****
--- 379,387 ----
    /* The loop nesting depth.  */
    int depth;
  
+   /* Predecestors of the loop.  */
+   struct loop **pred;
+ 
    /* The height of the loop (enclosed loop levels) within the loop
       hierarchy tree.  */
    int level;
*************** struct loop
*** 393,400 ****
    /* Link to the next (sibling) loop.  */
    struct loop *next;
  
!   /* Non-zero if the loop shares a header with another loop.  */
!   int shared;
  
    /* Non-zero if the loop is invalid (e.g., contains setjmp.).  */
    int invalid;
--- 395,402 ----
    /* Link to the next (sibling) loop.  */
    struct loop *next;
  
!   /* Loop that is copy of this loop.  */
!   struct loop *copy;
  
    /* Non-zero if the loop is invalid (e.g., contains setjmp.).  */
    int invalid;
*************** struct loops
*** 459,465 ****
  
    /* Array of natural loop descriptors (scanning this array in reverse order
       will find the inner loops before their enclosing outer loops).  */
!   struct loop *array;
  
    /* Pointer to root of loop heirachy tree.  */
    struct loop *tree_root;
--- 461,467 ----
  
    /* Array of natural loop descriptors (scanning this array in reverse order
       will find the inner loops before their enclosing outer loops).  */
!   struct loop **array;
  
    /* Pointer to root of loop heirachy tree.  */
    struct loop *tree_root;
*************** struct loops
*** 478,485 ****
      int *rc_order;
    } cfg;
  
-   /* Headers shared by multiple loops that should be merged.  */
-   sbitmap shared_headers;
  };
  
  extern int flow_loops_find PARAMS ((struct loops *, int flags));
--- 480,485 ----
*************** extern void flow_loop_dump PARAMS ((cons
*** 492,497 ****
--- 492,498 ----
  				    void (*)(const struct loop *,
  					     FILE *, int), int));
  extern int flow_loop_scan PARAMS ((struct loops *, struct loop *, int));
+ extern void flow_loop_tree_node_add PARAMS ((struct loop *, struct loop *));
  
  /* This structure maintains an edge list vector.  */
  struct edge_list
*************** extern rtx block_label			PARAMS ((basic_
*** 648,654 ****
  extern bool forwarder_block_p		PARAMS ((basic_block));
  extern bool purge_all_dead_edges	PARAMS ((int));
  extern bool purge_dead_edges		PARAMS ((basic_block));
! extern void find_sub_basic_blocks	PARAMS ((basic_block));
  extern void find_many_sub_basic_blocks	PARAMS ((sbitmap));
  extern bool can_fallthru		PARAMS ((basic_block, basic_block));
  extern void flow_nodes_print		PARAMS ((const char *, const sbitmap,
--- 649,656 ----
  extern bool forwarder_block_p		PARAMS ((basic_block));
  extern bool purge_all_dead_edges	PARAMS ((int));
  extern bool purge_dead_edges		PARAMS ((basic_block));
! extern void find_sub_basic_blocks	PARAMS ((basic_block, basic_block **,
!                                                  int *, int *));
  extern void find_many_sub_basic_blocks	PARAMS ((sbitmap));
  extern bool can_fallthru		PARAMS ((basic_block, basic_block));
  extern void flow_nodes_print		PARAMS ((const char *, const sbitmap,
*************** extern void free_aux_for_edges		PARAMS (
*** 668,675 ****
     debugger, and it is declared extern so we don't get warnings about
     it being unused.  */
  extern void verify_flow_info		PARAMS ((void));
- extern int flow_loop_outside_edge_p	PARAMS ((const struct loop *, edge));
  
  typedef struct conflict_graph_def *conflict_graph;
  
  /* Callback function when enumerating conflicts.  The arguments are
--- 670,686 ----
     debugger, and it is declared extern so we don't get warnings about
     it being unused.  */
  extern void verify_flow_info		PARAMS ((void));
  
+ extern bool flow_loop_outside_edge_p	PARAMS ((const struct loop *, edge));
+ extern bool flow_bb_inside_loop_p PARAMS ((const struct loop *, basic_block));
+ extern basic_block *get_loop_body PARAMS ((const struct loop *));
+ 
+ extern void add_bb_to_loop PARAMS ((basic_block, struct loop *));
+ extern void remove_bb_from_loops PARAMS ((basic_block));
+ struct loop * find_common_loop PARAMS ((struct loop *, struct loop *));
+ 
+ basic_block create_preheader PARAMS ((struct loop *, sbitmap *));
+ 
  typedef struct conflict_graph_def *conflict_graph;
  
  /* Callback function when enumerating conflicts.  The arguments are
*************** enum cdi_direction
*** 710,714 ****
--- 721,736 ----
  
  extern void calculate_dominance_info	PARAMS ((int *, sbitmap *,
  						 enum cdi_direction));
+ extern basic_block nearest_common_dominator	PARAMS ((sbitmap *,
+ 						 basic_block, basic_block));
+ extern void set_immediate_dominator	PARAMS ((sbitmap *,
+ 						 basic_block, basic_block));
+ extern basic_block get_immediate_dominator	PARAMS ((sbitmap *,
+ 						 basic_block));
+ extern bool dominated_by_p	PARAMS ((sbitmap *, basic_block, basic_block));
+ 
+ extern int get_dominated_by PARAMS ((sbitmap *, basic_block, basic_block **));
+ 
+ extern void verify_dominators PARAMS ((void));
  
  #endif /* GCC_BASIC_BLOCK_H */
Index: cfgloop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgloop.c,v
retrieving revision 1.2.2.4
diff -c -3 -p -r1.2.2.4 cfgloop.c
*** cfgloop.c	2001/12/30 16:20:53	1.2.2.4
--- cfgloop.c	2002/01/16 01:58:11
*************** Software Foundation, 59 Temple Place - S
*** 26,46 ****
  
  static void flow_loops_cfg_dump		PARAMS ((const struct loops *,
  						 FILE *));
! static int flow_loop_nested_p		PARAMS ((struct loop *,
! 						 struct loop *));
! static int flow_loop_entry_edges_find	PARAMS ((basic_block, const sbitmap,
! 						 edge **));
! static int flow_loop_exit_edges_find	PARAMS ((const sbitmap, edge **));
! static int flow_loop_nodes_find		PARAMS ((basic_block, basic_block,
! 						 sbitmap));
! static void flow_loop_pre_header_scan	PARAMS ((struct loop *));
  static basic_block flow_loop_pre_header_find PARAMS ((basic_block,
  						      const sbitmap *));
! static void flow_loop_tree_node_add	PARAMS ((struct loop *,
! 						 struct loop *));
! static void flow_loops_tree_build	PARAMS ((struct loops *));
! static int flow_loop_level_compute	PARAMS ((struct loop *, int));
  static int flow_loops_level_compute	PARAMS ((struct loops *));
  
  /* Dump loop related CFG information.  */
  
--- 26,45 ----
  
  static void flow_loops_cfg_dump		PARAMS ((const struct loops *,
  						 FILE *));
! static int flow_loop_nested_p PARAMS ((const struct loop *, const struct loop *));
! static void flow_loop_entry_edges_find	PARAMS ((struct loop *));
! static void flow_loop_exit_edges_find	PARAMS ((struct loop *));
! static int flow_loop_nodes_find	PARAMS ((basic_block,
!                                          struct loop *));
! static void flow_loop_pre_header_scan PARAMS ((struct loop *));
  static basic_block flow_loop_pre_header_find PARAMS ((basic_block,
  						      const sbitmap *));
! static int flow_loop_level_compute	PARAMS ((struct loop *));
  static int flow_loops_level_compute	PARAMS ((struct loops *));
+ static basic_block make_forwarder_block PARAMS ((basic_block, bool, bool,
+                                                  edge, int));
+ static void canonicalize_loop_headers   PARAMS ((void));
+ 
  
  /* Dump loop related CFG information.  */
  
*************** flow_loops_cfg_dump (loops, file)
*** 61,67 ****
        fprintf (file, ";; %d succs { ", i);
        for (succ = BASIC_BLOCK (i)->succ; succ; succ = succ->succ_next)
  	fprintf (file, "%d ", succ->dest->index);
!       flow_nodes_print ("} dom", loops->cfg.dom[i], file);
      }
  
    /* Dump the DFS node order.  */
--- 60,67 ----
        fprintf (file, ";; %d succs { ", i);
        for (succ = BASIC_BLOCK (i)->succ; succ; succ = succ->succ_next)
  	fprintf (file, "%d ", succ->dest->index);
!       fprintf (file, "}\n");
!       /* flow_nodes_print ("} dom", loops->cfg.dom[i], file); */
      }
  
    /* Dump the DFS node order.  */
*************** flow_loops_cfg_dump (loops, file)
*** 85,98 ****
      }
  }
  
! /* Return non-zero if the nodes of LOOP are a subset of OUTER.  */
  
  static int
  flow_loop_nested_p (outer, loop)
!      struct loop *outer;
!      struct loop *loop;
  {
!   return sbitmap_a_subset_b_p (loop->nodes, outer->nodes);
  }
  
  /* Dump the loop information specified by LOOP to the stream FILE
--- 85,99 ----
      }
  }
  
! /* Return non-zero if the LOOP is a subset of OUTER.  */
  
  static int
  flow_loop_nested_p (outer, loop)
!      const struct loop *outer;
!      const struct loop *loop;
  {
!   return loop->depth>outer->depth
!          && loop->pred[outer->depth] == outer;
  }
  
  /* Dump the loop information specified by LOOP to the stream FILE
*************** flow_loop_dump (loop, file, loop_dump_au
*** 105,126 ****
       void (*loop_dump_aux) PARAMS((const struct loop *, FILE *, int));
       int verbose;
  {
    if (! loop || ! loop->header)
      return;
  
!   if (loop->first->head && loop->last->end)
!     fprintf (file, ";;\n;; Loop %d (%d to %d):%s%s\n",
! 	    loop->num, INSN_UID (loop->first->head),
! 	    INSN_UID (loop->last->end),
! 	    loop->shared ? " shared" : "", loop->invalid ? " invalid" : "");
!   else
!     fprintf (file, ";;\n;; Loop %d:%s%s\n", loop->num,
! 	     loop->shared ? " shared" : "", loop->invalid ? " invalid" : "");
  
!   fprintf (file, ";;  header %d, latch %d, pre-header %d, first %d, last %d\n",
  	   loop->header->index, loop->latch->index,
! 	   loop->pre_header ? loop->pre_header->index : -1,
! 	   loop->first->index, loop->last->index);
    fprintf (file, ";;  depth %d, level %d, outer %ld\n",
  	   loop->depth, loop->level,
  	   (long) (loop->outer ? loop->outer->num : -1));
--- 106,123 ----
       void (*loop_dump_aux) PARAMS((const struct loop *, FILE *, int));
       int verbose;
  {
+   basic_block *bbs;
+   int i;
+ 
    if (! loop || ! loop->header)
      return;
  
!   fprintf (file, ";;\n;; Loop %d:%s\n", loop->num,
! 	     loop->invalid ? " invalid" : "");
  
!   fprintf (file, ";;  header %d, latch %d, pre-header %d\n",
  	   loop->header->index, loop->latch->index,
! 	   loop->pre_header ? loop->pre_header->index : -1);
    fprintf (file, ";;  depth %d, level %d, outer %ld\n",
  	   loop->depth, loop->level,
  	   (long) (loop->outer ? loop->outer->num : -1));
*************** flow_loop_dump (loop, file, loop_dump_au
*** 131,138 ****
  
    flow_edge_list_print (";;  entry edges", loop->entry_edges,
  			loop->num_entries, file);
!   fprintf (file, ";;  %d", loop->num_nodes);
!   flow_nodes_print (" nodes", loop->nodes, file);
    flow_edge_list_print (";;  exit edges", loop->exit_edges,
  			loop->num_exits, file);
  
--- 128,140 ----
  
    flow_edge_list_print (";;  entry edges", loop->entry_edges,
  			loop->num_entries, file);
!   fprintf (file, ";;  %d nodes", loop->num_nodes);
!   fprintf (file, ";;  nodes:");
!   bbs = get_loop_body (loop);
!   for (i = 0; i < loop->num_nodes; i++)
!     fprintf (file, " %d", bbs[i]->index);
!   free (bbs);
!   fprintf (file, "\n");
    flow_edge_list_print (";;  exit edges", loop->exit_edges,
  			loop->num_exits, file);
  
*************** flow_loops_dump (loops, file, loop_dump_
*** 153,194 ****
       void (*loop_dump_aux) PARAMS((const struct loop *, FILE *, int));
       int verbose;
  {
!   int i, j;
    int num_loops;
  
    num_loops = loops->num;
    if (! num_loops || ! file)
      return;
  
-   fprintf (file, ";; %d loops found, %d levels\n", num_loops, loops->levels);
    for (i = 0; i < num_loops; i++)
      {
!       struct loop *loop = &loops->array[i];
  
        flow_loop_dump (loop, file, loop_dump_aux, verbose);
-       if (loop->shared)
- 	for (j = 0; j < i; j++)
- 	  {
- 	    struct loop *oloop = &loops->array[j];
- 
- 	    if (loop->header == oloop->header)
- 	      {
- 		int disjoint;
- 		int smaller;
- 
- 		smaller = loop->num_nodes < oloop->num_nodes;
- 
- 		/* If the union of LOOP and OLOOP is different than
- 		   the larger of LOOP and OLOOP then LOOP and OLOOP
- 		   must be disjoint.  */
- 		disjoint = ! flow_loop_nested_p (smaller ? loop : oloop,
- 						 smaller ? oloop : loop);
- 		fprintf (file,
- 			 ";; loop header %d shared by loops %d, %d %s\n",
- 			 loop->header->index, i, j,
- 			 disjoint ? "disjoint" : "nested");
- 	      }
- 	  }
      }
  
    if (verbose)
--- 155,175 ----
       void (*loop_dump_aux) PARAMS((const struct loop *, FILE *, int));
       int verbose;
  {
!   int i;
    int num_loops;
  
    num_loops = loops->num;
    if (! num_loops || ! file)
      return;
+ 
+   fprintf (file, ";; %d loops found, %d levels\n",
+ 	   num_loops, loops->levels);
  
    for (i = 0; i < num_loops; i++)
      {
!       struct loop *loop = loops->array[i];
  
        flow_loop_dump (loop, file, loop_dump_aux, verbose);
      }
  
    if (verbose)
*************** flow_loops_free (loops)
*** 211,228 ****
        /* Free the loop descriptors.  */
        for (i = 0; i < loops->num; i++)
  	{
! 	  struct loop *loop = &loops->array[i];
  
  	  if (loop->pre_header_edges)
  	    free (loop->pre_header_edges);
- 	  if (loop->nodes)
- 	    sbitmap_free (loop->nodes);
  	  if (loop->entry_edges)
  	    free (loop->entry_edges);
  	  if (loop->exit_edges)
  	    free (loop->exit_edges);
  	  if (loop->exits_doms)
  	    sbitmap_free (loop->exits_doms);
  	}
  
        free (loops->array);
--- 192,210 ----
        /* Free the loop descriptors.  */
        for (i = 0; i < loops->num; i++)
  	{
! 	  struct loop *loop = loops->array[i];
  
  	  if (loop->pre_header_edges)
  	    free (loop->pre_header_edges);
  	  if (loop->entry_edges)
  	    free (loop->entry_edges);
  	  if (loop->exit_edges)
  	    free (loop->exit_edges);
  	  if (loop->exits_doms)
  	    sbitmap_free (loop->exits_doms);
+           if (loop->pred)
+             free (loop->pred);
+           free (loop);
  	}
  
        free (loops->array);
*************** flow_loops_free (loops)
*** 233,390 ****
  
        if (loops->cfg.dfs_order)
  	free (loops->cfg.dfs_order);
  
-       if (loops->shared_headers)
- 	sbitmap_free (loops->shared_headers);
      }
  }
  
! /* Find the entry edges into the loop with header HEADER and nodes
!    NODES and store in ENTRY_EDGES array.  Return the number of entry
!    edges from the loop.  */
  
! static int
! flow_loop_entry_edges_find (header, nodes, entry_edges)
!      basic_block header;
!      const sbitmap nodes;
!      edge **entry_edges;
  {
    edge e;
    int num_entries;
  
-   *entry_edges = NULL;
- 
    num_entries = 0;
!   for (e = header->pred; e; e = e->pred_next)
      {
!       basic_block src = e->src;
! 
!       if (src == ENTRY_BLOCK_PTR || ! TEST_BIT (nodes, src->index))
  	num_entries++;
      }
  
    if (! num_entries)
      abort ();
  
!   *entry_edges = (edge *) xmalloc (num_entries * sizeof (edge));
  
    num_entries = 0;
!   for (e = header->pred; e; e = e->pred_next)
      {
!       basic_block src = e->src;
! 
!       if (src == ENTRY_BLOCK_PTR || ! TEST_BIT (nodes, src->index))
! 	(*entry_edges)[num_entries++] = e;
      }
  
!   return num_entries;
  }
  
! /* Find the exit edges from the loop using the bitmap of loop nodes
!    NODES and store in EXIT_EDGES array.  Return the number of
!    exit edges from the loop.  */
  
! static int
! flow_loop_exit_edges_find (nodes, exit_edges)
!      const sbitmap nodes;
!      edge **exit_edges;
  {
    edge e;
!   int node;
!   int num_exits;
  
!   *exit_edges = NULL;
  
    /* Check all nodes within the loop to see if there are any
       successors not in the loop.  Note that a node may have multiple
       exiting edges ?????  A node can have one jumping edge and one fallthru
       edge so only one of these can exit the loop.  */
    num_exits = 0;
!   EXECUTE_IF_SET_IN_SBITMAP (nodes, 0, node, {
!     for (e = BASIC_BLOCK (node)->succ; e; e = e->succ_next)
!       {
! 	basic_block dest = e->dest;
  
! 	if (dest == EXIT_BLOCK_PTR || ! TEST_BIT (nodes, dest->index))
! 	    num_exits++;
        }
!   });
  
    if (! num_exits)
!     return 0;
  
!   *exit_edges = (edge *) xmalloc (num_exits * sizeof (edge));
  
    /* Store all exiting edges into an array.  */
    num_exits = 0;
!   EXECUTE_IF_SET_IN_SBITMAP (nodes, 0, node, {
!     for (e = BASIC_BLOCK (node)->succ; e; e = e->succ_next)
!       {
! 	basic_block dest = e->dest;
  
! 	if (dest == EXIT_BLOCK_PTR || ! TEST_BIT (nodes, dest->index))
! 	  (*exit_edges)[num_exits++] = e;
        }
!   });
! 
!   return num_exits;
  }
  
! /* Find the nodes contained within the loop with header HEADER and
!    latch LATCH and store in NODES.  Return the number of nodes within
!    the loop.  */
  
  static int
! flow_loop_nodes_find (header, latch, nodes)
       basic_block header;
!      basic_block latch;
!      sbitmap nodes;
  {
    basic_block *stack;
    int sp;
!   int num_nodes = 0;
  
!   stack = (basic_block *) xmalloc (n_basic_blocks * sizeof (basic_block));
!   sp = 0;
  
!   /* Start with only the loop header in the set of loop nodes.  */
!   sbitmap_zero (nodes);
!   SET_BIT (nodes, header->index);
!   num_nodes++;
!   header->loop_depth++;
! 
!   /* Push the loop latch on to the stack.  */
!   if (! TEST_BIT (nodes, latch->index))
      {
!       SET_BIT (nodes, latch->index);
!       latch->loop_depth++;
        num_nodes++;
!       stack[sp++] = latch;
!     }
! 
!   while (sp)
!     {
!       basic_block node;
!       edge e;
! 
!       node = stack[--sp];
!       for (e = node->pred; e; e = e->pred_next)
! 	{
! 	  basic_block ancestor = e->src;
! 
! 	  /* If each ancestor not marked as part of loop, add to set of
! 	     loop nodes and push on to stack.  */
! 	  if (ancestor != ENTRY_BLOCK_PTR
! 	      && ! TEST_BIT (nodes, ancestor->index))
! 	    {
! 	      SET_BIT (nodes, ancestor->index);
! 	      ancestor->loop_depth++;
! 	      num_nodes++;
! 	      stack[sp++] = ancestor;
  	    }
! 	}
      }
-   free (stack);
    return num_nodes;
  }
  
--- 215,362 ----
  
        if (loops->cfg.dfs_order)
  	free (loops->cfg.dfs_order);
+       if (loops->cfg.rc_order)
+ 	free (loops->cfg.rc_order);
  
      }
  }
  
! /* Find the entry edges into the LOOP.  */
  
! static void 
! flow_loop_entry_edges_find (loop)
!      struct loop *loop;
  {
    edge e;
    int num_entries;
  
    num_entries = 0;
!   for (e = loop->header->pred; e; e = e->pred_next)
      {
!       if (flow_loop_outside_edge_p (loop, e))
  	num_entries++;
      }
  
    if (! num_entries)
      abort ();
  
!   loop->entry_edges = (edge *) xmalloc (num_entries * sizeof (edge *));
  
    num_entries = 0;
!   for (e = loop->header->pred; e; e = e->pred_next)
      {
!       if (flow_loop_outside_edge_p (loop, e))
!         loop->entry_edges[num_entries++] = e;
      }
  
!   loop->num_entries = num_entries;
  }
  
! /* Find the exit edges from the LOOP.  */
  
! static void
! flow_loop_exit_edges_find (loop)
!      struct loop *loop;
  {
    edge e;
!   basic_block node, *bbs;
!   int num_exits, i;
  
!   loop->exit_edges = NULL;
!   loop->num_exits = 0;
  
    /* Check all nodes within the loop to see if there are any
       successors not in the loop.  Note that a node may have multiple
       exiting edges ?????  A node can have one jumping edge and one fallthru
       edge so only one of these can exit the loop.  */
    num_exits = 0;
!   bbs = get_loop_body (loop);
!   for (i = 0; i < loop->num_nodes; i++)
!     {
!       node = bbs[i];
!       for (e = node->succ; e; e = e->succ_next)
!         {
!           basic_block dest = e->dest;
  
!           if (!flow_bb_inside_loop_p (loop, dest))
!             num_exits++;
        }
!     }
  
    if (! num_exits)
!     {
!       free (bbs);
!       return;
!     }
  
!   loop->exit_edges = (edge *) xmalloc (num_exits * sizeof (edge *));
  
    /* Store all exiting edges into an array.  */
    num_exits = 0;
!   for (i = 0; i < loop->num_nodes; i++)
!     {
!       node = bbs[i];
!       for (e = node->succ; e; e = e->succ_next)
!         {
!           basic_block dest = e->dest;
  
!           if (!flow_bb_inside_loop_p (loop, dest))
! 	    loop->exit_edges[num_exits++] = e;
        }
!     }
!   free (bbs);
!   loop->num_exits = num_exits;
  }
  
! /* Find the nodes contained within the LOOP with header HEADER.
!    Return the number of nodes within the loop.  */
  
  static int
! flow_loop_nodes_find (header, loop)
       basic_block header;
!      struct loop *loop;
  {
    basic_block *stack;
    int sp;
!   int num_nodes = 1;
!   int findex, lindex;
  
!   header->loop_father = loop;
!   header->loop_depth = loop->depth;
!   findex = lindex = header->index;
  
!   if (loop->latch->loop_father != loop)
      {
!       stack = (basic_block *) xmalloc (n_basic_blocks * sizeof (basic_block));
!       sp = 0;
        num_nodes++;
!       stack[sp++] = loop->latch;
!       loop->latch->loop_father = loop;
!       loop->latch->loop_depth = loop->depth;
!  
!       while (sp)
!         {
!           basic_block node;
!           edge e;
! 
!           node = stack[--sp];
!       
!           for (e = node->pred; e; e = e->pred_next)
!             {
!               basic_block ancestor = e->src;
! 
! 	      if (ancestor != ENTRY_BLOCK_PTR
! 	          && ancestor->loop_father != loop)
! 	        {
! 	          ancestor->loop_father = loop;
! 	          ancestor->loop_depth = loop->depth;
! 	          num_nodes++;
! 	          stack[sp++] = ancestor;
! 	        }
  	    }
!         }
!       free (stack);
      }
    return num_nodes;
  }
  
*************** flow_loop_pre_header_find (header, dom)
*** 461,528 ****
    return pre_header;
  }
  
! /* Add LOOP to the loop hierarchy tree where PREVLOOP was the loop
!    previously added.  The insertion algorithm assumes that the loops
!    are added in the order found by a depth first search of the CFG.  */
  
! static void
! flow_loop_tree_node_add (prevloop, loop)
!      struct loop *prevloop;
       struct loop *loop;
  {
! 
!   if (flow_loop_nested_p (prevloop, loop))
!     {
!       prevloop->inner = loop;
!       loop->outer = prevloop;
!       return;
!     }
! 
!   for (; prevloop->outer; prevloop = prevloop->outer)
!     if (flow_loop_nested_p (prevloop->outer, loop))
!       {
! 	prevloop->next = loop;
! 	loop->outer = prevloop->outer;
! 	return;
!       }
! 
!   prevloop->next = loop;
!   loop->outer = NULL;
  }
  
- /* Build the loop hierarchy tree for LOOPS.  */
- 
- static void
- flow_loops_tree_build (loops)
-      struct loops *loops;
- {
-   int i;
-   int num_loops;
- 
-   num_loops = loops->num;
-   if (! num_loops)
-     return;
- 
-   /* Root the loop hierarchy tree with the first loop found.
-      Since we used a depth first search this should be the
-      outermost loop.  */
-   loops->tree_root = &loops->array[0];
-   loops->tree_root->outer = loops->tree_root->inner
-     = loops->tree_root->next = NULL;
- 
-   /* Add the remaining loops to the tree.  */
-   for (i = 1; i < num_loops; i++)
-     flow_loop_tree_node_add (&loops->array[i - 1], &loops->array[i]);
- }
- 
  /* Helper function to compute loop nesting depth and enclosed loop level
     for the natural loop specified by LOOP at the loop depth DEPTH.
     Returns the loop level.  */
  
  static int
! flow_loop_level_compute (loop, depth)
       struct loop *loop;
-      int depth;
  {
    struct loop *inner;
    int level = 1;
--- 433,463 ----
    return pre_header;
  }
  
! /* Add LOOP to the loop hierarchy tree where FATHER is father of the
!    added loop.  */
  
! void
! flow_loop_tree_node_add (father, loop)
!      struct loop *father;
       struct loop *loop;
  {
!   loop->next = father->inner;
!   father->inner = loop;
!   loop->outer = father;
! 
!   loop->depth = father->depth + 1;
!   loop->pred = xmalloc (sizeof (struct loop *) * loop->depth);
!   memcpy (loop->pred, father->pred, sizeof (struct loop *) * father->depth);
!   loop->pred[father->depth] = father;
  }
  
  /* Helper function to compute loop nesting depth and enclosed loop level
     for the natural loop specified by LOOP at the loop depth DEPTH.
     Returns the loop level.  */
  
  static int
! flow_loop_level_compute (loop)
       struct loop *loop;
  {
    struct loop *inner;
    int level = 1;
*************** flow_loop_level_compute (loop, depth)
*** 537,549 ****
       itself).  */
    for (inner = loop->inner; inner; inner = inner->next)
      {
!       int ilevel = flow_loop_level_compute (inner, depth + 1) + 1;
  
!       level = MAX (ilevel, level);
      }
  
    loop->level = level;
-   loop->depth = depth;
    return level;
  }
  
--- 472,484 ----
       itself).  */
    for (inner = loop->inner; inner; inner = inner->next)
      {
!       int ilevel = flow_loop_level_compute (inner) + 1;
  
!       if (ilevel > level)
! 	level = ilevel;
      }
  
    loop->level = level;
    return level;
  }
  
*************** static int
*** 555,572 ****
  flow_loops_level_compute (loops)
       struct loops *loops;
  {
!   int levels = 0;
!   struct loop *loop;
!   int level;
! 
!   /* Traverse all the outer level loops.  */
!   for (loop = loops->tree_root; loop; loop = loop->next)
!     {
!       level = flow_loop_level_compute (loop, 1);
!       levels = MAX (levels, level);
!     }
! 
!   return levels;
  }
  
  /* Scan a single natural loop specified by LOOP collecting information
--- 490,496 ----
  flow_loops_level_compute (loops)
       struct loops *loops;
  {
!   return flow_loop_level_compute (loops->tree_root);
  }
  
  /* Scan a single natural loop specified by LOOP collecting information
*************** flow_loop_scan (loops, loop, flags)
*** 583,606 ****
      flags |= LOOP_EXIT_EDGES;
  
    if (flags & LOOP_ENTRY_EDGES)
!     /* Find edges which enter the loop header.  Note that the entry edges
!        should only enter the header of a natural loop.  */
!     loop->num_entries = flow_loop_entry_edges_find (loop->header, loop->nodes,
! 						    &loop->entry_edges);
  
    if (flags & LOOP_EXIT_EDGES)
!     /* Find edges which exit the loop.  */
!     loop->num_exits
!       = flow_loop_exit_edges_find (loop->nodes, &loop->exit_edges);
  
    if (flags & LOOP_EXITS_DOMS)
      {
        int j;
  
        /* Determine which loop nodes dominate all the exits
  	 of the loop.  */
        loop->exits_doms = sbitmap_alloc (n_basic_blocks);
!       sbitmap_copy (loop->exits_doms, loop->nodes);
        for (j = 0; j < loop->num_exits; j++)
  	sbitmap_a_and_b (loop->exits_doms, loop->exits_doms,
  			 loops->cfg.dom[loop->exit_edges[j]->src->index]);
--- 507,541 ----
      flags |= LOOP_EXIT_EDGES;
  
    if (flags & LOOP_ENTRY_EDGES)
!     {
!       /* Find edges which enter the loop header.
! 	 Note that the entry edges should only
! 	 enter the header of a natural loop.  */
!       flow_loop_entry_edges_find (loop);
!     }
  
    if (flags & LOOP_EXIT_EDGES)
!     {
!       /* Find edges which exit the loop.  */
!       flow_loop_exit_edges_find (loop);
!     }
  
+ /* Get rid of this bitmap.  */
    if (flags & LOOP_EXITS_DOMS)
      {
        int j;
+       basic_block *bbs;
  
        /* Determine which loop nodes dominate all the exits
  	 of the loop.  */
        loop->exits_doms = sbitmap_alloc (n_basic_blocks);
!       sbitmap_zero (loop->exits_doms);
! 
!       bbs = get_loop_body (loop);
!       for (j = 0; j < loop->num_nodes; j++)
!         SET_BIT (loop->exits_doms, bbs[j]->index);
!       free (bbs);
! 
        for (j = 0; j < loop->num_exits; j++)
  	sbitmap_a_and_b (loop->exits_doms, loop->exits_doms,
  			 loops->cfg.dom[loop->exit_edges[j]->src->index]);
*************** flow_loop_scan (loops, loop, flags)
*** 625,630 ****
--- 560,773 ----
    return 1;
  }
  
+ #define HEADER_BLOCK(B) (* (int *) (B)->aux)
+ #define LATCH_EDGE(E) (*(int *) (E)->aux)
+ 
+ /* Split BB into entry part and rest; if REDIRECT_LATCH, redirect edges
+    marked as latch into entry part, analogically for REDIRECT_NONLATCH.
+    In both of these cases, ignore edge EXCEPT.  If CONN_LATCH, set edge
+    between created entry part and BB as latch one.  Return created entry
+    part.  */
+ static basic_block
+ make_forwarder_block (bb, redirect_latch, redirect_nonlatch, except, conn_latch)
+      basic_block bb;
+      bool redirect_latch;
+      bool redirect_nonlatch;
+      edge except;
+      int conn_latch;
+ {
+   edge e, next_e;
+   basic_block dummy;
+   dummy = create_basic_block (n_basic_blocks, NULL, NULL);
+   dummy->frequency = 0;
+   dummy->aux = xmalloc (sizeof (int));
+   HEADER_BLOCK (dummy) = 0;
+ 
+   /* Redirect edges. */
+   for (e = bb->pred; e; e = next_e)
+     {
+       basic_block target, jump;
+       next_e = e->pred_next;
+       if (e != except &&
+            ((redirect_latch && LATCH_EDGE (e)) ||
+             (redirect_nonlatch && !LATCH_EDGE (e))))
+         {
+           target = dummy;
+           dummy->frequency += EDGE_FREQUENCY (e);
+           jump = redirect_edge_and_branch_force (e, target);
+           if (jump)
+             {
+               jump->aux = xmalloc (sizeof (int));
+               HEADER_BLOCK (jump) = 0;
+               jump->succ->aux = xmalloc (sizeof (int));
+               LATCH_EDGE (jump->succ) = LATCH_EDGE (e);
+             }
+         }
+     }
+   /* Make edge to bb.  */
+   e = make_single_succ_edge (dummy, bb, EDGE_FALLTHRU);
+   if (redirect_edge_and_branch_force (e, bb))
+     abort ();
+   e->aux = xmalloc (sizeof (int));
+   LATCH_EDGE (e) = conn_latch;
+   return dummy;
+ }
+ 
+ /* Creates a pre-header for a LOOP.  Returns newly created block.  */
+ basic_block
+ create_preheader (loop, dom)
+      struct loop *loop;
+      sbitmap *dom;
+ {
+   edge e, next_e;
+   basic_block dummy;
+   struct loop *cloop = NULL;
+   int nentry = 0;
+ 
+   for (e = loop->header->pred; e; e = e->pred_next)
+     {
+       if (e->src == loop->latch)
+         continue;
+       cloop = find_common_loop (cloop, e->src->loop_father);
+       nentry++;
+     }
+   if (!nentry)
+     abort ();
+   if (nentry == 1)
+     return NULL;
+ 
+   dummy = create_basic_block (n_basic_blocks, NULL, NULL);
+   dummy->frequency = 0;
+ 
+   /* Redirect edges. */
+   for (e = loop->header->pred; e; e = next_e)
+     {
+       basic_block jump, src;
+       next_e = e->pred_next;
+       src = e->src;
+ 
+       if (src == loop->latch)
+         continue;
+ 
+       dummy->frequency += EDGE_FREQUENCY (e);
+       jump = redirect_edge_and_branch_force (e, dummy);
+       if (jump)
+         {
+           set_immediate_dominator (dom, jump, src);
+           add_bb_to_loop (jump, src->loop_father);
+         }
+     }
+   /* Make edge to bb.  */
+   e = make_single_succ_edge (dummy, loop->header, EDGE_FALLTHRU);
+   if (redirect_edge_and_branch_force (e, loop->header))
+     abort ();
+   set_immediate_dominator (dom, dummy,
+    get_immediate_dominator (dom, loop->header));
+   set_immediate_dominator (dom, loop->header, dummy);
+   add_bb_to_loop (dummy, cloop);
+ 
+   return dummy;
+ }
+ 
+ /* Takes care of merging natural loops with shared headers.  */
+ static void
+ canonicalize_loop_headers ()
+ {
+   sbitmap *dom;
+   basic_block header;
+   edge e;
+   int b;
+   
+   /* Compute the dominators.  */
+   dom = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
+   calculate_dominance_info (NULL, dom, CDI_DOMINATORS);
+ 
+   alloc_aux_for_blocks (sizeof (int));
+   alloc_aux_for_edges (sizeof (int));
+ 
+   /* Split blocks so that each loop has only single latch.  */
+   for (b = 0; b < n_basic_blocks; b++)
+     {
+       int num_latches = 0;
+       int have_abnormal_edge = 0;
+ 
+       header = BASIC_BLOCK (b);
+ 
+       for (e = header->pred; e; e = e->pred_next)
+ 	{
+ 	  basic_block latch = e->src;
+ 
+           if (e->flags & EDGE_ABNORMAL)
+             have_abnormal_edge = 1;
+ 
+ 	  if (latch != ENTRY_BLOCK_PTR && TEST_BIT (dom[latch->index], b))
+             {
+ 	      num_latches++;
+               LATCH_EDGE (e) = 1;
+             }
+ 	}
+       if (have_abnormal_edge)
+         HEADER_BLOCK (header) = 0;
+       else
+         HEADER_BLOCK (header) = num_latches;
+     }
+ 
+   for (b = 0; b < n_basic_blocks; b = header->index + 1)
+     {
+       int num_latch;
+       int want_join_latch;
+       int max_freq, is_heavy;
+       edge heavy;
+ 
+       header = BASIC_BLOCK (b);
+       if (!HEADER_BLOCK (header))
+         continue;
+ 
+       num_latch = HEADER_BLOCK (header);
+ 
+       want_join_latch = (num_latch > 1);
+ 
+       if (!want_join_latch)
+         continue;
+ 
+       /* Find a heavy edge.  */
+       is_heavy = 1;
+       heavy = NULL;
+       max_freq = 0;
+ #define HEAVY_EDGE_RATIO 8
+       for (e = header->pred; e; e = e->pred_next)
+         if (LATCH_EDGE (e) &&
+             EDGE_FREQUENCY (e) > max_freq)
+           max_freq = EDGE_FREQUENCY (e);
+       for (e = header->pred; e; e = e->pred_next)
+         if (LATCH_EDGE (e) &&
+             EDGE_FREQUENCY (e) >= max_freq / HEAVY_EDGE_RATIO)
+           {
+             if (heavy)
+               {
+                 is_heavy = 0;
+                 break;
+               }
+             else
+               heavy = e;
+           }
+ 
+       if (is_heavy)
+         {
+           basic_block new_header =
+             make_forwarder_block (header, true, true, heavy, 0);
+           if (num_latch > 2)
+             make_forwarder_block (new_header, true, false, NULL, 1);
+         }
+       else
+         make_forwarder_block (header, true, false, NULL, 1);
+     }
+ 
+   free_aux_for_blocks ();
+   free_aux_for_edges ();
+   sbitmap_vector_free (dom);
+ }
+ 
  /* Find all the natural loops in the function and save in LOOPS structure and
     recalculate loop_depth information in basic block structures.  FLAGS
     controls which loop information is collected.  Return the number of natural
*************** flow_loops_find (loops, flags)
*** 643,648 ****
--- 786,793 ----
    sbitmap *dom;
    int *dfs_order;
    int *rc_order;
+   basic_block header;
+   int *imm_dom;
  
    /* This function cannot be repeatedly called with different
       flags to build up the loop information.  The loop tree
*************** flow_loops_find (loops, flags)
*** 660,697 ****
    dfs_order = NULL;
    rc_order = NULL;
  
    /* Compute the dominators.  */
!   dom = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
!   calculate_dominance_info (NULL, dom, CDI_DOMINATORS);
  
!   /* Count the number of loop edges (back edges).  This should be the
       same as the number of natural loops.  */
    num_loops = 0;
    for (b = 0; b < n_basic_blocks; b++)
      {
-       basic_block header;
- 
        header = BASIC_BLOCK (b);
        header->loop_depth = 0;
  
        for (e = header->pred; e; e = e->pred_next)
  	{
  	  basic_block latch = e->src;
  
  	  /* Look for back edges where a predecessor is dominated
  	     by this block.  A natural loop has a single entry
  	     node (header) that dominates all the nodes in the
  	     loop.  It also has single back edge to the header
! 	     from a latch node.  Note that multiple natural loops
! 	     may share the same header.  */
! 	  if (b != header->index)
! 	    abort ();
! 
  	  if (latch != ENTRY_BLOCK_PTR && TEST_BIT (dom[latch->index], b))
! 	    num_loops++;
  	}
      }
  
    if (num_loops)
      {
        /* Compute depth first search order of the CFG so that outer
--- 805,891 ----
    dfs_order = NULL;
    rc_order = NULL;
  
+   /* Join loops with shared headers.  */
+   canonicalize_loop_headers ();
+ 
    /* Compute the dominators.  */
!   loops->cfg.dom = dom = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
!   imm_dom = xmalloc (n_basic_blocks * sizeof (int));
!   for (i = 0; i < n_basic_blocks; i++)
!     imm_dom[i] = -1;
!   calculate_dominance_info (imm_dom, dom, CDI_DOMINATORS);
!   for (i = 0; i < n_basic_blocks; i++)
!     BASIC_BLOCK (i)->dominator =
!       imm_dom[i] < 0 ?  ENTRY_BLOCK_PTR : BASIC_BLOCK (imm_dom[i]);
!   free (imm_dom);
  
!   /* Count the number of loop headers.  This should be the
       same as the number of natural loops.  */
+   headers = sbitmap_alloc (n_basic_blocks);
+   sbitmap_zero (headers);
+ 
    num_loops = 0;
    for (b = 0; b < n_basic_blocks; b++)
      {
        header = BASIC_BLOCK (b);
        header->loop_depth = 0;
  
        for (e = header->pred; e; e = e->pred_next)
  	{
  	  basic_block latch = e->src;
+           int more_latches = 0;
+ 
+           if (e->flags & EDGE_ABNORMAL)
+             {
+               if (more_latches)
+                 {
+                   RESET_BIT (headers, b);
+                   num_loops--;
+                 }
+               break;
+             }
  
  	  /* Look for back edges where a predecessor is dominated
  	     by this block.  A natural loop has a single entry
  	     node (header) that dominates all the nodes in the
  	     loop.  It also has single back edge to the header
! 	     from a latch node.  */
  	  if (latch != ENTRY_BLOCK_PTR && TEST_BIT (dom[latch->index], b))
!             {
!               /* Shared headers should be eliminated by now.  */
!               if (more_latches)
!                 abort ();
!               more_latches = 1;
!               SET_BIT (headers, b);
! 	      num_loops++;
!             }
  	}
      }
  
+   /* Allocate loop structures.  */
+   loops->array = (struct loop **) xcalloc (num_loops + 1, sizeof (struct loop *));
+ 
+   /* Dummy loop containing whole function.  */
+   loops->array[0] = xcalloc (1, sizeof (struct loop));
+   loops->array[0]->next = NULL;
+   loops->array[0]->inner = NULL;
+   loops->array[0]->outer = NULL;
+   loops->array[0]->depth = 0;
+   loops->array[0]->pred = NULL;
+   loops->array[0]->num_nodes = n_basic_blocks + 2;
+   loops->array[0]->latch = EXIT_BLOCK_PTR;
+   loops->array[0]->header = ENTRY_BLOCK_PTR;
+   ENTRY_BLOCK_PTR->loop_father = loops->array[0];
+   EXIT_BLOCK_PTR->loop_father = loops->array[0];
+ 
+   loops->tree_root = loops->array[0];
+ 
+   /* Find and record information about all the natural loops
+      in the CFG.  */
+   loops->num = 1;
+   for (b = 0; b<n_basic_blocks; b++)
+     BASIC_BLOCK (b)->loop_father = loops->tree_root;
+ 
    if (num_loops)
      {
        /* Compute depth first search order of the CFG so that outer
*************** flow_loops_find (loops, flags)
*** 705,808 ****
        loops->cfg.dfs_order = dfs_order;
        loops->cfg.rc_order = rc_order;
  
!       /* Allocate loop structures.  */
!       loops->array
! 	= (struct loop *) xcalloc (num_loops, sizeof (struct loop));
! 
!       headers = sbitmap_alloc (n_basic_blocks);
!       sbitmap_zero (headers);
! 
!       loops->shared_headers = sbitmap_alloc (n_basic_blocks);
!       sbitmap_zero (loops->shared_headers);
! 
!       /* Find and record information about all the natural loops
! 	 in the CFG.  */
!       num_loops = 0;
!       for (b = n_basic_blocks - 1; b >= 0; b--)
! 	{
! 	  basic_block latch;
  
  	  /* Search the nodes of the CFG in reverse completion order
  	     so that we can find outer loops first.  */
! 	  latch = BASIC_BLOCK (rc_order[b]);
  
! 	  /* Look for all the possible headers for this latch block.  */
! 	  for (e = latch->succ; e; e = e->succ_next)
  	    {
! 	      basic_block header = e->dest;
  
! 	      /* Look for forward edges where this block is dominated by
! 		 a successor of this block.  A natural loop has a single
! 		 entry node (header) that dominates all the nodes in the
! 		 loop.  It also has single back edge to the header from a
! 		 latch node.  Note that multiple natural loops may share
! 		 the same header.  */
! 	      if (header != EXIT_BLOCK_PTR
  		  && TEST_BIT (dom[latch->index], header->index))
! 		{
! 		  struct loop *loop;
! 
! 		  loop = loops->array + num_loops;
! 
! 		  loop->header = header;
! 		  loop->latch = latch;
! 		  loop->num = num_loops;
! 
! 		  num_loops++;
! 		}
  	    }
- 	}
- 
-       for (i = 0; i < num_loops; i++)
- 	{
- 	  struct loop *loop = &loops->array[i];
  
! 	  /* Keep track of blocks that are loop headers so
! 	     that we can tell which loops should be merged.  */
! 	  if (TEST_BIT (headers, loop->header->index))
! 	    SET_BIT (loops->shared_headers, loop->header->index);
! 	  SET_BIT (headers, loop->header->index);
! 
! 	  /* Find nodes contained within the loop.  */
! 	  loop->nodes = sbitmap_alloc (n_basic_blocks);
! 	  loop->num_nodes
! 	    = flow_loop_nodes_find (loop->header, loop->latch, loop->nodes);
! 
! 	  /* Compute first and last blocks within the loop.
! 	     These are often the same as the loop header and
! 	     loop latch respectively, but this is not always
! 	     the case.  */
! 	  loop->first
! 	    = BASIC_BLOCK (sbitmap_first_set_bit (loop->nodes));
! 	  loop->last
! 	    = BASIC_BLOCK (sbitmap_last_set_bit (loop->nodes));
! 
! 	  flow_loop_scan (loops, loop, flags);
  	}
  
-       /* Natural loops with shared headers may either be disjoint or
- 	 nested.  Disjoint loops with shared headers cannot be inner
- 	 loops and should be merged.  For now just mark loops that share
- 	 headers.  */
-       for (i = 0; i < num_loops; i++)
- 	if (TEST_BIT (loops->shared_headers, loops->array[i].header->index))
- 	  loops->array[i].shared = 1;
- 
        sbitmap_free (headers);
-     }
-   else
-     sbitmap_vector_free (dom);
- 
-   loops->num = num_loops;
  
!   /* Build the loop hierarchy tree.  */
!   flow_loops_tree_build (loops);
  
!   /* Assign the loop nesting depth and enclosed loop level for each
!      loop.  */
!   loops->levels = flow_loops_level_compute (loops);
  
!   return num_loops;
  }
  
  /* Update the information regarding the loops in the CFG
--- 899,963 ----
        loops->cfg.dfs_order = dfs_order;
        loops->cfg.rc_order = rc_order;
  
!       num_loops = 1;
! 
!       for (b = 0; b < n_basic_blocks; b++)
!         {
!           struct loop *loop;
  
  	  /* Search the nodes of the CFG in reverse completion order
  	     so that we can find outer loops first.  */
!           if (!TEST_BIT (headers, rc_order[b]))
!             continue;
! 
!           header = BASIC_BLOCK (rc_order[b]);
!           
!           loop = loops->array[num_loops] = xcalloc (1, sizeof (struct loop));
! 
!           loop->header = header;
!           loop->num = num_loops;
!           num_loops++;
  
! 	  /* Look for the latch for this header block.  */
!           for (e = header->pred; e; e = e->pred_next)
  	    {
! 	      basic_block latch = e->src;
  
! 	      if (latch != ENTRY_BLOCK_PTR
  		  && TEST_BIT (dom[latch->index], header->index))
!                 {
!                   loop->latch = latch;
!                   break;
!                 }
  	    }
  
!           flow_loop_tree_node_add (header->loop_father, loop);
! 	  loop->num_nodes = flow_loop_nodes_find (loop->header, loop);
  	}
  
        sbitmap_free (headers);
  
!       /* Assign the loop nesting depth and enclosed loop level for each
!          loop.  */
!       loops->levels = flow_loops_level_compute (loops);
! 
!       /* Scan the loops.  */
!       for (i = 1; i < num_loops; i++)
!         flow_loop_scan (loops, loops->array[i], flags);
  
!       loops->num = num_loops;
!     }
!   else
!     {
!       loops->cfg.dom = NULL;
!       sbitmap_vector_free (dom);
!     }
! #ifdef ENABLE_CHECKING
!   verify_flow_info ();
!   verify_dominators ();
! #endif
  
!   return loops->num;
  }
  
  /* Update the information regarding the loops in the CFG
*************** flow_loops_update (loops, flags)
*** 821,836 ****
    return flow_loops_find (loops, flags);
  }
  
  /* Return non-zero if edge E enters header of LOOP from outside of LOOP.  */
  
! int
  flow_loop_outside_edge_p (loop, e)
       const struct loop *loop;
       edge e;
  {
    if (e->dest != loop->header)
      abort ();
  
!   return (e->src == ENTRY_BLOCK_PTR)
!     || ! TEST_BIT (loop->nodes, e->src->index);
  }
--- 976,1098 ----
    return flow_loops_find (loops, flags);
  }
  
+ /* Return non-zero if basic block BB belongs to LOOP.  */
+ bool
+ flow_bb_inside_loop_p (loop, bb)
+      const struct loop *loop;
+      const basic_block bb;
+ {
+   struct loop *source_loop;
+   if (bb == ENTRY_BLOCK_PTR || bb == EXIT_BLOCK_PTR) return 0;
+   source_loop = bb->loop_father;
+   return loop == source_loop || flow_loop_nested_p (loop, source_loop);
+ }
+ 
  /* Return non-zero if edge E enters header of LOOP from outside of LOOP.  */
  
! bool
  flow_loop_outside_edge_p (loop, e)
       const struct loop *loop;
       edge e;
  {
    if (e->dest != loop->header)
      abort ();
+   return !flow_bb_inside_loop_p (loop, e->src);
+ }
+ 
+ /* Gets basic blocks of a loop.  */
+ basic_block *
+ get_loop_body (loop)
+      const struct loop *loop;
+ {
+   basic_block *st, *tovisit, lbb;
+   int sp = 0, tv = 0;
+   if (!loop->num_nodes)
+     abort ();
+   tovisit = xcalloc (loop->num_nodes, sizeof (basic_block));
+   tovisit[tv++] = loop->header;
+   loop->header->flags |= BB_VISITED;
+   if (loop->latch == EXIT_BLOCK_PTR)
+     {
+       /* There may be blocks unreachable from EXIT_BLOCK.  */
+       if (loop->num_nodes != n_basic_blocks + 2)
+         abort ();
+       for (sp = 0; sp < n_basic_blocks; sp++)
+         tovisit[tv++] = BASIC_BLOCK(sp);
+       tovisit[tv++] = EXIT_BLOCK_PTR;
+     }
+   else if (loop->latch != loop->header)
+     {
+       st = xcalloc (loop->num_nodes, sizeof (basic_block));
+       tovisit[tv++] = st[sp++] = loop->latch;
+       loop->latch->flags |= BB_VISITED;
+       while (sp)
+         {
+           edge e;
+           lbb = st[--sp];
+           for (e = lbb->pred; e; e = e->pred_next)
+             if (!(e->src->flags & BB_VISITED))
+               {
+                 if (tv >= loop->num_nodes)
+                   abort ();
+                 tovisit[tv++] = st[sp++] = e->src;
+                 e->src->flags |= BB_VISITED;
+               }
+         }
+       free (st);
+     }
+   if (tv != loop->num_nodes)
+     abort ();
+   for (tv = 0; tv < loop->num_nodes; tv++)
+     tovisit[tv]->flags &= ~BB_VISITED;
+   return tovisit;
+ }
+ 
+ /* Adds basic block BB to LOOP.  */
+ void
+ add_bb_to_loop (bb, loop)
+      basic_block bb;
+      struct loop *loop;
+  {
+    int i;
+    bb->loop_father = loop;
+    bb->loop_depth = loop->depth;
+    loop->num_nodes++;
+    for (i = 0; i < loop->depth; i++)
+      loop->pred[i]->num_nodes++;
+  }
  
! /* Remove basic block BB from loops.  */
! void
! remove_bb_from_loops (bb)
!      basic_block bb;
!  {
!    int i;
!    struct loop *loop = bb->loop_father;
!    loop->num_nodes--;
!    for (i = 0; i < loop->depth; i++)
!      loop->pred[i]->num_nodes--;
!    bb->loop_father = NULL;
!    bb->loop_depth = 0;
!  }
! 
! /* Finds nearest common ancestor in loop tree for given loops.  */
! struct loop *
! find_common_loop (loop_s, loop_d)
!     struct loop *loop_s;
!     struct loop *loop_d;
! {
!   if (!loop_s) return loop_d;
!   if (!loop_d) return loop_s;
!   if (loop_s->depth < loop_d->depth)
!     loop_d = loop_d->pred[loop_s->depth];
!   else if (loop_s->depth > loop_d->depth)
!     loop_s = loop_s->pred[loop_d->depth];
!   while (loop_s != loop_d)
!     {
!       loop_s = loop_s->outer;
!       loop_d = loop_d->outer;
!     }
!   return loop_s;
  }
+ 



More information about the Gcc-patches mailing list