This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[lno] Cfgcleanup between loop optimizations


Hello,

this patch enables cfgcleanup to be run inside the loop optimizer.
Which is good since both loop unswitching and complete loop unrolling
keep conditions of type "if (0)" in the code in order to keep them
simple, and this patch actually makes it possible for the rest of
loop optimizations to take advantage of the simplifications caused
by them.

To achieve this,

1) cfgcleanup is a bit restricted when loop structures are available
   (basically just to protect the extra blocks needed to keep the loops
   in a canonical, easy to work with shape).  Not a problem.
2) Loop nesting and membership of basic blocks in loops needs to be
   recomputed from scratch (trying to keep these up-to-date is just
   too complicated; I did try this in the rtl level loop unswitching
   and it is one of the pieces of the code I will be really happy when
   it disappears).  Not a problem either -- it is fast enough and we
   should not lose any significant information in the process.
3) Loop closed SSA needs to be updated.  I think some people won't like
   it, but I cannot do anything else (save for severe restrictions of
   what cfgcleanup optimizes, which does not seem to be worth that).

Additionally, the patch fixes one more minor problem with the current code --
whole lot of loop optimizations handle specially loops with just single
exit, and uses loop->exit_edges[0] for accessing the exit.  Which has
several problems. First it is not obvious from the code that the optimization is
really interested only in single exit loops, and I think that on many
places we just forget to test it.  Second, noone nowhere cares to
update the exit_edges field, and it is nowhere verified that the loop
did not lose or gain new exits in some optimization.  So the patch adds
new field "single_exit" to the loop structure that has to be kept up-to-date by
all optimizations (and verify_loop_structure ensures that it indeed
happens).

Bootstrapped & regtested on i686.

Zdenek

Index: ChangeLog.lno
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/ChangeLog.lno,v
retrieving revision 1.1.2.230
diff -c -3 -p -r1.1.2.230 ChangeLog.lno
*** ChangeLog.lno	20 Jul 2004 15:11:05 -0000	1.1.2.230
--- ChangeLog.lno	22 Jul 2004 00:23:10 -0000
***************
*** 1,3 ****
--- 1,47 ----
+ 2004-07-22  Zdenek Dvorak  <rakdver@atrey.karlin.mff.cuni.cz>
+ 
+ 	* cfgloop.c (flow_loop_nodes_find): Export.
+ 	(mark_single_exit_loops): New functions.
+ 	(verify_loop_structure): Verify single_exit.
+ 	* cfgloop.h (struct loop): Add single_exit field.
+ 	(LOOPS_HAVE_MARKED_SINGLE_EXITS): New constant.
+ 	(flow_loop_nodes_find, fix_loop_structure, mark_single_exit_loops):
+ 	Declare.
+ 	* cfgloopmanip.c (update_single_exits_after_duplication,
+ 	fix_loop_structure): New functions.
+ 	(duplicate_loop_to_header_edge): Use
+ 	update_single_exits_after_duplication.
+ 	* tree-cfg.c (cleanup_tree_cfg_loop): New function.
+ 	(tree_can_merge_blocks_p, remove_bb, thread_jumps): Respect loop
+ 	structure.
+ 	* tree-elim-check.c (eliminate_redundant_checks): Use single_exit.
+ 	* tree-flow.h (cleanup_tree_cfg_loop): Declare.
+ 	* tree-scalar-evolution.c (get_loop_exit_condition,
+ 	get_exit_conditions_rec, number_of_iterations_in_loop): Use
+ 	single_exit.
+ 	(scev_initialize): Do not call flow_loop_scan.
+ 	* tree-ssa-loop-ivcanon.c (canonicalize_loop_induction_variables):
+ 	Indicate whether cfg has changed.
+ 	(tree_unroll_loops_completely): Call cleanup_tree_cfg_loop.
+ 	* tree-ssa-loop-ivopts.c (struct loop_data): Remove n_exits
+ 	and single_exit fields.
+ 	(find_exit_edges): Removed.
+ 	(tree_ssa_iv_optimize_init): Do not call find_exit_edges.
+ 	(single_dom_exit): New function.
+ 	(determine_number_of_iterations, add_iv_outer_candidates,
+ 	may_eliminate_iv, may_replace_final_value,
+ 	determine_use_iv_cost_outer, rewrite_use_outer,
+ 	tree_ssa_iv_optimize_loop): Use single_dom_exit.
+ 	* tree-ssa-loop-manip.c (tree_ssa_loop_version): Update single_exit.
+ 	(tree_duplicate_loop_to_exit_cfg): Use single_exit.
+ 	* tree-ssa-loop-unswitch.c (tree_unswitch_single_loop): Indicate
+ 	whether something have changed.
+ 	(tree_ssa_unswitch_loops): Call cleanup_tree_cfg_loop.
+ 	* tree-ssa-loop.c (tree_ssa_loop_init): Call mark_single_exit_loops.
+ 	* tree-vectorizer.c
+ 	(vect_update_initial_conditions_of_duplicacted_loop,
+ 	vect_transform_loop_bound, vect_transform_loop): Use single_exit.
+ 
  2004-07-20  Dorit Naishlos  <dorit@il.ibm.com>
  
          * tree-data-ref.h (init_data_ref): Additional argument is_read.
Index: cfgloop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgloop.c,v
retrieving revision 1.14.2.12.2.6
diff -c -3 -p -r1.14.2.12.2.6 cfgloop.c
*** cfgloop.c	6 Jul 2004 19:25:08 -0000	1.14.2.12.2.6
--- cfgloop.c	22 Jul 2004 00:23:10 -0000
*************** Software Foundation, 59 Temple Place - S
*** 41,47 ****
  static void flow_loops_cfg_dump (const struct loops *, FILE *);
  static void flow_loop_entry_edges_find (struct loop *);
  static void flow_loop_exit_edges_find (struct loop *);
- static int flow_loop_nodes_find (basic_block, struct loop *);
  static void flow_loop_pre_header_scan (struct loop *);
  static basic_block flow_loop_pre_header_find (basic_block);
  static int flow_loop_level_compute (struct loop *);
--- 41,46 ----
*************** flow_loop_exit_edges_find (struct loop *
*** 328,334 ****
  /* Find the nodes contained within the LOOP with header HEADER.
     Return the number of nodes within the loop.  */
  
! static int
  flow_loop_nodes_find (basic_block header, struct loop *loop)
  {
    basic_block *stack;
--- 327,333 ----
  /* Find the nodes contained within the LOOP with header HEADER.
     Return the number of nodes within the loop.  */
  
! int
  flow_loop_nodes_find (basic_block header, struct loop *loop)
  {
    basic_block *stack;
*************** flow_loop_nodes_find (basic_block header
*** 373,378 ****
--- 372,434 ----
    return num_nodes;
  }
  
+ /* For each loop in the lOOPS tree that has just a single exit
+    record the exit edge.  */
+ 
+ void
+ mark_single_exit_loops (struct loops *loops)
+ {
+   basic_block bb;
+   edge e;
+   struct loop *loop;
+   unsigned i;
+ 
+   for (i = 1; i < loops->num; i++)
+     {
+       loop = loops->parray[i];
+       if (loop)
+ 	loop->single_exit = NULL;
+     }
+ 
+   FOR_EACH_BB (bb)
+     {
+       if (bb->loop_father == loops->tree_root)
+ 	continue;
+       for (e = bb->succ; e; e = e->succ_next)
+ 	{
+ 	  if (e->dest == EXIT_BLOCK_PTR)
+ 	    continue;
+ 
+ 	  if (flow_bb_inside_loop_p (bb->loop_father, e->dest))
+ 	    continue;
+ 
+ 	  for (loop = bb->loop_father;
+ 	       loop != e->dest->loop_father;
+ 	       loop = loop->outer)
+ 	    {
+ 	      /* If we have already seen an exit, mark this by the edge that
+ 		 surely does not occur as any exit.  */
+ 	      if (loop->single_exit)
+ 		loop->single_exit = ENTRY_BLOCK_PTR->succ;
+ 	      else
+ 		loop->single_exit = e;
+ 	    }
+ 	}
+     }
+ 
+   for (i = 1; i < loops->num; i++)
+     {
+       loop = loops->parray[i];
+       if (!loop)
+ 	continue;
+ 
+       if (loop->single_exit == ENTRY_BLOCK_PTR->succ)
+ 	loop->single_exit = NULL;
+     }
+ 
+   loops->state |= LOOPS_HAVE_MARKED_SINGLE_EXITS;
+ }
+ 
  /* Find the root node of the loop pre-header extended basic block and
     the edges along the trace from the root node to the loop header.  */
  
*************** verify_loop_structure (struct loops *loo
*** 1259,1266 ****
  	}
      }
  
-   free (sizes);
- 
    /* Check get_loop_body.  */
    for (i = 1; i < loops->num; i++)
      {
--- 1315,1320 ----
*************** verify_loop_structure (struct loops *loo
*** 1381,1388 ****
--- 1435,1505 ----
        free (irreds);
      }
  
+   /* Check the single_exit.  */
+   if (loops->state & LOOPS_HAVE_MARKED_SINGLE_EXITS)
+     {
+       memset (sizes, 0, sizeof (unsigned) * loops->num);
+       FOR_EACH_BB (bb)
+ 	{
+ 	  if (bb->loop_father == loops->tree_root)
+ 	    continue;
+ 	  for (e = bb->succ; e; e = e->succ_next)
+ 	    {
+ 	      if (e->dest == EXIT_BLOCK_PTR)
+ 		continue;
+ 
+ 	      if (flow_bb_inside_loop_p (bb->loop_father, e->dest))
+ 		continue;
+ 
+ 	      for (loop = bb->loop_father;
+ 		   loop != e->dest->loop_father;
+ 		   loop = loop->outer)
+ 		{
+ 		  sizes[loop->num]++;
+ 		  if (loop->single_exit
+ 		      && loop->single_exit != e)
+ 		    {
+ 		      error ("Wrong single exit %d->%d recorded for loop %d.",
+ 			     loop->single_exit->src->index,
+ 			     loop->single_exit->dest->index,
+ 			     loop->num);
+ 		      error ("Right exit is %d->%d.",
+ 			     e->src->index, e->dest->index);
+ 		      err = 1;
+ 		    }
+ 		}
+ 	    }
+ 	}
+ 
+       for (i = 1; i < loops->num; i++)
+ 	{
+ 	  loop = loops->parray[i];
+ 	  if (!loop)
+ 	    continue;
+ 
+ 	  if (sizes[i] == 1
+ 	      && !loop->single_exit)
+ 	    {
+ 	      error ("Single exit not recorded for loop %d.", loop->num);
+ 	      err = 1;
+ 	    }
+ 
+ 	  if (sizes[i] != 1
+ 	      && loop->single_exit)
+ 	    {
+ 	      error ("Loop %d should not have single exit (%d -> %d).",
+ 		     loop->num,
+ 		     loop->single_exit->src->index,
+ 		     loop->single_exit->dest->index);
+ 	      err = 1;
+ 	    }
+ 	}
+     }
+ 
    if (err)
      abort ();
+ 
+   free (sizes);
  }
  
  /* Returns latch edge of LOOP.  */
Index: cfgloop.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgloop.h,v
retrieving revision 1.2.4.9.2.21
diff -c -3 -p -r1.2.4.9.2.21 cfgloop.h
*** cfgloop.h	18 Jul 2004 23:12:30 -0000	1.2.4.9.2.21
--- cfgloop.h	22 Jul 2004 00:23:10 -0000
*************** struct loop
*** 185,190 ****
--- 185,194 ----
  
    /* Upper bound on number of iterations of a loop.  */
    struct nb_iter_bound *bounds;
+ 
+   /* If not NULL, loop has just single exit edge stored here (edges to the
+      EXIT_BLOCK_PTR do not count.  */
+   edge single_exit;
  };
  
  /* Flags for state of loop structure.  */
*************** enum
*** 192,198 ****
  {
    LOOPS_HAVE_PREHEADERS = 1,
    LOOPS_HAVE_SIMPLE_LATCHES = 2,
!   LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS = 4
  };
  
  /* Structure to hold CFG information about natural loops within a function.  */
--- 196,203 ----
  {
    LOOPS_HAVE_PREHEADERS = 1,
    LOOPS_HAVE_SIMPLE_LATCHES = 2,
!   LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS = 4,
!   LOOPS_HAVE_MARKED_SINGLE_EXITS = 8
  };
  
  /* Structure to hold CFG information about natural loops within a function.  */
*************** extern void flow_loop_dump (const struct
*** 257,264 ****
  			    void (*)(const struct loop *, FILE *, int), int);
  extern int flow_loop_scan (struct loop *, int);
  extern void flow_loop_free (struct loop *);
! void mark_irreducible_loops (struct loops *);
  extern void create_loop_notes (void);
  
  /* Loop data structure manipulation/querying.  */
  extern void flow_loop_tree_node_add (struct loop *, struct loop *);
--- 262,272 ----
  			    void (*)(const struct loop *, FILE *, int), int);
  extern int flow_loop_scan (struct loop *, int);
  extern void flow_loop_free (struct loop *);
! extern int flow_loop_nodes_find (basic_block, struct loop *);
! void fix_loop_structure (struct loops *);
! void mark_single_exit_loops (struct loops *);
  extern void create_loop_notes (void);
+ extern void mark_irreducible_loops (struct loops *loops);
  
  /* Loop data structure manipulation/querying.  */
  extern void flow_loop_tree_node_add (struct loop *, struct loop *);
Index: cfgloopmanip.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgloopmanip.c,v
retrieving revision 1.3.2.11.2.12
diff -c -3 -p -r1.3.2.11.2.12 cfgloopmanip.c
*** cfgloopmanip.c	18 Jul 2004 23:12:31 -0000	1.3.2.11.2.12
--- cfgloopmanip.c	22 Jul 2004 00:23:10 -0000
*************** can_duplicate_loop_p (struct loop *loop)
*** 824,829 ****
--- 824,854 ----
    return ret;
  }
  
+ /* The NBBS blocks in BBS will get duplicated and the copies will be placed
+    to LOOP.  Update the single_exit information in superloops of LOOP.  */
+ 
+ static void
+ update_single_exits_after_duplication (basic_block *bbs, unsigned nbbs,
+ 				       struct loop *loop)
+ {
+   unsigned i;
+ 
+   for (i = 0; i < nbbs; i++)
+     bbs[i]->rbi->duplicated = 1;
+ 
+   for (; loop->outer; loop = loop->outer)
+     {
+       if (!loop->single_exit)
+ 	continue;
+ 
+       if (loop->single_exit->src->rbi->duplicated)
+ 	loop->single_exit = NULL;
+     }
+ 
+   for (i = 0; i < nbbs; i++)
+     bbs[i]->rbi->duplicated = 0;
+ }
+ 
  
  /* Duplicates body of LOOP to given edge E NDUPL times.  Takes care of updating
     LOOPS structure and dominators.  E's destination must be LOOP header for
*************** duplicate_loop_to_header_edge (struct lo
*** 967,972 ****
--- 992,1001 ----
        first_active_latch = latch;
      }
  
+   /* Update the information about single exits.  */
+   if (loops->state & LOOPS_HAVE_MARKED_SINGLE_EXITS)
+     update_single_exits_after_duplication (bbs, n, target);
+ 
    /* Record exit edge in original loop body.  */
    if (orig && TEST_BIT (wont_exit, 0))
      to_remove[(*n_to_remove)++] = orig;
*************** create_loop_notes (void)
*** 1345,1347 ****
--- 1374,1461 ----
      }
    flow_loops_free (&loops);
  }
+ 
+ /* The structure of LOOPS might have changed.  Some loops might get removed
+    (and their headers and latches were set to NULL), loop exists might get
+    removed (thus the loop nesting may be wrong), and some blocks and edges
+    were changed (so the information about bb --> loop mapping does not have
+    to be correct).  But still for the remaining loops the header dominates
+    the latch, and loops did not get new subloobs (new loops might possibly
+    get created, but we are not interested in them).  Fix up the mess.  */
+ 
+ void
+ fix_loop_structure (struct loops *loops)
+ {
+   basic_block bb;
+   struct loop *loop, *ploop;
+   unsigned i;
+ 
+   /* Remove the old bb -> loop mapping.  */
+   FOR_EACH_BB (bb)
+     {
+       bb->loop_father = loops->tree_root;
+     }
+ 
+   /* Remove the dead loops from structures.  */
+   loops->tree_root->num_nodes = n_basic_blocks + 2;
+   for (i = 1; i < loops->num; i++)
+     {
+       loop = loops->parray[i];
+       if (!loop)
+ 	continue;
+ 
+       loop->num_nodes = 0;
+       if (loop->header)
+ 	continue;
+ 
+       while (loop->inner)
+ 	{
+ 	  ploop = loop->inner;
+ 	  flow_loop_tree_node_remove (ploop);
+ 	  flow_loop_tree_node_add (loop->outer, ploop);
+ 	}
+ 
+       /* Remove the loop and free its data.  */
+       flow_loop_tree_node_remove (loop);
+       loops->parray[loop->num] = NULL;
+       flow_loop_free (loop);
+     }
+ 
+   /* Rescan the bodies of loops, starting from the outermost.  */
+   loop = loops->tree_root;
+   while (1)
+     {
+       if (loop->inner)
+ 	loop = loop->inner;
+       else
+ 	{
+ 	  while (!loop->next
+ 		 && loop != loops->tree_root)
+ 	    loop = loop->outer;
+ 	  if (loop == loops->tree_root)
+ 	    break;
+ 
+ 	  loop = loop->next;
+ 	}
+ 
+       loop->num_nodes = flow_loop_nodes_find (loop->header, loop);
+     }
+ 
+   /* Now fix the loop nesting.  */
+   for (i = 1; i < loops->num; i++)
+     {
+       loop = loops->parray[i];
+       if (!loop)
+ 	continue;
+ 
+       bb = loop_preheader_edge (loop)->src;
+       if (bb->loop_father != loop->outer)
+ 	{
+ 	  flow_loop_tree_node_remove (loop);
+ 	  flow_loop_tree_node_add (bb->loop_father, loop);
+ 	}
+     }
+ 
+   mark_single_exit_loops (loops);
+   mark_irreducible_loops (loops);
+ }
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-cfg.c,v
retrieving revision 1.1.4.244.2.23
diff -c -3 -p -r1.1.4.244.2.23 tree-cfg.c
*** tree-cfg.c	18 Jul 2004 23:13:33 -0000	1.1.4.244.2.23
--- tree-cfg.c	22 Jul 2004 00:23:10 -0000
*************** cleanup_tree_cfg (void)
*** 750,755 ****
--- 750,774 ----
    timevar_pop (TV_TREE_CLEANUP_CFG);
  }
  
+ /* Cleanup cfg and repair loop structures.  */
+ 
+ void
+ cleanup_tree_cfg_loop (void)
+ {
+   cleanup_tree_cfg ();
+ 
+   fix_loop_structure (current_loops);
+ 
+   /* This usually does nothing.  But sometimes parts of cfg that originally
+      were inside a loop get out of it due to edge removal (since they
+      become unreachable by back edges from latch).  */
+   rewrite_into_loop_closed_ssa ();
+ 
+ #ifdef ENABLE_CHECKING
+   verify_loop_structure (current_loops);
+ #endif
+ }
+ 
  
  /* Cleanup useless labels in basic blocks.  This is something we wish
     to do early because it allows us to group case labels before creating
*************** tree_can_merge_blocks_p (basic_block a, 
*** 1063,1068 ****
--- 1082,1092 ----
  	return false;
      }
  
+   /* Protect the loop latches.  */
+   if (current_loops
+       && b->loop_father->latch == b)
+     return false;
+ 
    return true;
  }
  
*************** remove_bb (basic_block bb)
*** 1810,1815 ****
--- 1834,1853 ----
  	}
      }
  
+   /* If we remove the header or the latch of a loop, mark the loop for
+      removal by setting its header and latch to NULL.  */
+   if (current_loops)
+     {
+       struct loop *loop = bb->loop_father;
+ 
+       if (loop->latch == bb
+ 	  || loop->header == bb)
+ 	{
+ 	  loop->latch = NULL;
+ 	  loop->header = NULL;
+ 	}
+     }
+ 
    /* Remove all the instructions in the block.  */
    for (i = bsi_start (bb); !bsi_end_p (i); bsi_remove (&i))
      {
*************** thread_jumps (void)
*** 3961,3966 ****
--- 3999,4017 ----
  	  break;
  
        bb_ann (bb)->forwardable = (e == NULL);
+ 
+       if (!current_loops)
+ 	continue;
+ 	  
+       /* Protect loop latches and preheaders.  */
+       if (!bb->succ
+ 	  || bb->succ->succ_next
+ 	  || bb->succ->dest == EXIT_BLOCK_PTR)
+ 	continue;
+ 
+       dest = bb->succ->dest;
+       if (dest->loop_father->header == dest)
+ 	bb_ann (bb)->forwardable = 0;
      }
  
    FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
Index: tree-elim-check.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-elim-check.c,v
retrieving revision 1.1.2.12
diff -c -3 -p -r1.1.2.12 tree-elim-check.c
*** tree-elim-check.c	6 Jul 2004 19:25:09 -0000	1.1.2.12
--- tree-elim-check.c	22 Jul 2004 00:23:10 -0000
*************** eliminate_redundant_checks (void)
*** 469,476 ****
  	  /* Don't try to prove anything about the loop exit
  	     conditions: avoid the block that contains the condition
  	     that guards the exit of the loop.  */
! 	  if (!loop->exit_edges
! 	      || loop->exit_edges[0]->src == bb)
  	    continue;
  	  
  	  for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
--- 469,476 ----
  	  /* Don't try to prove anything about the loop exit
  	     conditions: avoid the block that contains the condition
  	     that guards the exit of the loop.  */
! 	  if (!loop->single_exit
! 	      || loop->single_exit->src == bb)
  	    continue;
  	  
  	  for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-flow.h,v
retrieving revision 1.1.4.177.2.40
diff -c -3 -p -r1.1.4.177.2.40 tree-flow.h
*** tree-flow.h	18 Jul 2004 23:13:34 -0000	1.1.4.177.2.40
--- tree-flow.h	22 Jul 2004 00:23:10 -0000
*************** extern void print_loop_ir (FILE *);
*** 477,482 ****
--- 477,483 ----
  extern void cleanup_dead_labels (void);
  extern void group_case_labels (void);
  extern void cleanup_tree_cfg (void);
+ extern void cleanup_tree_cfg_loop (void);
  extern tree first_stmt (basic_block);
  extern tree last_stmt (basic_block);
  extern tree *last_stmt_ptr (basic_block);
Index: tree-scalar-evolution.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-scalar-evolution.c,v
retrieving revision 1.1.2.67
diff -c -3 -p -r1.1.2.67 tree-scalar-evolution.c
*** tree-scalar-evolution.c	12 Jul 2004 21:18:07 -0000	1.1.2.67
--- tree-scalar-evolution.c	22 Jul 2004 00:23:10 -0000
*************** tree 
*** 1001,1018 ****
  get_loop_exit_condition (struct loop *loop)
  {
    tree res = NULL_TREE;
    
    if (dump_file && (dump_flags & TDF_DETAILS))
      fprintf (dump_file, "(get_loop_exit_condition \n  ");
    
!   if (loop->exit_edges)
      {
-       edge exit_edge;
        tree expr;
        
-       exit_edge = loop->exit_edges[0];
        expr = last_stmt (exit_edge->src);
-       
        if (analyzable_condition (expr))
  	res = expr;
      }
--- 1001,1017 ----
  get_loop_exit_condition (struct loop *loop)
  {
    tree res = NULL_TREE;
+   edge exit_edge = loop->single_exit;
+ 
    
    if (dump_file && (dump_flags & TDF_DETAILS))
      fprintf (dump_file, "(get_loop_exit_condition \n  ");
    
!   if (exit_edge)
      {
        tree expr;
        
        expr = last_stmt (exit_edge->src);
        if (analyzable_condition (expr))
  	res = expr;
      }
*************** get_exit_conditions_rec (struct loop *lo
*** 1039,1046 ****
    get_exit_conditions_rec (loop->inner, exit_conditions);
    get_exit_conditions_rec (loop->next, exit_conditions);
    
!   flow_loop_scan (loop, LOOP_EXIT_EDGES);
!   if (loop->num_exits == 1)
      {
        tree loop_condition = get_loop_exit_condition (loop);
        
--- 1038,1044 ----
    get_exit_conditions_rec (loop->inner, exit_conditions);
    get_exit_conditions_rec (loop->next, exit_conditions);
    
!   if (loop->single_exit)
      {
        tree loop_condition = get_loop_exit_condition (loop);
        
*************** number_of_iterations_in_loop (struct loo
*** 2185,2193 ****
    if (dump_file && (dump_flags & TDF_DETAILS))
      fprintf (dump_file, "(number_of_iterations_in_loop\n");
    
!   if (!loop->exit_edges)
      goto end;
-   exit = loop->exit_edges[0];
  
    if (!number_of_iterations_exit (loop, exit, &niter_desc))
      goto end;
--- 2183,2191 ----
    if (dump_file && (dump_flags & TDF_DETAILS))
      fprintf (dump_file, "(number_of_iterations_in_loop\n");
    
!   exit = loop->single_exit;
!   if (!exit)
      goto end;
  
    if (!number_of_iterations_exit (loop, exit, &niter_desc))
      goto end;
*************** scev_initialize (struct loops *loops)
*** 2458,2467 ****
  
    for (i = 1; i < loops->num; i++)
      if (loops->parray[i])
!       {
! 	flow_loop_scan (loops->parray[i], LOOP_EXIT_EDGES);
! 	loops->parray[i]->nb_iterations = NULL_TREE;
!       }
  }
  
  /* Cleans up the information cached by the scalar evolutions analysis.  */
--- 2456,2462 ----
  
    for (i = 1; i < loops->num; i++)
      if (loops->parray[i])
!       loops->parray[i]->nb_iterations = NULL_TREE;
  }
  
  /* Cleans up the information cached by the scalar evolutions analysis.  */
Index: tree-ssa-loop-ivcanon.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-loop-ivcanon.c,v
retrieving revision 1.1.2.17
diff -c -3 -p -r1.1.2.17 tree-ssa-loop-ivcanon.c
*** tree-ssa-loop-ivcanon.c	7 Jul 2004 15:11:06 -0000	1.1.2.17
--- tree-ssa-loop-ivcanon.c	22 Jul 2004 00:23:10 -0000
*************** try_unroll_loop_completely (struct loops
*** 179,187 ****
     tree.  CREATE_IV is true if we may create a new iv.  COMPLETELY_UNROLL is
     true if we should do complete unrolling even if it may cause the code
     growth.  If TRY_EVAL is true, we try to determine the number of iterations
!    of a loop by direct evaluation.  */
  
! static void
  canonicalize_loop_induction_variables (struct loops *loops, struct loop *loop,
  				       bool create_iv, bool completely_unroll,
  				       bool try_eval)
--- 179,187 ----
     tree.  CREATE_IV is true if we may create a new iv.  COMPLETELY_UNROLL is
     true if we should do complete unrolling even if it may cause the code
     growth.  If TRY_EVAL is true, we try to determine the number of iterations
!    of a loop by direct evaluation.  Returns true if cfg is changed.  */
  
! static bool
  canonicalize_loop_induction_variables (struct loops *loops, struct loop *loop,
  				       bool create_iv, bool completely_unroll,
  				       bool try_eval)
*************** canonicalize_loop_induction_variables (s
*** 192,200 ****
    niter = number_of_iterations_in_loop (loop);
    if (TREE_CODE (niter) == INTEGER_CST)
      {
!       exit = loop->exit_edges[0];
        if (!just_once_each_iteration_p (loop, exit->src))
! 	return;
  
        /* The result of number_of_iterations_in_loop is by one higher than
  	 we expect (i.e. it returns number of executions of the exit
--- 192,200 ----
    niter = number_of_iterations_in_loop (loop);
    if (TREE_CODE (niter) == INTEGER_CST)
      {
!       exit = loop->single_exit;
        if (!just_once_each_iteration_p (loop, exit->src))
! 	return false;
  
        /* The result of number_of_iterations_in_loop is by one higher than
  	 we expect (i.e. it returns number of executions of the exit
*************** canonicalize_loop_induction_variables (s
*** 208,214 ****
  
    if (chrec_contains_undetermined (niter)
        || TREE_CODE (niter) != INTEGER_CST)
!     return;
  
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
--- 208,214 ----
  
    if (chrec_contains_undetermined (niter)
        || TREE_CODE (niter) != INTEGER_CST)
!     return false;
  
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
*************** canonicalize_loop_induction_variables (s
*** 218,227 ****
      }
  
    if (try_unroll_loop_completely (loops, loop, exit, niter, completely_unroll))
!     return;
  
    if (create_iv)
      create_canonical_iv (loop, exit, niter);
  }
  
  /* The main entry point of the pass.  Adds canonical induction variables
--- 218,229 ----
      }
  
    if (try_unroll_loop_completely (loops, loop, exit, niter, completely_unroll))
!     return true;
  
    if (create_iv)
      create_canonical_iv (loop, exit, niter);
+ 
+   return false;
  }
  
  /* The main entry point of the pass.  Adds canonical induction variables
*************** tree_unroll_loops_completely (struct loo
*** 249,261 ****
  {
    unsigned i;
    struct loop *loop;
  
    for (i = 1; i < loops->num; i++)
      {
        loop = loops->parray[i];
  
!       if (loop)
! 	canonicalize_loop_induction_variables (loops, loop, false, true,
! 					       !flag_ivcanon);
      }
  }
--- 251,270 ----
  {
    unsigned i;
    struct loop *loop;
+   bool changed = false;
  
    for (i = 1; i < loops->num; i++)
      {
        loop = loops->parray[i];
  
!       if (!loop)
! 	continue;
! 
!       changed |= canonicalize_loop_induction_variables (loops, loop,
! 							false, true,
! 							!flag_ivcanon);
      }
+ 
+   if (changed)
+     cleanup_tree_cfg_loop ();
  }
Index: tree-ssa-loop-ivopts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-loop-ivopts.c,v
retrieving revision 1.1.2.46
diff -c -3 -p -r1.1.2.46 tree-ssa-loop-ivopts.c
*** tree-ssa-loop-ivopts.c	18 Jul 2004 23:13:38 -0000	1.1.2.46
--- tree-ssa-loop-ivopts.c	22 Jul 2004 00:23:10 -0000
*************** struct version_info
*** 124,132 ****
  /* Information attached to loop.  */
  struct loop_data
  {
-   unsigned n_exits;	/* Number of exit edges.  */
-   edge single_exit;	/* The exit edge in case there is exactly one and
- 			   its source dominates the loops latch.  */
    struct tree_niter_desc niter;
  			/* Number of iterations.  */
  
--- 124,129 ----
*************** loop_data (struct loop *loop)
*** 283,288 ****
--- 280,301 ----
    return loop->aux;
  }
  
+ /* The single loop exit if it dominates the latch, NULL otherwise.  */
+ 
+ static edge
+ single_dom_exit (struct loop *loop)
+ {
+   edge exit = loop->single_exit;
+ 
+   if (!exit)
+     return NULL;
+ 
+   if (!just_once_each_iteration_p (loop, exit->src))
+     return NULL;
+ 
+   return exit;
+ }
+ 
  /* Dumps information about the induction variable IV to FILE.  */
  
  extern void dump_iv (FILE *, struct iv *);
*************** array2ptr (tree type)
*** 758,797 ****
    return build_pointer_type (TREE_TYPE (type));
  }
  
- /* Sets single_exit field for loops.  */
- 
- static void
- find_exit_edges (void)
- {
-   basic_block bb;
-   edge e;
-   struct loop *src, *dest;;
- 
-   FOR_EACH_BB (bb)
-     {
-       for (e = bb->succ; e; e = e->succ_next)
- 	{
- 	  src = e->src->loop_father;
- 	  dest = find_common_loop (src, e->dest->loop_father);
- 
- 	  for (; src != dest; src = src->outer)
- 	    {
- 	      loop_data (src)->n_exits++;
- 	      if (loop_data (src)->n_exits > 1)
- 		{
- 		  loop_data (src)->single_exit = NULL;
- 		  continue;
- 		}
- 
- 	      if (!dominated_by_p (CDI_DOMINATORS, src->latch, e->src))
- 		continue;
- 
- 	      loop_data (src)->single_exit = e;
- 	    }
- 	}
-     }
- }
- 
  /* Returns the basic block in that statements should be emitted for IP_END
     position in LOOP.  */
  
--- 771,776 ----
*************** tree_ssa_iv_optimize_init (struct loops 
*** 941,948 ****
      if (loops->parray[i])
        loops->parray[i]->aux = xcalloc (1, sizeof (struct loop_data));
  
-   find_exit_edges ();
- 
    VARRAY_GENERIC_PTR_NOGC_INIT (data->iv_uses, 20, "iv_uses");
    VARRAY_GENERIC_PTR_NOGC_INIT (data->iv_candidates, 20, "iv_candidates");
    VARRAY_GENERIC_PTR_NOGC_INIT (decl_rtl_to_reset, 20, "decl_rtl_to_reset");
--- 920,925 ----
*************** static void
*** 1231,1237 ****
  determine_number_of_iterations (struct ivopts_data *data)
  {
    struct loop *loop = data->current_loop;
!   edge exit = loop_data (loop)->single_exit;
  
    if (!exit)
      return;
--- 1208,1214 ----
  determine_number_of_iterations (struct ivopts_data *data)
  {
    struct loop *loop = data->current_loop;
!   edge exit = single_dom_exit (loop);
  
    if (!exit)
      return;
*************** add_iv_outer_candidates (struct ivopts_d
*** 2021,2027 ****
    struct loop *loop = data->current_loop;
  
    /* We must know where we exit the loop and how many times does it roll.  */
!   if (!loop_data (loop)->single_exit)
      return;
  
    niter = &loop_data (loop)->niter;
--- 1998,2004 ----
    struct loop *loop = data->current_loop;
  
    /* We must know where we exit the loop and how many times does it roll.  */
!   if (!single_dom_exit (loop))
      return;
  
    niter = &loop_data (loop)->niter;
*************** may_eliminate_iv (struct loop *loop,
*** 3232,3238 ****
    /* For now just very primitive -- we work just for the single exit condition,
       and are quite conservative about the possible overflows.  TODO -- both of
       these can be improved.  */
!   exit = loop_data (loop)->single_exit;
    if (!exit)
      return false;
    if (use->stmt != last_stmt (exit->src))
--- 3209,3215 ----
    /* For now just very primitive -- we work just for the single exit condition,
       and are quite conservative about the possible overflows.  TODO -- both of
       these can be improved.  */
!   exit = single_dom_exit (loop);
    if (!exit)
      return false;
    if (use->stmt != last_stmt (exit->src))
*************** may_replace_final_value (struct loop *lo
*** 3325,3331 ****
    edge exit;
    struct tree_niter_desc *niter;
  
!   exit = loop_data (loop)->single_exit;
    if (!exit)
      return false;
  
--- 3302,3308 ----
    edge exit;
    struct tree_niter_desc *niter;
  
!   exit = single_dom_exit (loop);
    if (!exit)
      return false;
  
*************** determine_use_iv_cost_outer (struct ivop
*** 3373,3379 ****
        return;
      }
  
!   exit = loop_data (loop)->single_exit;
    if (exit)
      {
        /* If there is just a single exit, we may use value of the candidate
--- 3350,3356 ----
        return;
      }
  
!   exit = single_dom_exit (loop);
    if (exit)
      {
        /* If there is just a single exit, we may use value of the candidate
*************** rewrite_use_outer (struct ivopts_data *d
*** 4462,4468 ****
      tgt = TREE_OPERAND (use->stmt, 0);
    else
      abort ();
!   exit = loop_data (data->current_loop)->single_exit;
  
    if (exit)
      {
--- 4439,4445 ----
      tgt = TREE_OPERAND (use->stmt, 0);
    else
      abort ();
!   exit = single_dom_exit (data->current_loop);
  
    if (exit)
      {
*************** tree_ssa_iv_optimize_loop (struct ivopts
*** 4675,4696 ****
  {
    bool changed = false;
    bitmap iv_set;
  
    data->current_loop = loop;
  
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
        fprintf (dump_file, "Processing loop %d\n", loop->num);
!       fprintf (dump_file, "  %d exits\n", loop_data (loop)->n_exits);
!       if (loop_data (loop)->single_exit)
  	{
- 	  edge ex = loop_data (loop)->single_exit;
- 
  	  fprintf (dump_file, "  single exit %d -> %d, exit condition ",
! 		   ex->src->index, ex->dest->index);
! 	  print_generic_expr (dump_file, last_stmt (ex->src), TDF_SLIM);
  	  fprintf (dump_file, "\n");
  	}
        fprintf (dump_file, "\n");
      }
  
--- 4652,4674 ----
  {
    bool changed = false;
    bitmap iv_set;
+   edge exit;
  
    data->current_loop = loop;
  
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
        fprintf (dump_file, "Processing loop %d\n", loop->num);
!       
!       exit = single_dom_exit (loop);
!       if (exit)
  	{
  	  fprintf (dump_file, "  single exit %d -> %d, exit condition ",
! 		   exit->src->index, exit->dest->index);
! 	  print_generic_expr (dump_file, last_stmt (exit->src), TDF_SLIM);
  	  fprintf (dump_file, "\n");
  	}
+ 
        fprintf (dump_file, "\n");
      }
  
Index: tree-ssa-loop-manip.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-loop-manip.c,v
retrieving revision 1.1.2.25
diff -c -3 -p -r1.1.2.25 tree-ssa-loop-manip.c
*** tree-ssa-loop-manip.c	19 Jul 2004 15:28:40 -0000	1.1.2.25
--- tree-ssa-loop-manip.c	22 Jul 2004 00:23:10 -0000
*************** struct loop *
*** 596,602 ****
  tree_ssa_loop_version (struct loops *loops, struct loop * loop, 
  		       tree cond_expr, basic_block *condition_bb)
  {
!   edge entry, latch_edge;
    basic_block first_head, second_head;
    int irred_flag;
    struct loop *nloop;
--- 596,602 ----
  tree_ssa_loop_version (struct loops *loops, struct loop * loop, 
  		       tree cond_expr, basic_block *condition_bb)
  {
!   edge entry, latch_edge, exit;
    basic_block first_head, second_head;
    int irred_flag;
    struct loop *nloop;
*************** tree_ssa_loop_version (struct loops *loo
*** 636,641 ****
--- 636,645 ----
  		   *condition_bb,
  		   false /* Do not redirect all edges.  */);
  
+   exit = loop->single_exit;
+   if (exit)
+     nloop->single_exit = find_edge (exit->src->rbi->copy, exit->dest);
+ 
    /* loopify redirected latch_edge. Update its PENDING_STMTS.  */ 
    lv_update_pending_stmts (latch_edge);
  
*************** tree_duplicate_loop_to_exit_cfg (struct 
*** 1056,1064 ****
    unsigned i; 
    unsigned  n = loop->num_nodes;
    struct loop *new_loop;
!   basic_block exit_dest = loop->exit_edges[0]->dest;
    bool was_imm_dom;
    
    was_imm_dom = (get_immediate_dominator 
  		       (CDI_DOMINATORS, exit_dest) == loop->header ? 
  		       true : false);
--- 1060,1077 ----
    unsigned i; 
    unsigned  n = loop->num_nodes;
    struct loop *new_loop;
!   basic_block exit_dest;
    bool was_imm_dom;
    
+   if (!loop->single_exit)
+     {
+       if (dump_file && (dump_flags & TDF_DETAILS))
+ 	  fprintf (dump_file,
+ 		   "Loop does not have a single exit.\n");
+       return false;
+     }
+ 
+   exit_dest = loop->single_exit->dest;
    was_imm_dom = (get_immediate_dominator 
  		       (CDI_DOMINATORS, exit_dest) == loop->header ? 
  		       true : false);
*************** tree_duplicate_loop_to_exit_cfg (struct 
*** 1115,1120 ****
--- 1128,1134 ----
        return false;
  
      }
+ 
    /* FIXME: Should we copy contents of the loop structure
       to the new loop?  */
  
*************** tree_duplicate_loop_to_exit_cfg (struct 
*** 1123,1143 ****
      new_bbs[i]->rbi->copy_number = 1;
  
    /* Redirect the special edges.  */
!   if(!exit_dest)
!     {
!       if (dump_file && (dump_flags & TDF_DETAILS))
! 	  fprintf (dump_file,
! 		   "First exit basic block of loop is NULL.\n");
!       return false;
!     }
!     
!   
!   redirect_edge_and_branch_force (loop->exit_edges[0],
! 				  new_bbs[0]);
!   set_immediate_dominator (CDI_DOMINATORS, new_bbs[0], loop->exit_edges[0]->src); 
    if (was_imm_dom)
      set_immediate_dominator (CDI_DOMINATORS, exit_dest, new_loop->header);
!   
    free (new_bbs);
    free (bbs);
  
--- 1137,1149 ----
      new_bbs[i]->rbi->copy_number = 1;
  
    /* Redirect the special edges.  */
!   exit_dest = loop->single_exit->dest;
! 
!   redirect_edge_and_branch_force (loop->single_exit, new_bbs[0]);
!   set_immediate_dominator (CDI_DOMINATORS, new_bbs[0], loop->single_exit->src); 
    if (was_imm_dom)
      set_immediate_dominator (CDI_DOMINATORS, exit_dest, new_loop->header);
! 
    free (new_bbs);
    free (bbs);
  
Index: tree-ssa-loop-unswitch.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-loop-unswitch.c,v
retrieving revision 1.1.2.2
diff -c -3 -p -r1.1.2.2 tree-ssa-loop-unswitch.c
*** tree-ssa-loop-unswitch.c	30 Mar 2004 01:39:54 -0000	1.1.2.2
--- tree-ssa-loop-unswitch.c	22 Jul 2004 00:23:10 -0000
*************** Software Foundation, 59 Temple Place - S
*** 75,81 ****
  
  static struct loop *tree_unswitch_loop (struct loops *, struct loop *, basic_block,
  				   tree);
! static void tree_unswitch_single_loop (struct loops *, struct loop *, int);
  static tree tree_may_unswitch_on (basic_block, struct loop *);
  
  /* Main entry point.  Perform loop unswitching on all suitable LOOPS.  */
--- 75,81 ----
  
  static struct loop *tree_unswitch_loop (struct loops *, struct loop *, basic_block,
  				   tree);
! static bool tree_unswitch_single_loop (struct loops *, struct loop *, int);
  static tree tree_may_unswitch_on (basic_block, struct loop *);
  
  /* Main entry point.  Perform loop unswitching on all suitable LOOPS.  */
*************** tree_ssa_unswitch_loops (struct loops *l
*** 85,90 ****
--- 85,91 ----
  {
    int i, num;
    struct loop *loop;
+   bool changed = false;
  
    /* Go through inner loops (only original ones).  */
    num = loops->num;
*************** tree_ssa_unswitch_loops (struct loops *l
*** 99,110 ****
        if (loop->inner)
  	continue;
  
!       tree_unswitch_single_loop (loops, loop, 0);
  #ifdef ENABLE_CHECKING
        verify_dominators (CDI_DOMINATORS);
        verify_loop_structure (loops);
  #endif
      }
  }
  
  /* Checks whether we can unswitch LOOP on condition at end of BB -- one of its
--- 100,114 ----
        if (loop->inner)
  	continue;
  
!       changed |= tree_unswitch_single_loop (loops, loop, 0);
  #ifdef ENABLE_CHECKING
        verify_dominators (CDI_DOMINATORS);
        verify_loop_structure (loops);
  #endif
      }
+ 
+   if (changed)
+     cleanup_tree_cfg_loop ();
  }
  
  /* Checks whether we can unswitch LOOP on condition at end of BB -- one of its
*************** simplify_using_entry_checks (struct loop
*** 178,197 ****
     it to grow too much, it is too easy to create example on that the code would
     grow exponentially.  */
  
! static void
  tree_unswitch_single_loop (struct loops *loops, struct loop *loop, int num)
  {
    basic_block *bbs;
    struct loop *nloop;
    unsigned i;
    tree cond = NULL_TREE, stmt;
  
    /* Do not unswitch too much.  */
    if (num > PARAM_VALUE (PARAM_MAX_UNSWITCH_LEVEL))
      {
        if (dump_file && (dump_flags & TDF_DETAILS))
  	fprintf (dump_file, ";; Not unswitching anymore, hit max level\n");
!       return;
      }
  
    /* Only unswitch innermost loops.  */
--- 182,202 ----
     it to grow too much, it is too easy to create example on that the code would
     grow exponentially.  */
  
! static bool
  tree_unswitch_single_loop (struct loops *loops, struct loop *loop, int num)
  {
    basic_block *bbs;
    struct loop *nloop;
    unsigned i;
    tree cond = NULL_TREE, stmt;
+   bool changed = false;
  
    /* Do not unswitch too much.  */
    if (num > PARAM_VALUE (PARAM_MAX_UNSWITCH_LEVEL))
      {
        if (dump_file && (dump_flags & TDF_DETAILS))
  	fprintf (dump_file, ";; Not unswitching anymore, hit max level\n");
!       return false;
      }
  
    /* Only unswitch innermost loops.  */
*************** tree_unswitch_single_loop (struct loops 
*** 199,205 ****
      {
        if (dump_file && (dump_flags & TDF_DETAILS))
  	fprintf (dump_file, ";; Not unswitching, not innermost loop\n");
!       return;
      }
  
    /* The loop should not be too large, to limit code growth.  */
--- 204,210 ----
      {
        if (dump_file && (dump_flags & TDF_DETAILS))
  	fprintf (dump_file, ";; Not unswitching, not innermost loop\n");
!       return false;
      }
  
    /* The loop should not be too large, to limit code growth.  */
*************** tree_unswitch_single_loop (struct loops 
*** 208,214 ****
      {
        if (dump_file && (dump_flags & TDF_DETAILS))
  	fprintf (dump_file, ";; Not unswitching, loop too big\n");
!       return;
      }
  
    i = 0;
--- 213,219 ----
      {
        if (dump_file && (dump_flags & TDF_DETAILS))
  	fprintf (dump_file, ";; Not unswitching, loop too big\n");
!       return false;
      }
  
    i = 0;
*************** tree_unswitch_single_loop (struct loops 
*** 224,230 ****
        if (i == loop->num_nodes)
  	{
  	  free (bbs);
! 	  return;
  	}
  
        cond = simplify_using_entry_checks (loop, cond);
--- 229,235 ----
        if (i == loop->num_nodes)
  	{
  	  free (bbs);
! 	  return changed;
  	}
  
        cond = simplify_using_entry_checks (loop, cond);
*************** tree_unswitch_single_loop (struct loops 
*** 233,243 ****
--- 238,250 ----
  	{
  	  /* Remove false path.  */
  	  COND_EXPR_COND (stmt) = boolean_true_node;
+ 	  changed = true;
  	}
        else if (integer_zerop (cond))
  	{
  	  /* Remove true path.  */
  	  COND_EXPR_COND (stmt) = boolean_false_node;
+ 	  changed = true;
  	}
        else
  	break;
*************** tree_unswitch_single_loop (struct loops 
*** 252,262 ****
    /* Unswitch the loop on this condition.  */
    nloop = tree_unswitch_loop (loops, loop, bbs[i], cond);
    if (!nloop)
!     return;
  
    /* Invoke itself on modified loops.  */
    tree_unswitch_single_loop (loops, nloop, num + 1);
    tree_unswitch_single_loop (loops, loop, num + 1);
  }
  
  /* Unswitch a LOOP w.r. to given basic block UNSWITCH_ON.  We only support
--- 259,270 ----
    /* Unswitch the loop on this condition.  */
    nloop = tree_unswitch_loop (loops, loop, bbs[i], cond);
    if (!nloop)
!     return changed;
  
    /* Invoke itself on modified loops.  */
    tree_unswitch_single_loop (loops, nloop, num + 1);
    tree_unswitch_single_loop (loops, loop, num + 1);
+   return true;
  }
  
  /* Unswitch a LOOP w.r. to given basic block UNSWITCH_ON.  We only support
Index: tree-ssa-loop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-loop.c,v
retrieving revision 1.1.2.3.2.28
diff -c -3 -p -r1.1.2.3.2.28 tree-ssa-loop.c
*** tree-ssa-loop.c	18 Jul 2004 23:13:38 -0000	1.1.2.3.2.28
--- tree-ssa-loop.c	22 Jul 2004 00:23:10 -0000
*************** tree_ssa_loop_init (void)
*** 110,115 ****
--- 110,119 ----
    current_loops = tree_loop_optimizer_init (dump_file, true);
    if (!current_loops)
      return;
+       
+   /* Find the loops that are exitted just through a single edge.  */
+   mark_single_exit_loops (current_loops);
+       
    scev_initialize (current_loops);
  }
  
Index: tree-vectorizer.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-vectorizer.c,v
retrieving revision 1.1.2.54
diff -c -3 -p -r1.1.2.54 tree-vectorizer.c
*** tree-vectorizer.c	20 Jul 2004 15:11:05 -0000	1.1.2.54
--- tree-vectorizer.c	22 Jul 2004 00:23:11 -0000
*************** vect_update_initial_conditions_of_duplic
*** 1573,1584 ****
    edge latch = loop_latch_edge (loop);
    tree phi;
    block_stmt_iterator interm_bb_last_bsi;
!   basic_block intermediate_bb = loop->exit_edges[0]->dest;
    edge inter_bb_true_edge;
    basic_block exit_bb;
  
    /* Find edge from intermediate bb to new loop header.  */
!   pe = find_edge (loop->exit_edges[0]->dest, new_loop_header);
    inter_bb_true_edge = find_edge (intermediate_bb, new_loop_exit->dest);
    exit_bb = new_loop_exit->dest;
    
--- 1573,1584 ----
    edge latch = loop_latch_edge (loop);
    tree phi;
    block_stmt_iterator interm_bb_last_bsi;
!   basic_block intermediate_bb = loop->single_exit->dest;
    edge inter_bb_true_edge;
    basic_block exit_bb;
  
    /* Find edge from intermediate bb to new loop header.  */
!   pe = find_edge (loop->single_exit->dest, new_loop_header);
    inter_bb_true_edge = find_edge (intermediate_bb, new_loop_exit->dest);
    exit_bb = new_loop_exit->dest;
    
*************** static void
*** 1735,1741 ****
  vect_transform_loop_bound (loop_vec_info loop_vinfo, tree niters)
  {
    struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
!   edge exit_edge = loop->exit_edges[0];
    block_stmt_iterator loop_exit_bsi = bsi_last (exit_edge->src);
    tree indx_before_incr, indx_after_incr;
    tree orig_cond_expr;
--- 1735,1741 ----
  vect_transform_loop_bound (loop_vec_info loop_vinfo, tree niters)
  {
    struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
!   edge exit_edge = loop->single_exit;
    block_stmt_iterator loop_exit_bsi = bsi_last (exit_edge->src);
    tree indx_before_incr, indx_after_incr;
    tree orig_cond_expr;
*************** vect_transform_loop (loop_vec_info loop_
*** 1844,1856 ****
  	LOOP_VINFO_LOOP (loop_vinfo)->pre_header->loop_father;
  
        /* Remember exit bb before duplication.  */
!       exit_bb = loop->exit_edges[0]->dest;
  
        /* Duplicate loop. 
  	 New (epilog) loop is concatenated to the exit of original loop.  */
        tree_duplicate_loop_to_exit (loop, loops);
  
!       new_loop_header = loop->exit_edges[0]->dest;
        
        /* Generate the following variables on the preheader of original loop:
  	 
--- 1844,1856 ----
  	LOOP_VINFO_LOOP (loop_vinfo)->pre_header->loop_father;
  
        /* Remember exit bb before duplication.  */
!       exit_bb = loop->single_exit->dest;
  
        /* Duplicate loop. 
  	 New (epilog) loop is concatenated to the exit of original loop.  */
        tree_duplicate_loop_to_exit (loop, loops);
  
!       new_loop_header = loop->single_exit->dest;
        
        /* Generate the following variables on the preheader of original loop:
  	 
*************** vect_transform_loop (loop_vec_info loop_
*** 1876,1885 ****
  	 
  	 if ( ni_name == ratio_mult_vf_name ) skip epilog loop.  */
        inter_bb = vect_gen_if_guard 
! 	(loop->exit_edges[0], cond, exit_bb, exit_ep);
        add_bb_to_loop (inter_bb, outer_loop);
  
!       loop->exit_edges[0] = inter_bb->pred;
  
        /* Build conditional expr before loop to be vectorized.  */
        vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
--- 1876,1885 ----
  	 
  	 if ( ni_name == ratio_mult_vf_name ) skip epilog loop.  */
        inter_bb = vect_gen_if_guard 
! 	(loop->single_exit, cond, exit_bb, exit_ep);
        add_bb_to_loop (inter_bb, outer_loop);
  
!       loop->single_exit = inter_bb->pred;
  
        /* Build conditional expr before loop to be vectorized.  */
        vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]