[lno] Cleanup the code duplication functions

Zdenek Dvorak rakdver@atrey.karlin.mff.cuni.cz
Wed Aug 4 19:14:00 GMT 2004


Hello,

this patch cleans up code duplication functions a bit.  It removes code
duplication (ehm... meaning the source code here) between functions from
tree-cfg.c and tree-ssa-loop-manip.c and splits out some useful utility
functions.

It also provides replacement functions for tree_duplicate_loop_to_exit.
The problem with tree_duplicate_loop_to_exit is that it does not
preserve semantics of the program and lacks documentation on what it
really does with ssa form; it therefore cannot be used without hacking
around and fixing up the things it messed up somehow, which does not
seem to be a good design decision.  However since using the replacement
functions in vectorizer would require some changes in it, I do not
understand the vectorizer enough to do the changes, and Olga has her own
rewrite and enhancement of that part with that I do not want to collide,
I have kept this functions alive.  I have just made it internal to the
vectorizer, so that noone will start using it by mistake.

Zdenek

Index: ChangeLog.lno
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/ChangeLog.lno,v
retrieving revision 1.1.2.246
diff -c -3 -p -r1.1.2.246 ChangeLog.lno
*** ChangeLog.lno	3 Aug 2004 22:46:01 -0000	1.1.2.246
--- ChangeLog.lno	4 Aug 2004 19:03:27 -0000
***************
*** 1,3 ****
--- 1,48 ----
+ 2004-08-04  Zdenek Dvorak  <rakdver@atrey.karlin.mff.cuni.cz>
+ 
+ 	* basic-block.h (get_dominated_by_region): Declare.
+ 	* cfgloop.h (update_single_exits_after_duplication): Declare.
+ 	(split_loop_bb): Declaration changed.
+ 	* cfgloopmanip.c (split_loop_bb): Take void * argument instead of
+ 	rtx one.
+ 	(update_single_exits_after_duplication): Export.
+ 	* dominance.c (get_dominated_by_region): New function.
+ 	* tree-cfg.c (add_phi_args_after_copy_bb): Split out from ...
+ 	(add_phi_args_after_copy): ... here.
+ 	(allocate_ssa_names): Export.  Allocate the ssa names map if
+ 	necessary.
+ 	(rewrite_to_new_ssa_names_bb): Split out from ...
+ 	(rewrite_to_new_ssa_names): ... here.
+ 	(tree_duplicate_sese_region): Changed due to allocate_ssa_names
+ 	change.  Use get_dominated_by_region.
+ 	* tree-flow.h (add_phi_args_after_copy_bb, add_phi_args_after_copy,
+ 	rewrite_to_new_ssa_names_bb, rewrite_to_new_ssa_names,
+ 	allocate_ssa_names, split_loop_exit_edge,
+ 	bsi_insert_on_edge_immediate_loop, tree_split_loop_iterations,
+ 	tree_align_loop_iterations): Declare.
+ 	(tree_duplicate_loop_to_exit): Declaration removed.
+ 	* tree-ssa-loop-ivopts.c (create_iv): Use
+ 	bsi_insert_on_edge_immediate_loop.
+ 	(split_loop_exit_edge): Moved to tree-ssa-loop-manip.c.
+ 	* tree-ssa-loop-manip.c (copy_phi_nodes): Renamed to
+ 	copy_phi_node_args.  Use add_phi_args_after_copy_bb.
+ 	(allocate_new_names, rename_use_op, rename_def_op,
+ 	rename_variables_in_bb, rename_variables, free_new_names,
+ 	tdlte_rename_variables_in_loop, tdlte_copy_phi_nodes,
+ 	tree_duplicate_loop_to_exit_cfg, tree_duplicate_loop_to_exit):
+ 	Moved to tree-vectorize.c.
+ 	(extend_exit_phi_nodes): Removed.
+ 	(tree_duplicate_loop_to_header_edge): Use the functions from
+ 	tree-cfg.c.
+ 	(tree_split_loop_iterations, tree_align_loop_iterations,
+ 	bsi_insert_on_edge_immediate_loop): New functions.
+ 	(split_loop_exit_edge): Moved from tree-ssa-loop-ivopts.c.
+ 	* tree-vectorizer.c ((allocate_new_names, rename_use_op,
+ 	rename_def_op, rename_variables_in_bb, rename_variables, free_new_names,
+ 	tdlte_rename_variables_in_loop, tdlte_copy_phi_nodes,
+ 	tree_duplicate_loop_to_exit_cfg, tree_duplicate_loop_to_exit):
+ 	Moved from tree-ssa-loop-manip.c.
+ 
  2004-08-04  Dorit Naishlos <dorit@il.ibm.com>
  
  	* tree-vectorizer.c (vect_create_index_for_array_ref): Remove
Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/basic-block.h,v
retrieving revision 1.153.2.39.2.12
diff -c -3 -p -r1.153.2.39.2.12 basic-block.h
*** basic-block.h	18 Jul 2004 23:12:12 -0000	1.153.2.39.2.12
--- basic-block.h	4 Aug 2004 19:03:27 -0000
*************** extern void set_immediate_dominator (enu
*** 714,719 ****
--- 714,721 ----
  extern basic_block get_immediate_dominator (enum cdi_direction, basic_block);
  extern bool dominated_by_p (enum cdi_direction, basic_block, basic_block);
  extern int get_dominated_by (enum cdi_direction, basic_block, basic_block **);
+ extern unsigned get_dominated_by_region (enum cdi_direction, basic_block *,
+ 					 unsigned, basic_block *);
  extern void add_to_dominance_info (enum cdi_direction, basic_block);
  extern void delete_from_dominance_info (enum cdi_direction, basic_block);
  basic_block recount_dominator (enum cdi_direction, basic_block);
Index: cfgloop.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgloop.h,v
retrieving revision 1.2.4.9.2.22
diff -c -3 -p -r1.2.4.9.2.22 cfgloop.h
*** cfgloop.h	22 Jul 2004 01:01:35 -0000	1.2.4.9.2.22
--- cfgloop.h	4 Aug 2004 19:03:27 -0000
*************** extern void flow_loop_free (struct loop 
*** 265,270 ****
--- 265,271 ----
  extern int flow_loop_nodes_find (basic_block, struct loop *);
  void fix_loop_structure (struct loops *);
  void mark_single_exit_loops (struct loops *);
+ void update_single_exits_after_duplication (basic_block *, unsigned, struct loop *);
  extern void create_loop_notes (void);
  extern void mark_irreducible_loops (struct loops *loops);
  
*************** extern int duplicate_loop_to_header_edge
*** 327,333 ****
  extern struct loop *loopify (struct loops *, edge, edge, basic_block, bool);
  extern void unloop (struct loops *, struct loop *);
  extern bool remove_path (struct loops *, edge);
! extern edge split_loop_bb (basic_block, rtx);
  
  /* Induction variable analysis.  */
  
--- 328,334 ----
  extern struct loop *loopify (struct loops *, edge, edge, basic_block, bool);
  extern void unloop (struct loops *, struct loop *);
  extern bool remove_path (struct loops *, edge);
! extern edge split_loop_bb (basic_block, void *);
  
  /* Induction variable analysis.  */
  
Index: cfgloopmanip.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgloopmanip.c,v
retrieving revision 1.3.2.11.2.13
diff -c -3 -p -r1.3.2.11.2.13 cfgloopmanip.c
*** cfgloopmanip.c	22 Jul 2004 01:01:35 -0000	1.3.2.11.2.13
--- cfgloopmanip.c	4 Aug 2004 19:03:27 -0000
*************** static void fix_irreducible_loops (basic
*** 53,59 ****
  /* Splits basic block BB after INSN, returns created edge.  Updates loops
     and dominators.  */
  edge
! split_loop_bb (basic_block bb, rtx insn)
  {
    edge e;
  
--- 53,59 ----
  /* Splits basic block BB after INSN, returns created edge.  Updates loops
     and dominators.  */
  edge
! split_loop_bb (basic_block bb, void *insn)
  {
    edge e;
  
*************** can_duplicate_loop_p (struct loop *loop)
*** 827,833 ****
  /* 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)
  {
--- 827,833 ----
  /* 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.  */
  
! void
  update_single_exits_after_duplication (basic_block *bbs, unsigned nbbs,
  				       struct loop *loop)
  {
Index: dominance.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/dominance.c,v
retrieving revision 1.10.2.11.2.7
diff -c -3 -p -r1.10.2.11.2.7 dominance.c
*** dominance.c	29 Jul 2004 08:51:28 -0000	1.10.2.11.2.7
--- dominance.c	4 Aug 2004 19:03:27 -0000
*************** get_dominated_by (enum cdi_direction dir
*** 746,751 ****
--- 746,777 ----
    return n;
  }
  
+ /* Find all basic blocks that are immediately dominated (in direction DIR)
+    by some block between N_REGION ones stored in REGION, except for blocks
+    in the REGION itself.  The found blocks are stored to DOMS and their number
+    is returned.  */
+ 
+ unsigned
+ get_dominated_by_region (enum cdi_direction dir, basic_block *region,
+ 			 unsigned n_region, basic_block *doms)
+ {
+   unsigned n_doms = 0, i;
+   basic_block dom;
+ 
+   for (i = 0; i < n_region; i++)
+     region[i]->rbi->duplicated = 1;
+   for (i = 0; i < n_region; i++)
+     for (dom = first_dom_son (dir, region[i]);
+ 	 dom;
+ 	 dom = next_dom_son (dir, dom))
+       if (!dom->rbi->duplicated)
+ 	doms[n_doms++] = dom;
+   for (i = 0; i < n_region; i++)
+     region[i]->rbi->duplicated = 0;
+ 
+   return n_doms;
+ }
+ 
  /* Redirect all edges pointing to BB to TO.  */
  void
  redirect_immediate_dominators (enum cdi_direction dir, basic_block bb,
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-cfg.c,v
retrieving revision 1.1.4.244.2.25
diff -c -3 -p -r1.1.4.244.2.25 tree-cfg.c
*** tree-cfg.c	2 Aug 2004 13:08:06 -0000	1.1.4.244.2.25
--- tree-cfg.c	4 Aug 2004 19:03:27 -0000
*************** tree_duplicate_bb (basic_block bb)
*** 4466,4517 ****
    return new_bb;
  }
  
! /* Blocks in REGION_COPY array of length N_REGION were created by
!    duplication of basic blocks.  Add phi node arguments for edges
!    going from these blocks.  */
  
! static void
! add_phi_args_after_copy (basic_block *region_copy, unsigned n_region)
  {
!   basic_block bb, bb_copy;
    edge e, e_copy;
    tree phi, phi_copy, phi_next, def;
!   unsigned i;
  
!   for (i = 0; i < n_region; i++)
!     region_copy[i]->rbi->duplicated = 1;
! 
!   for (i = 0; i < n_region; i++)
      {
!       bb_copy = region_copy[i];
!       bb = bb_copy->rbi->original;
  
!       for (e_copy = bb_copy->succ; e_copy; e_copy = e_copy->succ_next)
! 	{
! 	  if (!phi_nodes (e_copy->dest))
! 	    continue;
  
! 	  if (e_copy->dest->rbi->duplicated)
! 	    e = find_edge (bb, e_copy->dest->rbi->original);
! 	  else
! 	    e = find_edge (bb, e_copy->dest);
  
  	  if (!e)
  	    abort ();
  
! 	  for (phi = phi_nodes (e->dest), phi_copy = phi_nodes (e_copy->dest);
! 	       phi;
! 	       phi = phi_next, phi_copy = TREE_CHAIN (phi_copy))
! 	    {
! 	      phi_next = TREE_CHAIN (phi);
  
! 	      if (PHI_RESULT (phi) != PHI_RESULT (phi_copy))
! 		abort ();
! 	      def = PHI_ARG_DEF_FROM_EDGE (phi, e);
! 	      add_phi_arg (&phi_copy, def, e_copy);
! 	    }
  	}
      }
  
    for (i = 0; i < n_region; i++)
      region_copy[i]->rbi->duplicated = 0;
--- 4466,4537 ----
    return new_bb;
  }
  
! /* Basic block BB_COPY was created by code duplication.  Add phi node
!    arguments for edges going out of BB_COPY.  The blocks that were
!    duplicated have rbi->duplicated set to one.  */
  
! void
! add_phi_args_after_copy_bb (basic_block bb_copy)
  {
!   basic_block bb, dest;
    edge e, e_copy;
    tree phi, phi_copy, phi_next, def;
!       
!   bb = bb_copy->rbi->original;
  
!   for (e_copy = bb_copy->succ; e_copy; e_copy = e_copy->succ_next)
      {
!       if (!phi_nodes (e_copy->dest))
! 	continue;
  
!       if (e_copy->dest->rbi->duplicated)
! 	dest = e_copy->dest->rbi->original;
!       else
! 	dest = e_copy->dest;
  
!       e = find_edge (bb, dest);
!       if (!e)
! 	{
! 	  /* During loop unrolling the target of the latch edge is copied.
! 	     In this case we are not looking for edge to dest, but to
! 	     duplicated block whose original was dest.  */
! 	  for (e = bb->succ; e; e = e->succ_next)
! 	    if (e->dest->rbi->duplicated
! 		&& e->dest->rbi->original == dest)
! 	      break;
  
  	  if (!e)
  	    abort ();
+ 	}
  
!       for (phi = phi_nodes (e->dest), phi_copy = phi_nodes (e_copy->dest);
! 	   phi;
! 	   phi = phi_next, phi_copy = TREE_CHAIN (phi_copy))
! 	{
! 	  phi_next = TREE_CHAIN (phi);
  
! 	  if (PHI_RESULT (phi) != PHI_RESULT (phi_copy))
! 	    abort ();
! 	  def = PHI_ARG_DEF_FROM_EDGE (phi, e);
! 	  add_phi_arg (&phi_copy, def, e_copy);
  	}
      }
+ }
+ 
+ /* Blocks in REGION_COPY array of length N_REGION were created by
+    duplication of basic blocks.  Add phi node arguments for edges
+    going from these blocks.  */
+ 
+ void
+ add_phi_args_after_copy (basic_block *region_copy, unsigned n_region)
+ {
+   unsigned i;
+ 
+   for (i = 0; i < n_region; i++)
+     region_copy[i]->rbi->duplicated = 1;
+ 
+   for (i = 0; i < n_region; i++)
+     add_phi_args_after_copy_bb (region_copy[i]);
  
    for (i = 0; i < n_region; i++)
      region_copy[i]->rbi->duplicated = 0;
*************** ssa_name_map_entry_eq (const void *in_ta
*** 4547,4564 ****
  /* Allocate duplicates of ssa names in list DEFINITIONS and store the mapping
     to MAP.  */
  
! static void
! allocate_ssa_names (bitmap definitions, htab_t map)
  {
    tree name;
    struct ssa_name_map_entry *entry;
    PTR *slot;
    unsigned ver;
  
    EXECUTE_IF_SET_IN_BITMAP (definitions, 0, ver,
      {
        name = ssa_name (ver);
!       slot = htab_find_slot_with_hash (map, name, SSA_NAME_VERSION (name),
  				       INSERT);
        if (*slot)
  	entry = *slot;
--- 4567,4587 ----
  /* Allocate duplicates of ssa names in list DEFINITIONS and store the mapping
     to MAP.  */
  
! void
! allocate_ssa_names (bitmap definitions, htab_t *map)
  {
    tree name;
    struct ssa_name_map_entry *entry;
    PTR *slot;
    unsigned ver;
  
+   if (!*map)
+     *map = htab_create (10, ssa_name_map_entry_hash,
+ 			ssa_name_map_entry_eq, free);
    EXECUTE_IF_SET_IN_BITMAP (definitions, 0, ver,
      {
        name = ssa_name (ver);
!       slot = htab_find_slot_with_hash (*map, name, SSA_NAME_VERSION (name),
  				       INSERT);
        if (*slot)
  	entry = *slot;
*************** rewrite_to_new_ssa_names_use (use_operan
*** 4610,4623 ****
    SET_USE (use, entry->to_name);
  }
  
! /* Rewrite the ssa names in N_REGION blocks REGION to the new ones as specified
!    by the mapping MAP.  */
  
! static void
! rewrite_to_new_ssa_names (basic_block *region, unsigned n_region, htab_t map)
  {
!   basic_block bb;
!   unsigned i, r;
    edge e;
    tree phi, stmt;
    block_stmt_iterator bsi;
--- 4633,4645 ----
    SET_USE (use, entry->to_name);
  }
  
! /* Rewrite the ssa names in basic block BB to new ones as specified by the
!    mapping MAP.  */
  
! void
! rewrite_to_new_ssa_names_bb (basic_block bb, htab_t map)
  {
!   unsigned i;
    edge e;
    tree phi, stmt;
    block_stmt_iterator bsi;
*************** rewrite_to_new_ssa_names (basic_block *r
*** 4628,4694 ****
    v_must_def_optype v_must_defs;
    stmt_ann_t ann;
  
!   for (r = 0; r < n_region; r++)
!     {
!       bb = region[r];
  
!       for (e = bb->pred; e; e = e->pred_next)
! 	if (e->flags & EDGE_ABNORMAL)
! 	  break;
  
!       for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
! 	{
! 	  rewrite_to_new_ssa_names_def (PHI_RESULT_PTR (phi), phi, map);
! 	  if (e)
! 	    SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)) = 1;
! 	}
  
!       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
! 	{
! 	  stmt = bsi_stmt (bsi);
! 	  get_stmt_operands (stmt);
! 	  ann = stmt_ann (stmt);
  
! 	  uses = USE_OPS (ann);
! 	  for (i = 0; i < NUM_USES (uses); i++)
! 	    rewrite_to_new_ssa_names_use (USE_OP_PTR (uses, i), map);
  
! 	  defs = DEF_OPS (ann);
! 	  for (i = 0; i < NUM_DEFS (defs); i++)
! 	    rewrite_to_new_ssa_names_def (DEF_OP_PTR (defs, i), stmt, map);
  
! 	  vuses = VUSE_OPS (ann);
! 	  for (i = 0; i < NUM_VUSES (vuses); i++)
! 	    rewrite_to_new_ssa_names_use (VUSE_OP_PTR (vuses, i), map);
  
! 	  v_may_defs = V_MAY_DEF_OPS (ann);
! 	  for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
! 	    {
! 	      rewrite_to_new_ssa_names_use
! 		      (V_MAY_DEF_OP_PTR (v_may_defs, i), map);
! 	      rewrite_to_new_ssa_names_def
! 		      (V_MAY_DEF_RESULT_PTR (v_may_defs, i), stmt, map);
! 	    }
  
! 	  v_must_defs = V_MUST_DEF_OPS (ann);
! 	  for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++)
! 	    rewrite_to_new_ssa_names_def
! 		    (V_MUST_DEF_OP_PTR (v_must_defs, i), stmt, map);
! 	}
  
!       for (e = bb->succ; e; e = e->succ_next)
! 	for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi))
  	  {
! 	    rewrite_to_new_ssa_names_use
! 		    (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), map);
! 
! 	    if (e->flags & EDGE_ABNORMAL)
! 	      {
! 		tree op = PHI_ARG_DEF_FROM_EDGE (phi, e);
! 		SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op) = 1;
! 	      }
  	  }
!     }
  }
  
  /* Duplicates a REGION (set of N_REGION basic blocks) with just a single
--- 4650,4723 ----
    v_must_def_optype v_must_defs;
    stmt_ann_t ann;
  
!   for (e = bb->pred; e; e = e->pred_next)
!     if (e->flags & EDGE_ABNORMAL)
!       break;
  
!   for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
!     {
!       rewrite_to_new_ssa_names_def (PHI_RESULT_PTR (phi), phi, map);
!       if (e)
! 	SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)) = 1;
!     }
  
!   for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
!     {
!       stmt = bsi_stmt (bsi);
!       get_stmt_operands (stmt);
!       ann = stmt_ann (stmt);
  
!       uses = USE_OPS (ann);
!       for (i = 0; i < NUM_USES (uses); i++)
! 	rewrite_to_new_ssa_names_use (USE_OP_PTR (uses, i), map);
  
!       defs = DEF_OPS (ann);
!       for (i = 0; i < NUM_DEFS (defs); i++)
! 	rewrite_to_new_ssa_names_def (DEF_OP_PTR (defs, i), stmt, map);
  
!       vuses = VUSE_OPS (ann);
!       for (i = 0; i < NUM_VUSES (vuses); i++)
! 	rewrite_to_new_ssa_names_use (VUSE_OP_PTR (vuses, i), map);
  
!       v_may_defs = V_MAY_DEF_OPS (ann);
!       for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
! 	{
! 	  rewrite_to_new_ssa_names_use
! 		  (V_MAY_DEF_OP_PTR (v_may_defs, i), map);
! 	  rewrite_to_new_ssa_names_def
! 		  (V_MAY_DEF_RESULT_PTR (v_may_defs, i), stmt, map);
! 	}
  
!       v_must_defs = V_MUST_DEF_OPS (ann);
!       for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++)
! 	rewrite_to_new_ssa_names_def
! 		(V_MUST_DEF_OP_PTR (v_must_defs, i), stmt, map);
!     }
  
!   for (e = bb->succ; e; e = e->succ_next)
!     for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi))
!       {
! 	rewrite_to_new_ssa_names_use
! 		(PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), map);
  
! 	if (e->flags & EDGE_ABNORMAL)
  	  {
! 	    tree op = PHI_ARG_DEF_FROM_EDGE (phi, e);
! 	    SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op) = 1;
  	  }
!       }
! }
! 
! /* Rewrite the ssa names in N_REGION blocks REGION to the new ones as specified
!    by the mapping MAP.  */
! 
! void
! rewrite_to_new_ssa_names (basic_block *region, unsigned n_region, htab_t map)
! {
!   unsigned r;
! 
!   for (r = 0; r < n_region; r++)
!     rewrite_to_new_ssa_names_bb (region[r], map);
  }
  
  /* Duplicates a REGION (set of N_REGION basic blocks) with just a single
*************** tree_duplicate_sese_region (edge entry, 
*** 4712,4719 ****
    edge exit_copy;
    bitmap definitions;
    tree phi, var;
!   basic_block *doms, dom;
!   htab_t ssa_name_map;
  
    if (!can_copy_bbs_p (region, n_region))
      return false;
--- 4741,4748 ----
    edge exit_copy;
    bitmap definitions;
    tree phi, var;
!   basic_block *doms;
!   htab_t ssa_name_map = NULL;
  
    if (!can_copy_bbs_p (region, n_region))
      return false;
*************** tree_duplicate_sese_region (edge entry, 
*** 4765,4781 ****
    /* Record blocks outside the region that are duplicated by something
       inside.  */
    doms = xmalloc (sizeof (basic_block) * n_basic_blocks);
!   n_doms = 0;
!   for (i = 0; i < n_region; i++)
!     region[i]->rbi->duplicated = 1;
!   for (i = 0; i < n_region; i++)
!     for (dom = first_dom_son (CDI_DOMINATORS, region[i]);
! 	 dom;
! 	 dom = next_dom_son (CDI_DOMINATORS, dom))
!       if (!dom->rbi->duplicated)
! 	doms[n_doms++] = dom;
!   for (i = 0; i < n_region; i++)
!     region[i]->rbi->duplicated = 0;
  
    copy_bbs (region, n_region, region_copy, &exit, 1, &exit_copy, loop);
    definitions = marked_ssa_names ();
--- 4794,4800 ----
    /* Record blocks outside the region that are duplicated by something
       inside.  */
    doms = xmalloc (sizeof (basic_block) * n_basic_blocks);
!   n_doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region, doms);
  
    copy_bbs (region, n_region, region_copy, &exit, 1, &exit_copy, loop);
    definitions = marked_ssa_names ();
*************** tree_duplicate_sese_region (edge entry, 
*** 4824,4834 ****
       have immediate uses, it might be better to leave definitions in region
       unchanged, create new ssa names for phi nodes on exit, and rewrite
       the uses, to avoid changing the copied region.  */
!   ssa_name_map = htab_create (10, ssa_name_map_entry_hash,
! 			      ssa_name_map_entry_eq, free);
!   allocate_ssa_names (definitions, ssa_name_map);
    rewrite_to_new_ssa_names (region, n_region, ssa_name_map);
!   allocate_ssa_names (definitions, ssa_name_map);
    rewrite_to_new_ssa_names (region_copy, n_region, ssa_name_map);
    htab_delete (ssa_name_map);
  
--- 4843,4851 ----
       have immediate uses, it might be better to leave definitions in region
       unchanged, create new ssa names for phi nodes on exit, and rewrite
       the uses, to avoid changing the copied region.  */
!   allocate_ssa_names (definitions, &ssa_name_map);
    rewrite_to_new_ssa_names (region, n_region, ssa_name_map);
!   allocate_ssa_names (definitions, &ssa_name_map);
    rewrite_to_new_ssa_names (region_copy, n_region, ssa_name_map);
    htab_delete (ssa_name_map);
  
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-flow.h,v
retrieving revision 1.1.4.177.2.44
diff -c -3 -p -r1.1.4.177.2.44 tree-flow.h
*** tree-flow.h	2 Aug 2004 13:08:07 -0000	1.1.4.177.2.44
--- tree-flow.h	4 Aug 2004 19:03:27 -0000
*************** extern tree tree_block_label (basic_bloc
*** 507,512 ****
--- 507,517 ----
  extern void extract_true_false_edges_from_block (basic_block, edge *, edge *);
  extern bool tree_duplicate_sese_region (edge, edge, basic_block *, unsigned,
  					basic_block *);
+ extern void add_phi_args_after_copy_bb (basic_block);
+ extern void add_phi_args_after_copy (basic_block *, unsigned);
+ extern void rewrite_to_new_ssa_names_bb (basic_block, struct htab *);
+ extern void rewrite_to_new_ssa_names (basic_block *, unsigned, htab_t);
+ extern void allocate_ssa_names (bitmap, struct htab **);
  extern bool tree_purge_dead_eh_edges (basic_block);
  extern bool tree_purge_all_dead_eh_edges (bitmap);
  
*************** tree can_count_iv_in_wider_type (struct 
*** 663,668 ****
--- 668,675 ----
  void free_numbers_of_iterations_estimates (struct loops *);
  void loop_commit_inserts (void);
  bool for_each_index (tree *, bool (*) (tree, tree *, void *), void *);
+ void split_loop_exit_edge (edge);
+ basic_block bsi_insert_on_edge_immediate_loop (edge, tree);
  
  /* In tree-ssa-dce.c.  */
  void tree_ssa_dce_no_cfg_changes (void);
*************** bool tree_duplicate_loop_to_header_edge 
*** 678,685 ****
  					 unsigned int, sbitmap,
  					 edge, edge *,
  					 unsigned int *, int);
  void tree_unroll_loops_completely (struct loops *);
- bool tree_duplicate_loop_to_exit (struct loop *loop, struct loops *loops);
  void create_iv (tree, tree, tree, struct loop *, block_stmt_iterator *, bool,
  		tree *, tree *);
  void standard_iv_increment_position (struct loop *, block_stmt_iterator *,
--- 685,694 ----
  					 unsigned int, sbitmap,
  					 edge, edge *,
  					 unsigned int *, int);
+ struct loop *tree_split_loop_iterations (struct loop *, edge, tree, struct loops *);
+ struct loop *tree_align_loop_iterations (struct loop *, edge, tree, unsigned,
+ 					 struct loops *);
  void tree_unroll_loops_completely (struct loops *);
  void create_iv (tree, tree, tree, struct loop *, block_stmt_iterator *, bool,
  		tree *, tree *);
  void standard_iv_increment_position (struct loop *, block_stmt_iterator *,
Index: tree-ssa-loop-ivopts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-loop-ivopts.c,v
retrieving revision 1.1.2.48
diff -c -3 -p -r1.1.2.48 tree-ssa-loop-ivopts.c
*** tree-ssa-loop-ivopts.c	23 Jul 2004 14:03:24 -0000	1.1.2.48
--- tree-ssa-loop-ivopts.c	4 Aug 2004 19:03:28 -0000
*************** create_iv (tree base, tree step, tree va
*** 4066,4077 ****
    initial = force_gimple_operand (base, &stmts, false, var);
    if (stmts)
      {
-       basic_block new_bb;
        edge pe = loop_preheader_edge (loop);
!       
!       new_bb = bsi_insert_on_edge_immediate (pe, stmts);
!       if (new_bb)
! 	add_bb_to_loop (new_bb, new_bb->pred->src->loop_father);
      }
  
    stmt = create_phi_node (vb, loop->header);
--- 4066,4074 ----
    initial = force_gimple_operand (base, &stmts, false, var);
    if (stmts)
      {
        edge pe = loop_preheader_edge (loop);
! 
!       bsi_insert_on_edge_immediate_loop (pe, stmts);
      }
  
    stmt = create_phi_node (vb, loop->header);
*************** rewrite_use_compare (struct ivopts_data 
*** 4361,4389 ****
    *op_p = op;
  }
  
- /* Split loop exit edge EXIT.  The things are a bit complicated by a need to
-    preserve the loop closed ssa form.  */
- 
- static void
- split_loop_exit_edge (edge exit)
- {
-   basic_block dest = exit->dest;
-   basic_block bb = loop_split_edge_with (exit, NULL);
-   tree phi, new_phi, new_name;
-   use_operand_p op_p;
- 
-   for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi))
-     {
-       op_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, bb->succ);
- 
-       new_name = duplicate_ssa_name (USE_FROM_PTR (op_p), NULL);
-       new_phi = create_phi_node (new_name, bb);
-       SSA_NAME_DEF_STMT (new_name) = new_phi;
-       add_phi_arg (&new_phi, USE_FROM_PTR (op_p), exit);
-       SET_USE (op_p, new_name);
-     }
- }
- 
  /* Ensure that operand *OP_P may be used at the end of EXIT without
     violating loop closed ssa form.  */
  
--- 4358,4363 ----
Index: tree-ssa-loop-manip.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-loop-manip.c,v
retrieving revision 1.1.2.28
diff -c -3 -p -r1.1.2.28 tree-ssa-loop-manip.c
*** tree-ssa-loop-manip.c	2 Aug 2004 13:08:07 -0000	1.1.2.28
--- tree-ssa-loop-manip.c	4 Aug 2004 19:03:28 -0000
*************** static void lv_update_pending_stmts (edg
*** 43,288 ****
  static void lv_adjust_loop_header_phi (basic_block, basic_block, basic_block, 
  				       edge);
  
! /* Copies phi nodes in newly created copies of the LOOP.  The new blocks start
!    since FIRST_NEW_BLOCK index.  PEELING is true if we were peeling
!    the loop.  */
  
  static void
! copy_phi_nodes (struct loop *loop, unsigned first_new_block, bool peeling)
  {
    unsigned i;
-   basic_block bb, orig;
-   tree phi, new_phi, def;
-   edge e, new_e;
-   edge latch = loop_latch_edge (loop), entry = loop_preheader_edge (loop);
  
    for (i = first_new_block; i < (unsigned) last_basic_block; i++)
!     {
!       bb = BASIC_BLOCK (i);
!       orig = bb->rbi->original;
! 
!       for (phi = phi_nodes (orig), new_phi = phi_nodes (bb);
! 	   phi;
! 	   phi = TREE_CHAIN (phi), new_phi = TREE_CHAIN (new_phi))
! 	{
! 	  if (orig == loop->header)
! 	    {
! 	      if (!bb->pred || bb->pred->pred_next)
! 		abort ();
! 
! 	      new_e = bb->pred;
! 	      e = (peeling && bb->rbi->copy_number == 1 ? entry : latch);
! 	      def = PHI_ARG_DEF_FROM_EDGE (phi, e);
! 	      add_phi_arg (&new_phi, def, new_e);
! 	      continue;
! 	    }
! 
! 	  for (new_e = bb->pred; new_e; new_e = new_e->pred_next)
! 	    {
! 	      e = find_edge (new_e->src->rbi->original, orig);
! 	      if (!e)
! 		abort ();
! 
! 	      def = PHI_ARG_DEF_FROM_EDGE (phi, e);
! 	      add_phi_arg (&new_phi, def, new_e);
! 	    }
! 	}
!     }
! 
!   if (peeling)
!     {
!       /* Update the phi nodes in the header so that the latch value comes from
! 	 both edges.  */
!       for (phi = phi_nodes (loop->header); phi; phi = TREE_CHAIN (phi))
! 	{
! 	  int i;
! 	  def = PHI_ARG_DEF_FROM_EDGE (phi, latch);
! 	  i = phi_arg_from_edge (phi, entry);
! 	  SET_PHI_ARG_DEF (phi, i, def);
! 	}
!     }
! }
! 
! /* For each definition in DEFINITIONS allocates:
! 
!    NDUPL + 1 copies if ORIGIN is true
!    NDUPL copies if ORIGIN is false
! 
!    (one for each duplicate of the loop body).  
!    If ORIGIN is true, additional set of DEFINITIONS 
!    is allocated for initial loop copy. */
! 
! static void
! allocate_new_names (bitmap definitions, unsigned ndupl, bool origin)
! {
!   tree def;
!   unsigned i, ver;
!   tree *new_names;
!   bool abnormal;
! 
!   EXECUTE_IF_SET_IN_BITMAP (definitions, 0, ver,
!     {
!       def = ssa_name (ver);
!       new_names = xmalloc (sizeof (tree) * (ndupl + (origin ? 1 : 0)));
! 
!       abnormal = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def);
!       for (i = (origin ? 0 : 1); i <= ndupl; i++)
! 	{
! 	  new_names[i] = duplicate_ssa_name (def, SSA_NAME_DEF_STMT (def));
! 	  SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_names[i]) = abnormal;
! 	}
!      /* Delay this until now so it doesn't get propagated to the copies.
! 	That would cause problems in the next outer loop.  */
!       SSA_NAME_AUX (def) = new_names;
!     });
! }
! 
! /* Renames the variable *OP_P in statement STMT.  If DEF is true,
!    *OP_P is defined by the statement.  N_COPY is the number of the
!    copy of the loop body we are renaming.  */
! 
! static void
! rename_use_op (use_operand_p op_p, unsigned n_copy)
! {
!   tree *new_names;
! 
!   if (TREE_CODE (USE_FROM_PTR (op_p)) != SSA_NAME)
!     return;
! 
!   new_names = SSA_NAME_AUX (USE_FROM_PTR (op_p));
! 
!   /* Something defined outside of the loop.  */
!   if (!new_names)
!     return;
! 
!   /* An ordinary ssa name defined in the loop.  */
! 
!   SET_USE (op_p, new_names[n_copy]);
! }
! 
! /* Renames the variable *OP_P in statement STMT.  If DEF is true,
!    *OP_P is defined by the statement.  N_COPY is the number of the
!    copy of the loop body we are renaming.  */
! 
! static void
! rename_def_op (def_operand_p op_p, tree stmt, unsigned n_copy)
! {
!   tree *new_names;
! 
!   if (TREE_CODE (DEF_FROM_PTR (op_p)) != SSA_NAME)
!     return;
! 
!   new_names = SSA_NAME_AUX (DEF_FROM_PTR (op_p));
  
!   /* Something defined outside of the loop.  */
!   if (!new_names)
!     return;
! 
!   /* An ordinary ssa name defined in the loop.  */
! 
!   SET_DEF (op_p, new_names[n_copy]);
!   SSA_NAME_DEF_STMT (DEF_FROM_PTR (op_p)) = stmt;
! }
! 
! /* Renames the variables in basic block BB.  */
! 
! static void
! rename_variables_in_bb (basic_block bb)
! {
!   tree phi;
!   block_stmt_iterator bsi;
!   tree stmt;
!   stmt_ann_t ann;
!   use_optype uses;
!   vuse_optype vuses;
!   def_optype defs;
!   v_may_def_optype v_may_defs;
!   v_must_def_optype v_must_defs;
!   unsigned i, nbb = bb->rbi->copy_number;
!   edge e;
! 
!   for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
!     rename_def_op (PHI_RESULT_PTR (phi), phi, nbb);
! 
!   for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
!     {
!       stmt = bsi_stmt (bsi);
!       get_stmt_operands (stmt);
!       ann = stmt_ann (stmt);
! 
!       uses = USE_OPS (ann);
!       for (i = 0; i < NUM_USES (uses); i++)
! 	rename_use_op (USE_OP_PTR (uses, i), nbb);
! 
!       defs = DEF_OPS (ann);
!       for (i = 0; i < NUM_DEFS (defs); i++)
! 	rename_def_op (DEF_OP_PTR (defs, i), stmt, nbb);
! 
!       vuses = VUSE_OPS (ann);
!       for (i = 0; i < NUM_VUSES (vuses); i++)
! 	rename_use_op (VUSE_OP_PTR (vuses, i), nbb);
! 
!       v_may_defs = V_MAY_DEF_OPS (ann);
!       for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
! 	{
! 	  rename_use_op (V_MAY_DEF_OP_PTR (v_may_defs, i), nbb);
! 	  rename_def_op (V_MAY_DEF_RESULT_PTR (v_may_defs, i), stmt, nbb);
! 	}
! 
!       v_must_defs = V_MUST_DEF_OPS (ann);
!       for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++)
! 	rename_def_op (V_MUST_DEF_OP_PTR (v_must_defs, i), stmt, nbb);
! 
!     }
  
!   for (e = bb->succ; e; e = e->succ_next)
!     for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi))
!       rename_use_op (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), nbb);
  }
  
  /* Renames variables in the area copied by tree_duplicate_loop_to_header_edge.
!    FIRST_NEW_BLOCK is the first block in the copied area.   */
  
  static void
! rename_variables (unsigned first_new_block)
  {
!   unsigned i;
    basic_block bb;
  
    for (i = first_new_block; i < (unsigned) last_basic_block; i++)
      {
        bb = BASIC_BLOCK (i);
  
!       rename_variables_in_bb (bb);
! 
!       if (bb->rbi->copy_number == 1)
! 	rename_variables_in_bb (bb->rbi->original);
!     }
! }
! 
! /* Releases the structures holding the new ssa names. 
!    The original ssa names are released if ORIGIN is true.
!    Otherwise they are saved for initial loop copy.  */
! 
! static void
! free_new_names (bitmap definitions, bool origin)
! {
!   tree def;
!   unsigned ver;
! 
!   EXECUTE_IF_SET_IN_BITMAP (definitions, 0, ver,
!     {
!       def = ssa_name (ver);
! 
!       if (SSA_NAME_AUX (def))
  	{
! 	  free (SSA_NAME_AUX (def));
! 	  SSA_NAME_AUX (def) = NULL;
  	}
  
!       if (origin)
! 	release_ssa_name_force (def);
!     });
  }
  
  /* Sets SSA_NAME_DEF_STMT for results of all phi nodes in BB.  */
--- 43,93 ----
  static void lv_adjust_loop_header_phi (basic_block, basic_block, basic_block, 
  				       edge);
  
! /* Copies phi node arguments for duplicated blocks.  The index of the first
!    duplicated block is FIRST_NEW_BLOCK.  */
  
  static void
! copy_phi_node_args (unsigned first_new_block)
  {
    unsigned i;
  
    for (i = first_new_block; i < (unsigned) last_basic_block; i++)
!     BASIC_BLOCK (i)->rbi->duplicated = 1;
  
!   for (i = first_new_block; i < (unsigned) last_basic_block; i++)
!     add_phi_args_after_copy_bb (BASIC_BLOCK (i));
  
!   for (i = first_new_block; i < (unsigned) last_basic_block; i++)
!     BASIC_BLOCK (i)->rbi->duplicated = 0;
  }
  
  /* Renames variables in the area copied by tree_duplicate_loop_to_header_edge.
!    FIRST_NEW_BLOCK is the first block in the copied area.   DEFINITIONS is
!    a bitmap of all ssa names defined inside the loop.  */
  
  static void
! rename_variables (unsigned first_new_block, bitmap definitions)
  {
!   unsigned i, copy_number = 0;
    basic_block bb;
+   htab_t ssa_name_map = NULL;
  
    for (i = first_new_block; i < (unsigned) last_basic_block; i++)
      {
        bb = BASIC_BLOCK (i);
  
!       /* We assume that first come all blocks from the first copy, then all
! 	 blocks from the second copy, etc.  */
!       if (copy_number != (unsigned) bb->rbi->copy_number)
  	{
! 	  allocate_ssa_names (definitions, &ssa_name_map);
! 	  copy_number = bb->rbi->copy_number;
  	}
  
!       rewrite_to_new_ssa_names_bb (bb, ssa_name_map);
!     }
! 
!   htab_delete (ssa_name_map);
  }
  
  /* Sets SSA_NAME_DEF_STMT for results of all phi nodes in BB.  */
*************** set_phi_def_stmts (basic_block bb)
*** 296,327 ****
      SSA_NAME_DEF_STMT (PHI_RESULT (phi)) = phi;
  }
  
- /* Extends phi nodes on EXIT to the newly created edges.  */
- 
- static void
- extend_exit_phi_nodes (unsigned first_new_block, edge exit)
- {
-   basic_block exit_block = exit->dest;
-   edge ae;
-   tree phi, def;
- 
-   for (phi = phi_nodes (exit_block); phi; phi = TREE_CHAIN (phi))
-     {
-       def = PHI_ARG_DEF_FROM_EDGE (phi, exit);
- 
-       for (ae = exit_block->pred; ae; ae = ae->pred_next)
- 	{
- 	  if (ae->src->index < (int) first_new_block)
- 	    continue;
- 
- 	  if (ae->src->rbi->original != exit->src)
- 	    continue;
- 
- 	  add_phi_arg (&phi, def, ae);
- 	}
-     }
- }
- 
  /* The same ad cfgloopmanip.c:duplicate_loop_to_header_edge, but also updates
     ssa.  In order to achieve this, only loops whose exits all lead to the same
     location are handled.
--- 101,106 ----
*************** tree_duplicate_loop_to_header_edge (stru
*** 340,351 ****
    unsigned first_new_block;
    basic_block bb;
    unsigned i;
-   bool peeling = (e != loop_latch_edge (loop));
-   edge latch, latch_copy;
    tree phi, arg, map, def;
    bitmap definitions;
-   edge *exits;
-   unsigned n_exits;
  
    if (!(loops->state & LOOPS_HAVE_SIMPLE_LATCHES))
      return false;
--- 119,126 ----
*************** tree_duplicate_loop_to_header_edge (stru
*** 356,363 ****
    verify_loop_closed_ssa ();
  #endif
  
-   exits = get_loop_exit_edges (loop, &n_exits);
- 
    if (any_marked_for_rewrite_p ())
      abort ();
  
--- 131,136 ----
*************** tree_duplicate_loop_to_header_edge (stru
*** 366,403 ****
  				      orig, to_remove, n_to_remove, flags))
      return false;
  
-   definitions = marked_ssa_names ();
-   allocate_new_names (definitions, ndupl, true);
- 
    /* Readd the removed phi args for e.  */
-   latch = loop_latch_edge (loop);
-   latch_copy = peeling ? loop_preheader_edge (loop) : latch;
    map = PENDING_STMT (e);
    PENDING_STMT (e) = NULL;
  
!   for (phi = phi_nodes (loop->header), arg = map;
         phi;
         phi = TREE_CHAIN (phi), arg = TREE_CHAIN (arg))
      {
        def = TREE_VALUE (arg);
!       add_phi_arg (&phi, def, latch_copy);
      }
    if (arg)
      abort ();
  
!   /* Extend exit phi nodes.  */
!   for (i = 0; i < n_exits; i++)
!     extend_exit_phi_nodes (first_new_block, exits[i]);
!   free (exits);
! 
!   /* Copy the phi nodes.  */
!   copy_phi_nodes (loop, first_new_block, peeling);
  
    /* Rename the variables.  */
!   rename_variables (first_new_block);
!   free_new_names (definitions, true);
!   BITMAP_XFREE (definitions);
    unmark_all_for_rewrite ();
  
    /* For some time we have the identical ssa names as results in multiple phi
       nodes.  When phi node is resized, it sets SSA_NAME_DEF_STMT of its result
--- 139,166 ----
  				      orig, to_remove, n_to_remove, flags))
      return false;
  
    /* Readd the removed phi args for e.  */
    map = PENDING_STMT (e);
    PENDING_STMT (e) = NULL;
  
!   for (phi = phi_nodes (e->dest), arg = map;
         phi;
         phi = TREE_CHAIN (phi), arg = TREE_CHAIN (arg))
      {
        def = TREE_VALUE (arg);
!       add_phi_arg (&phi, def, e);
      }
    if (arg)
      abort ();
  
!   /* Copy the phi node arguments.  */
!   copy_phi_node_args (first_new_block);
  
    /* Rename the variables.  */
!   definitions = marked_ssa_names ();
!   rename_variables (first_new_block, definitions);
    unmark_all_for_rewrite ();
+   BITMAP_XFREE (definitions);
  
    /* For some time we have the identical ssa names as results in multiple phi
       nodes.  When phi node is resized, it sets SSA_NAME_DEF_STMT of its result
*************** verify_loop_closed_ssa (void)
*** 952,1179 ****
      }
  }
  
- /* Renames variables in new generated LOOP.  */
- 
- static void
- tdlte_rename_variables_in_loop (struct loop *loop)
- {
-   unsigned i;
-   basic_block *bbs;
- 
-   bbs = get_loop_body (loop);
- 
-   for (i = 0; i < loop->num_nodes; i++)
-     {
-       rename_variables_in_bb (bbs[i]);
-     }
- 
-   free (bbs);
- }
  
! /* This function copies phis from loop to new_loop 
!    as they were not generated by duplication of bbs.  */
  
! static void
! tdlte_copy_phi_nodes (struct loop *loop, struct loop *new_loop)
  {
!   tree phi, new_phi, def;
!   edge new_e;
!   edge latch = loop_latch_edge (loop);
! 
!      
!   for (phi = phi_nodes (loop->header), 
! 	 new_phi = phi_nodes (new_loop->header); 
!        phi; 
!        phi = TREE_CHAIN (phi), 
! 	 new_phi = TREE_CHAIN (new_phi))
!     {
!       new_e = new_loop->header->pred;
!       def = PHI_ARG_DEF_FROM_EDGE (phi, latch);
!       add_phi_arg (&new_phi, def, new_e);
!     }
! 
! }
! 
! /* This function: 
!    - copies basic blocks of the loop LOOP;
!    - locate them at the only exit of LOOP; 
!    - redirect edges so that two loops are produced: 
!              initial LOOP and newly generated;
!    - update dominators;
!    - returns pointer to new loop in NEW_LOOP_P.
! 
!    FORNOW: only innermost loops with 
!            1 exit are handled. 
! */
! 
! static bool
! tree_duplicate_loop_to_exit_cfg (struct loop *loop, struct loops *loops,
! 				 struct loop **new_loop_p)
! {
!   struct loop *target;
!   basic_block *new_bbs, *bbs;
!   edge latch_edge;
  
!   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);
  
!   bbs = get_loop_body (loop);
  
!   /* Check whether duplication is possible.  */
!   if (!can_copy_bbs_p (bbs, loop->num_nodes))
!     {
!       free (bbs);
!       return false;
!     }
!   new_bbs = xmalloc (sizeof (basic_block) * loop->num_nodes);
  
!   /* Find edge from latch.  */
!   latch_edge = loop_latch_edge (loop);
  
!   /* We duplicate only innermost loops */
!   if(loop->inner)
      {
!       if (dump_file && (dump_flags & TDF_DETAILS))
! 	  fprintf (dump_file,
! 		   "Loop duplication failed. Loop is not innermost.\n");
!       free (bbs);
!       return false;
      }
  
!   /* FORNOW: only loops with 1 exit. */
!   if(loop->num_exits != 1)
!     {
!       if (dump_file && (dump_flags & TDF_DETAILS))
! 	  fprintf (dump_file,
! 		   "More than one exit from loop.\n");
!       return false;
!     }    
! 
!   /* Loop the new bbs will belong to.  */
!   target = loop->outer;
!   if(!target)
!     {
!       if (dump_file && (dump_flags & TDF_DETAILS))
! 	  fprintf (dump_file,
! 		   "Loop is outer-most loop.\n");
!       return false;
!     }    
!     
!   /* Generate new loop structure. */
!   new_loop = duplicate_loop (loops, loop, target); 
!   if(!new_loop)
!     {
!       if (dump_file && (dump_flags & TDF_DETAILS))
! 	  fprintf (dump_file,
! 		   "duplicate_loop returns NULL.\n");
!       return false;
! 
!     }
  
!   /* FIXME: Should we copy contents of the loop structure
!      to the new loop?  */
  
!   copy_bbs (bbs, n, new_bbs, NULL, 0, NULL, NULL);
!   for (i = 0; i < n; i++)
!     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);
  
  
!   *new_loop_p = new_loop;
!   return true;
  }
  
! /* This function generate pure copy of LOOP 
!    and locate it immediately after given LOOP.
!    It fixes phis of copy loop so that they inherit 
!    one of their values from exit edge of initial LOOP.  */
  
! bool
! tree_duplicate_loop_to_exit (struct loop *loop, struct loops *loops)
  {
!   struct loop *new_loop = NULL;
!   bitmap definitions;
!   edge pred;
!   tree *new_names, new_var;
!   tree phi, def;
!   unsigned first_new_block;
! 
!   if (any_marked_for_rewrite_p ())
!     abort ();
  
!   first_new_block = last_basic_block;
!   if(!tree_duplicate_loop_to_exit_cfg (loop, loops, &new_loop))
      {
!       if (dump_file && (dump_flags & TDF_DETAILS))
! 	fprintf (dump_file,
! 		 "tree_duplicate_loop_to_exit failed.\n");
!       return false;
      }
  
!   if(!new_loop)
!     abort();
  
!   definitions = marked_ssa_names ();
!   allocate_new_names (definitions, 1, false);
  
!   /* Copy phis from loop->header to new_loop->header.  */
!   tdlte_copy_phi_nodes (loop, new_loop);
  
!   /* Fix phis to inherit values from loop exit edge.  */
!   for (phi = phi_nodes (new_loop->header); phi; phi = TREE_CHAIN (phi))
!     {
!       pred = new_loop->header->pred;
!       def = PHI_ARG_DEF_FROM_EDGE (phi, pred);
  
!       if (TREE_CODE (def) != SSA_NAME)
! 	continue;
  
!       new_names = SSA_NAME_AUX (def);
  
!       /* Something defined outside of the loop.  */
!       if (!new_names)
! 	continue;
! 
!       /* An ordinary ssa name defined in the loop.  */
!       new_var = new_names[new_loop->header->rbi->copy_number];
!       
!       add_phi_arg (&phi, new_var, loop_latch_edge(new_loop));
!     }
  
!   /* Rename the variables.  */
!   tdlte_rename_variables_in_loop (new_loop);
  
!   free_new_names (definitions, false);
  
!   BITMAP_XFREE (definitions);
!   unmark_all_for_rewrite ();
  
!   return true;
! }
  
--- 715,1068 ----
      }
  }
  
  
! /* Duplicates LOOP to the exit edge EXIT.  The original loops exit condition
!    is changed to EXIT_ON.  The newly created loop is returned.  In case
!    duplication fails, NULL is returned instead.
! 
!    I.e.
! 
!    while (1)
!      {
!        before;
!        if (cond)
!          break;
!        after;
!      }
! 
!    is transformed into
! 
!    while (1)
!      {
!        before;
!        if (exit_on)
!          break;
!        after;
!      }
! 
!    while (!cond)
!      {
!        after;
!        before;
!      } */
  
! struct loop *
! tree_split_loop_iterations (struct loop *loop, edge exit, tree exit_on,
! 			    struct loops *loops)
  {
!   basic_block *bbs, *new_bbs, *doms, new_latch_orig;
!   struct loop *new_loop, *aloop;
!   block_stmt_iterator bsi;
!   tree stmt;
!   edge new_exit, e;
!   unsigned n_bbs, n_doms, i;
!   tree phi;
!   bitmap definitions_before, all_definitions;
!   unsigned exit_bb_index;
!   htab_t ssa_name_map = NULL;
  
!   if (any_marked_for_rewrite_p ())
!     abort ();
  
!   /* Check whether duplication is possible.  */
  
!   if (!just_once_each_iteration_p (loop, exit->src))
!     return NULL;
  
!   if (loop->inner)
!     return NULL;
  
!   if (!can_duplicate_loop_p (loop))
!     return NULL;
  
!   /* Ensure that the exit is in a separate basic block.  */
!   bsi = bsi_last (exit->src);
!   if (bsi_end_p (bsi))
!     return NULL;
!   stmt = bsi_stmt (bsi);
!   if (TREE_CODE (stmt) != COND_EXPR)
!     return NULL;
!   bsi_prev (&bsi);
!   if (!bsi_end_p (bsi))
      {
!       stmt = bsi_stmt (bsi);
!       split_loop_bb (exit->src, stmt);
      }
  
!   /* And that it has just a single predecessor that has just a single
!      successor, and that it contains no phi nodes.  */
!   if (exit->src->pred->pred_next
!       || exit->src->pred->src->succ->succ_next
!       || phi_nodes (exit->src))
!     split_loop_bb (exit->src, NULL);
!   new_latch_orig = exit->src->pred->src;
! 
!   /* The duplication itself.  */
!   n_bbs = loop->num_nodes;
!   bbs = get_loop_body_in_dom_order (loop);
!   for (exit_bb_index = 0; bbs[exit_bb_index] != exit->src; exit_bb_index++)
!     continue;
! 
!   if (loops->state & LOOPS_HAVE_MARKED_SINGLE_EXITS)
!     {
!       /* Exclude the EXIT from consideration for now, since it is not going to
! 	 be really duplicated.  */
!       update_single_exits_after_duplication (bbs, exit_bb_index,
! 					     loop->outer);
!       update_single_exits_after_duplication (bbs + exit_bb_index + 1,
! 					     n_bbs - exit_bb_index - 1,
! 					     loop->outer);
!     }
! 
!   new_loop = duplicate_loop (loops, loop, loop->outer);
!   new_bbs = xmalloc (sizeof (basic_block) * n_bbs);
! 
!   copy_bbs (bbs, exit_bb_index, new_bbs, NULL, 0, NULL, loop->outer);
!   definitions_before = marked_ssa_names ();
!   copy_bbs (bbs + exit_bb_index, n_bbs - exit_bb_index, new_bbs + exit_bb_index,
! 	    &exit, 1, &new_exit, loop->outer);
!   all_definitions = marked_ssa_names ();
! 
!   /* Due to copying the loop in two parts some edges were not redirected.  */
!   redirect_edge_and_branch_force (new_latch_orig->rbi->copy->succ,
! 				  new_exit->src);
!   redirect_edge_and_branch_force (loop->latch->rbi->copy->succ,
! 				  loop->header->rbi->copy);
! 
!   add_phi_args_after_copy (new_bbs, n_bbs);
! 
!   set_immediate_dominator (CDI_DOMINATORS, new_exit->src, exit->src);
!   set_immediate_dominator (CDI_DOMINATORS, new_loop->header, new_loop->latch);
!   new_loop->header = new_exit->src;
!   new_loop->latch = new_latch_orig->rbi->copy;
! 
!   if (loops->state & LOOPS_HAVE_MARKED_SINGLE_EXITS)
!     {
!       if (loop->single_exit == exit)
! 	new_loop->single_exit = new_exit;
! 
!       for (aloop = loop->outer;
! 	   !flow_bb_inside_loop_p (aloop, exit->dest);
! 	   aloop = aloop->outer)
! 	if (aloop->single_exit == exit)
! 	  aloop->single_exit = new_exit;
!     }
! 
!   redirect_edge_and_branch_force (exit, new_exit->src);
!   /* Forget the phi nodes on the exit of the original loop, since they are no
!      longer used.  */
!   PENDING_STMT (exit) = NULL;
! 
!   stmt = last_stmt (exit->src);
!   COND_EXPR_COND (stmt) = exit_on;
!   if (exit->flags & EDGE_FALSE_VALUE)
!     {
!       exit->flags &= ~EDGE_FALSE_VALUE;
!       exit->flags |= EDGE_TRUE_VALUE;
! 
!       e = exit->src->succ;
!       if (e == exit)
! 	e = e->succ_next;
! 
!       exit->flags &= ~EDGE_TRUE_VALUE;
!       exit->flags |= EDGE_FALSE_VALUE;
!     }
! 
!   /* Update the dominators.  */
!   doms = xmalloc (sizeof (basic_block) * n_basic_blocks);
!   n_doms = get_dominated_by_region (CDI_DOMINATORS, bbs, n_bbs, doms);
!   iterate_fix_dominators (CDI_DOMINATORS, doms, n_doms);
!   free (doms);
! 
!   /* Rewrite the ssa names in the copy of the loop.  But first create the phi
!      nodes that transfer values from LOOP to NEW_LOOP.  TODO -- for now we
!      transfer all values defined before the exit, it is sufficient to transfer
!      those that are used after the exit.  */
!   EXECUTE_IF_SET_IN_BITMAP (definitions_before, 0, i,
!     {
!       phi = create_phi_node (ssa_name (i), new_loop->header);
!       add_phi_arg (&phi, ssa_name (i), new_loop->header->pred);
!       add_phi_arg (&phi, ssa_name (i), new_loop->header->pred->pred_next);
!     });
!   allocate_ssa_names (all_definitions, &ssa_name_map);
!   rewrite_to_new_ssa_names (new_bbs, exit_bb_index, ssa_name_map);
!   allocate_ssa_names (definitions_before, &ssa_name_map);
!   rewrite_to_new_ssa_names (new_bbs + exit_bb_index, n_bbs - exit_bb_index,
! 			    ssa_name_map);
  
!   /* Ensure that NEW_LOOP has a simple preheader.  */
!   split_loop_exit_edge (exit);
  
! #ifdef ENABLE_CHECKING
!   verify_dominators (CDI_DOMINATORS);
!   verify_loop_structure (loops);
!   verify_loop_closed_ssa ();
! #endif
  
    free (new_bbs);
    free (bbs);
  
+   unmark_all_for_rewrite ();
+   BITMAP_XFREE (definitions_before);
+   BITMAP_XFREE (all_definitions);
+   htab_delete (ssa_name_map);
  
!   return new_loop;
  }
  
! /* Split loop exit edge EXIT.  The things are a bit complicated by a need to
!    preserve the loop closed ssa form.  */
  
! void
! split_loop_exit_edge (edge exit)
  {
!   basic_block dest = exit->dest;
!   basic_block bb = loop_split_edge_with (exit, NULL);
!   tree phi, new_phi, new_name;
!   use_operand_p op_p;
  
!   for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi))
      {
!       op_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, bb->succ);
! 
!       new_name = duplicate_ssa_name (USE_FROM_PTR (op_p), NULL);
!       new_phi = create_phi_node (new_name, bb);
!       SSA_NAME_DEF_STMT (new_name) = new_phi;
!       add_phi_arg (&new_phi, USE_FROM_PTR (op_p), exit);
!       SET_USE (op_p, new_name);
      }
+ }
  
! /* Insert statement STMT to the edge E and update the loop structures.
!    Returns the newly created block (if any).  */
  
! basic_block
! bsi_insert_on_edge_immediate_loop (edge e, tree stmt)
! {
!   basic_block src, dest, new_bb;
!   struct loop *loop_c;
  
!   src = e->src;
!   dest = e->dest;
  
!   loop_c = find_common_loop (src->loop_father, dest->loop_father);
  
!   new_bb = bsi_insert_on_edge_immediate (e, stmt);
  
!   if (!new_bb)
!     return NULL;
  
!   add_bb_to_loop (new_bb, loop_c);
!   if (dest->loop_father->latch == src)
!     dest->loop_father->latch = new_bb;
! 
!   return new_bb;
! }
  
! /* Ensure that the number of iterations of LOOP is divisible by MOD,
!    by moving a few last iterations to the new loop.  EXIT is the exit edge
!    on that the new loop is created.  NITER is the number of iterations
!    of the LOOP before it exits through EXIT.  LOOPS is the loop tree.
!    MOD must be a power of two.
!    
!    For example
!    
!    while (1)
!      {
!        before;
!        if (cond)
!          break;
!        after;
!      }
! 
!    is transformed into
! 
!    niter1 = (niter + 1) & ~(mod - 1);
!    if (niter < mod - 1)
!      before;
!    else
!      {
!        while (1)
!          {
!             before;
! 	    if (--niter1 == 0)
! 	      break;
! 	    after;
! 	 }
!      }
!    while (!cond)
!      {
!        after;
!        before;
!      }
!    */ 
  
! struct loop *
! tree_align_loop_iterations (struct loop *loop, edge exit, tree niter,
! 			    unsigned mod, struct loops *loops)
! {
!   tree niter1, stmts, type, tmod, niter_count, exit_cond_stmt;
!   tree var_base, exit_cond, init_cond, always_exit;
!   struct loop *new_loop;
!   block_stmt_iterator bsi;
!   bool after;
!   basic_block init_cond_bb;
  
!   /* MOD must be a power of two.  */
!   if (mod & (mod - 1))
!     abort ();
  
!   /* Prepare the expression for # of iterations.  */
!   type = TREE_TYPE (niter);
!   var_base = create_tmp_var (type, "unaligned_niter_tmp");
!   add_referenced_tmp_var (var_base);
! 
!   niter = force_gimple_operand (unshare_expr (niter), &stmts, false, var_base);
!   if (stmts)
!     bsi_insert_on_edge_immediate_loop (loop_preheader_edge (loop),
! 				       stmts);
! 
!   niter1 = build2 (PLUS_EXPR, type,
! 		   unshare_expr (niter), build_int_cst (type, 1));
!   tmod = fold (build1 (BIT_NOT_EXPR, type, build_int_cst (type, mod - 1)));
!   niter1 = build2 (BIT_AND_EXPR, type, niter1, tmod);
!   niter1 = fold (niter1);
! 
!   var_base = create_tmp_var (type, "aligned_niter_tmp");
!   add_referenced_tmp_var (var_base);
!   niter1 = force_gimple_operand (niter1, &stmts, false, var_base);
!   if (stmts)
!     bsi_insert_on_edge_immediate_loop (loop_preheader_edge (loop),
! 				       stmts);
! 
!   /* Prepare the counter of iterations of the loop.  */
!   var_base = create_tmp_var (type, "align_niter_iv");
!   add_referenced_tmp_var (var_base);
!   standard_iv_increment_position (loop, &bsi, &after);
!   create_iv (niter1, build_int_cst (type, (HOST_WIDE_INT) -1),
! 	     var_base, loop, &bsi, after, &niter_count, NULL);
! 
!   /* Split out the new loop and insert the niter1 != 1 exit condition to
!      the original loop.  */
!   exit_cond = build2 (EQ_EXPR, boolean_type_node,
! 		      niter_count, build_int_cst (type, 1));
!   new_loop = tree_split_loop_iterations (loop, exit, exit_cond, loops);
!   if (!new_loop)
!     return NULL;
! 
!   /* Use loop versioning to create the niter < mod - 1 guard.  */
!   init_cond = build2 (GE_EXPR, boolean_type_node,
! 		      niter,  build_int_cst (type, mod - 1));
!   tree_ssa_loop_version (loops, loop, init_cond, &init_cond_bb);
!   
!   /* Make the "after" part of the second version of the loop
!      unreachable.  */
!   if (exit->flags & EDGE_TRUE_VALUE)
!     always_exit = boolean_true_node;
!   else
!     always_exit = boolean_false_node;
!   exit_cond_stmt = last_stmt (exit->src->rbi->copy);
!   COND_EXPR_COND (exit_cond_stmt) = always_exit;
  
+   return new_loop;
+ }
Index: tree-vectorizer.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-vectorizer.c,v
retrieving revision 1.1.2.58
diff -c -3 -p -r1.1.2.58 tree-vectorizer.c
*** tree-vectorizer.c	3 Aug 2004 22:46:01 -0000	1.1.2.58
--- tree-vectorizer.c	4 Aug 2004 19:03:28 -0000
*************** int tree_nargs[] = {
*** 224,229 ****
--- 224,625 ----
  
  #undef DEFTREECODE
  
+ /* tree_duplicate_loop_to_exit and the helper functions for it used to be
+    placed in tree-ssa-loop-manip.c.  However tree_duplicate_loop_to_exit does
+    not preserve semantics of the program.  As one of the consequences it
+    modifies the SSA form to some ad-hoc undocumented state.  Both semantics and
+    SSA form is then magically restored in vect_transform_loop.
+ 
+    The function is unsuitable for generic use, and therefore is moved here.
+    If needed, use tree_split_loop_iterations or tree_align_loop_iterations,
+    which provide similar functionality, but actually preserve semantics of the
+    program and keep ssa form in a consistent state.  */
+ 
+ /* Releases the structures holding the new ssa names. 
+    The original ssa names are released if ORIGIN is true.
+    Otherwise they are saved for initial loop copy.  */
+ 
+ static void
+ free_new_names (bitmap definitions, bool origin)
+ {
+   tree def;
+   unsigned ver;
+ 
+   EXECUTE_IF_SET_IN_BITMAP (definitions, 0, ver,
+     {
+       def = ssa_name (ver);
+ 
+       if (SSA_NAME_AUX (def))
+ 	{
+ 	  free (SSA_NAME_AUX (def));
+ 	  SSA_NAME_AUX (def) = NULL;
+ 	}
+ 
+       if (origin)
+ 	release_ssa_name_force (def);
+     });
+ }
+ 
+ /* For each definition in DEFINITIONS allocates:
+ 
+    NDUPL + 1 copies if ORIGIN is true
+    NDUPL copies if ORIGIN is false
+ 
+    (one for each duplicate of the loop body).  
+    If ORIGIN is true, additional set of DEFINITIONS 
+    is allocated for initial loop copy. */
+ 
+ static void
+ allocate_new_names (bitmap definitions, unsigned ndupl, bool origin)
+ {
+   tree def;
+   unsigned i, ver;
+   tree *new_names;
+   bool abnormal;
+ 
+   EXECUTE_IF_SET_IN_BITMAP (definitions, 0, ver,
+     {
+       def = ssa_name (ver);
+       new_names = xmalloc (sizeof (tree) * (ndupl + (origin ? 1 : 0)));
+ 
+       abnormal = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def);
+       for (i = (origin ? 0 : 1); i <= ndupl; i++)
+ 	{
+ 	  new_names[i] = duplicate_ssa_name (def, SSA_NAME_DEF_STMT (def));
+ 	  SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_names[i]) = abnormal;
+ 	}
+      /* Delay this until now so it doesn't get propagated to the copies.
+ 	That would cause problems in the next outer loop.  */
+       SSA_NAME_AUX (def) = new_names;
+     });
+ }
+ 
+ /* Renames the variable *OP_P in statement STMT.  If DEF is true,
+    *OP_P is defined by the statement.  N_COPY is the number of the
+    copy of the loop body we are renaming.  */
+ 
+ static void
+ rename_use_op (use_operand_p op_p, unsigned n_copy)
+ {
+   tree *new_names;
+ 
+   if (TREE_CODE (USE_FROM_PTR (op_p)) != SSA_NAME)
+     return;
+ 
+   new_names = SSA_NAME_AUX (USE_FROM_PTR (op_p));
+ 
+   /* Something defined outside of the loop.  */
+   if (!new_names)
+     return;
+ 
+   /* An ordinary ssa name defined in the loop.  */
+ 
+   SET_USE (op_p, new_names[n_copy]);
+ }
+ 
+ /* Renames the variable *OP_P in statement STMT.  If DEF is true,
+    *OP_P is defined by the statement.  N_COPY is the number of the
+    copy of the loop body we are renaming.  */
+ 
+ static void
+ rename_def_op (def_operand_p op_p, tree stmt, unsigned n_copy)
+ {
+   tree *new_names;
+ 
+   if (TREE_CODE (DEF_FROM_PTR (op_p)) != SSA_NAME)
+     return;
+ 
+   new_names = SSA_NAME_AUX (DEF_FROM_PTR (op_p));
+ 
+   /* Something defined outside of the loop.  */
+   if (!new_names)
+     return;
+ 
+   /* An ordinary ssa name defined in the loop.  */
+ 
+   SET_DEF (op_p, new_names[n_copy]);
+   SSA_NAME_DEF_STMT (DEF_FROM_PTR (op_p)) = stmt;
+ }
+ 
+ /* Renames the variables in basic block BB.  */
+ 
+ static void
+ rename_variables_in_bb (basic_block bb)
+ {
+   tree phi;
+   block_stmt_iterator bsi;
+   tree stmt;
+   stmt_ann_t ann;
+   use_optype uses;
+   vuse_optype vuses;
+   def_optype defs;
+   v_may_def_optype v_may_defs;
+   v_must_def_optype v_must_defs;
+   unsigned i, nbb = bb->rbi->copy_number;
+   edge e;
+ 
+   for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
+     rename_def_op (PHI_RESULT_PTR (phi), phi, nbb);
+ 
+   for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+     {
+       stmt = bsi_stmt (bsi);
+       get_stmt_operands (stmt);
+       ann = stmt_ann (stmt);
+ 
+       uses = USE_OPS (ann);
+       for (i = 0; i < NUM_USES (uses); i++)
+ 	rename_use_op (USE_OP_PTR (uses, i), nbb);
+ 
+       defs = DEF_OPS (ann);
+       for (i = 0; i < NUM_DEFS (defs); i++)
+ 	rename_def_op (DEF_OP_PTR (defs, i), stmt, nbb);
+ 
+       vuses = VUSE_OPS (ann);
+       for (i = 0; i < NUM_VUSES (vuses); i++)
+ 	rename_use_op (VUSE_OP_PTR (vuses, i), nbb);
+ 
+       v_may_defs = V_MAY_DEF_OPS (ann);
+       for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
+ 	{
+ 	  rename_use_op (V_MAY_DEF_OP_PTR (v_may_defs, i), nbb);
+ 	  rename_def_op (V_MAY_DEF_RESULT_PTR (v_may_defs, i), stmt, nbb);
+ 	}
+ 
+       v_must_defs = V_MUST_DEF_OPS (ann);
+       for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++)
+ 	rename_def_op (V_MUST_DEF_OP_PTR (v_must_defs, i), stmt, nbb);
+ 
+     }
+ 
+   for (e = bb->succ; e; e = e->succ_next)
+     for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi))
+       rename_use_op (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), nbb);
+ }
+ /* Renames variables in new generated LOOP.  */
+ 
+ static void
+ tdlte_rename_variables_in_loop (struct loop *loop)
+ {
+   unsigned i;
+   basic_block *bbs;
+ 
+   bbs = get_loop_body (loop);
+ 
+   for (i = 0; i < loop->num_nodes; i++)
+     {
+       rename_variables_in_bb (bbs[i]);
+     }
+ 
+   free (bbs);
+ }
+ 
+ /* This function copies phis from loop to new_loop 
+    as they were not generated by duplication of bbs.  */
+ 
+ static void
+ tdlte_copy_phi_nodes (struct loop *loop, struct loop *new_loop)
+ {
+   tree phi, new_phi, def;
+   edge new_e;
+   edge latch = loop_latch_edge (loop);
+ 
+      
+   for (phi = phi_nodes (loop->header), 
+ 	 new_phi = phi_nodes (new_loop->header); 
+        phi; 
+        phi = TREE_CHAIN (phi), 
+ 	 new_phi = TREE_CHAIN (new_phi))
+     {
+       new_e = new_loop->header->pred;
+       def = PHI_ARG_DEF_FROM_EDGE (phi, latch);
+       add_phi_arg (&new_phi, def, new_e);
+     }
+ 
+ }
+ 
+ /* This function: 
+    - copies basic blocks of the loop LOOP;
+    - locate them at the only exit of LOOP; 
+    - redirect edges so that two loops are produced: 
+              initial LOOP and newly generated;
+    - update dominators;
+    - returns pointer to new loop in NEW_LOOP_P.
+ 
+    FORNOW: only innermost loops with 
+            1 exit are handled. 
+ */
+ 
+ static bool
+ tree_duplicate_loop_to_exit_cfg (struct loop *loop, struct loops *loops,
+ 				 struct loop **new_loop_p)
+ {
+   struct loop *target;
+   basic_block *new_bbs, *bbs;
+   edge latch_edge;
+ 
+   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);
+ 
+   bbs = get_loop_body (loop);
+ 
+   /* Check whether duplication is possible.  */
+   if (!can_copy_bbs_p (bbs, loop->num_nodes))
+     {
+       free (bbs);
+       return false;
+     }
+   new_bbs = xmalloc (sizeof (basic_block) * loop->num_nodes);
+ 
+   /* Find edge from latch.  */
+   latch_edge = loop_latch_edge (loop);
+ 
+   /* We duplicate only innermost loops */
+   if(loop->inner)
+     {
+       if (dump_file && (dump_flags & TDF_DETAILS))
+ 	  fprintf (dump_file,
+ 		   "Loop duplication failed. Loop is not innermost.\n");
+       free (bbs);
+       return false;
+     }
+ 
+   /* FORNOW: only loops with 1 exit. */
+   if(loop->num_exits != 1)
+     {
+       if (dump_file && (dump_flags & TDF_DETAILS))
+ 	  fprintf (dump_file,
+ 		   "More than one exit from loop.\n");
+       return false;
+     }    
+ 
+   /* Loop the new bbs will belong to.  */
+   target = loop->outer;
+   if(!target)
+     {
+       if (dump_file && (dump_flags & TDF_DETAILS))
+ 	  fprintf (dump_file,
+ 		   "Loop is outer-most loop.\n");
+       return false;
+     }    
+     
+   /* Generate new loop structure. */
+   new_loop = duplicate_loop (loops, loop, target); 
+   if(!new_loop)
+     {
+       if (dump_file && (dump_flags & TDF_DETAILS))
+ 	  fprintf (dump_file,
+ 		   "duplicate_loop returns NULL.\n");
+       return false;
+ 
+     }
+ 
+   /* FIXME: Should we copy contents of the loop structure
+      to the new loop?  */
+ 
+   copy_bbs (bbs, n, new_bbs, NULL, 0, NULL, NULL);
+   for (i = 0; i < n; i++)
+     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);
+ 
+ 
+   *new_loop_p = new_loop;
+   return true;
+ }
+ 
+ /* This function generate pure copy of LOOP 
+    and locate it immediately after given LOOP.
+    It fixes phis of copy loop so that they inherit 
+    one of their values from exit edge of initial LOOP.  */
+ 
+ static bool
+ tree_duplicate_loop_to_exit (struct loop *loop, struct loops *loops)
+ {
+   struct loop *new_loop = NULL;
+   bitmap definitions;
+   edge pred;
+   tree *new_names, new_var;
+   tree phi, def;
+   unsigned first_new_block;
+ 
+   if (any_marked_for_rewrite_p ())
+     abort ();
+ 
+   first_new_block = last_basic_block;
+   if(!tree_duplicate_loop_to_exit_cfg (loop, loops, &new_loop))
+     {
+       if (dump_file && (dump_flags & TDF_DETAILS))
+ 	fprintf (dump_file,
+ 		 "tree_duplicate_loop_to_exit failed.\n");
+       return false;
+     }
+ 
+   if(!new_loop)
+     abort();
+ 
+   definitions = marked_ssa_names ();
+   allocate_new_names (definitions, 1, false);
+ 
+   /* Copy phis from loop->header to new_loop->header.  */
+   tdlte_copy_phi_nodes (loop, new_loop);
+ 
+   /* Fix phis to inherit values from loop exit edge.  */
+   for (phi = phi_nodes (new_loop->header); phi; phi = TREE_CHAIN (phi))
+     {
+       pred = new_loop->header->pred;
+       def = PHI_ARG_DEF_FROM_EDGE (phi, pred);
+ 
+       if (TREE_CODE (def) != SSA_NAME)
+ 	continue;
+ 
+       new_names = SSA_NAME_AUX (def);
+ 
+       /* Something defined outside of the loop.  */
+       if (!new_names)
+ 	continue;
+ 
+       /* An ordinary ssa name defined in the loop.  */
+       new_var = new_names[new_loop->header->rbi->copy_number];
+       
+       add_phi_arg (&phi, new_var, loop_latch_edge(new_loop));
+     }
+ 
+   /* Rename the variables.  */
+   tdlte_rename_variables_in_loop (new_loop);
+ 
+   free_new_names (definitions, false);
+ 
+   BITMAP_XFREE (definitions);
+   unmark_all_for_rewrite ();
+ 
+   return true;
+ }
  
  /* Function new_stmt_vec_info.
  



More information about the Gcc-patches mailing list