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]

[patch] Cfghooks rewrite


Hello,

this patch moves the parts of the cfg manipulation that are independent
on the code representation to the cfg hooks.  The main reason for this
patch is that it should decrease the number of conflicts between
tree-ssa and mainline significantly.

Bootstrapped & regtested on i686.

Zdenek

	* Makefile.in (cfghooks.o): Add TIMEVAR_H and toplev.h dependency.
	* basic-block.h (tidy_fallthru_edge, tidy_fallthru_edges, dump_bb,
	verify_flow_info): Declaration removed.
	* cfg.c (verify_flow_info, dump_bb): Moved to cfghooks.c.
	(debug_bb, debug_bb_n): Add argument to dump_bb call.
	* cfgcleanup.c (try_simplify_condjump, try_crossjump_to_edge,
	try_optimize_cfg, delete_unreachable_blocks): Use delete_basic_block
	instead of delete_block.
	* cfghooks.c: Include timevar.h and toplev.h.
	(cfg_hooks): Define here.
	(verify_flow_info, dump_bb): Moved from cfg.c.
	(redirect_edge_and_branch, redirect_edge_and_branch_force,
	split_block, split_block_after_labels, move_block_after,
	delete_basic_block, split_edge, create_basic_block,
	create_empty_bb, can_merge_blocks_p, merge_blocks,
	make_forwarder_block, tidy_fallthru_edge, tidy_fallthru_edges):
	New functions.
	* cfghooks.h (struct cfg_hooks): Added fields name,
	make_forwarder_block, tidy_fallthru_edge and
	move_block_after. Changed type of verify_flow_info, dump_bb,
	split_block fields. Renamed cfgh_split_edge and delete_block
	fields.
	(redirect_edge_and_branch, redirect_edge_and_branch_force,
	split_block, delete_block, split_edge, create_basic_block,
	can_merge_blocks_p, merge_blocks): Macros removed.
	(cfg_hooks): Do not export.
	(verify_flow_info, dump_bb, redirect_edge_and_branch,
	redirect_edge_and_branch_force, split_block, split_block_after_labels,
	move_block_after, delete_basic_block, split_edge, create_basic_block,
	create_empty_bb, can_merge_blocks_p, merge_blocks,
	make_forwarder_block, tidy_fallthru_edge, tidy_fallthru_edges):
	Declare.
	(cfg_layout_rtl_cfg_hooks): Declare.
	* cfgloop.c (update_latch_info, mfb_keep_just, mfb_keep_nonlatch):
	New functions.
	(canonicalize_loop_headers): Use new semantics of make_forwarder_block.
	(redirect_edge_with_latch_update): Removed.
	(make_forwarder_block): Moved to cfghooks.c, semantics changed.
	* cfgloopmanip.c (remove_bbs): Do not update dominators here.
	* cfgrtl.c (cfg_layout_split_block, rtl_split_block, rtl_dump_bb,
	rtl_delete_block, rtl_split_block, rtl_merge_blocks,
	tidy_fallthru_edge, rtl_split_edge, cfg_layout_delete_block,
	cfg_layout_merge_blocks, cfg_layout_split_edge): Partly moved to
	cfghooks.c.
	(rtl_create_basic_block): Coding style fix.
	(rtl_tidy_fallthru_edge, rtl_move_block_after,
	rtl_make_forwarder_block): New functions.
	(update_cfg_after_block_merging): Removed.
	(rtl_cfg_hooks, cfg_layout_rtl_cfg_hooks): Fill in new entries.
	* flow.c (verify_wide_reg, verify_local_live_at_start): Add argument
	to dump_bb.
	* ifcvt.c (merge_if_block, find_cond_trap, find_if_case_1,
	find_if_case_2): Don't update dominators.
	* timevar.def (TV_CFG_VERIFY): New.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1234
diff -c -3 -p -r1.1234 Makefile.in
*** Makefile.in	27 Jan 2004 20:35:50 -0000	1.1234
--- Makefile.in	28 Jan 2004 10:20:43 -0000
*************** cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) co
*** 1684,1690 ****
     $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \
     function.h except.h $(GGC_H) $(TM_P_H) alloc-pool.h
  cfghooks.o: cfghooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
!    $(BASIC_BLOCK_H) cfglayout.h
  cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \
     insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \
     function.h except.h $(GGC_H) $(TM_P_H) insn-config.h $(EXPR_H)
--- 1684,1690 ----
     $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \
     function.h except.h $(GGC_H) $(TM_P_H) alloc-pool.h
  cfghooks.o: cfghooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
!    $(BASIC_BLOCK_H) cfglayout.h $(TIMEVAR_H) toplev.h
  cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \
     insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \
     function.h except.h $(GGC_H) $(TM_P_H) insn-config.h $(EXPR_H)
Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/basic-block.h,v
retrieving revision 1.189
diff -c -3 -p -r1.189 basic-block.h
*** basic-block.h	23 Jan 2004 11:02:06 -0000	1.189
--- basic-block.h	28 Jan 2004 10:20:44 -0000
*************** extern edge redirect_edge_succ_nodup (ed
*** 363,370 ****
  extern void redirect_edge_pred (edge, basic_block);
  extern basic_block create_basic_block_structure (rtx, rtx, rtx, basic_block);
  extern void clear_bb_flags (void);
- extern void tidy_fallthru_edge (edge, basic_block, basic_block);
- extern void tidy_fallthru_edges (void);
  extern void flow_reverse_top_sort_order_compute (int *);
  extern int flow_depth_first_order_compute (int *, int *);
  extern void flow_preorder_transversal_compute (int *);
--- 363,368 ----
*************** extern bool probably_never_executed_bb_p
*** 537,543 ****
  
  /* In flow.c */
  extern void init_flow (void);
- extern void dump_bb (basic_block, FILE *);
  extern void debug_bb (basic_block);
  extern basic_block debug_bb_n (int);
  extern void dump_regset (regset, FILE *);
--- 535,540 ----
*************** extern void alloc_aux_for_edge (edge, in
*** 569,579 ****
  extern void alloc_aux_for_edges (int);
  extern void clear_aux_for_edges (void);
  extern void free_aux_for_edges (void);
- 
- /* This function is always defined so it can be called from the
-    debugger, and it is declared extern so we don't get warnings about
-    it being unused.  */
- extern void verify_flow_info (void);
  
  typedef struct conflict_graph_def *conflict_graph;
  
--- 566,571 ----
Index: cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfg.c,v
retrieving revision 1.57
diff -c -3 -p -r1.57 cfg.c
*** cfg.c	21 Jan 2004 20:39:52 -0000	1.57
--- cfg.c	28 Jan 2004 10:20:44 -0000
*************** free_aux_for_edges (void)
*** 810,994 ****
    clear_aux_for_edges ();
  }
  
- /* Verify the CFG consistency.
- 
-    Currently it does following checks edge and basic block list correctness
-    and calls into IL dependent checking then.  */
- void
- verify_flow_info (void)
- {
-   size_t *edge_checksum;
-   int num_bb_notes, err = 0;
-   basic_block bb, last_bb_seen;
-   basic_block *last_visited;
- 
-   last_visited = xcalloc (last_basic_block + 2, sizeof (basic_block));
-   edge_checksum = xcalloc (last_basic_block + 2, sizeof (size_t));
- 
-   /* Check bb chain & numbers.  */
-   last_bb_seen = ENTRY_BLOCK_PTR;
-   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb, NULL, next_bb)
-     {
-       if (bb != EXIT_BLOCK_PTR
- 	  && bb != BASIC_BLOCK (bb->index))
- 	{
- 	  error ("bb %d on wrong place", bb->index);
- 	  err = 1;
- 	}
- 
-       if (bb->prev_bb != last_bb_seen)
- 	{
- 	  error ("prev_bb of %d should be %d, not %d",
- 		 bb->index, last_bb_seen->index, bb->prev_bb->index);
- 	  err = 1;
- 	}
- 
-       last_bb_seen = bb;
-     }
- 
-   /* Now check the basic blocks (boundaries etc.) */
-   FOR_EACH_BB_REVERSE (bb)
-     {
-       int n_fallthru = 0;
-       edge e;
- 
-       if (bb->count < 0)
- 	{
- 	  error ("verify_flow_info: Wrong count of block %i %i",
- 	         bb->index, (int)bb->count);
- 	  err = 1;
- 	}
-       if (bb->frequency < 0)
- 	{
- 	  error ("verify_flow_info: Wrong frequency of block %i %i",
- 	         bb->index, bb->frequency);
- 	  err = 1;
- 	}
-       for (e = bb->succ; e; e = e->succ_next)
- 	{
- 	  if (last_visited [e->dest->index + 2] == bb)
- 	    {
- 	      error ("verify_flow_info: Duplicate edge %i->%i",
- 		     e->src->index, e->dest->index);
- 	      err = 1;
- 	    }
- 	  if (e->probability < 0 || e->probability > REG_BR_PROB_BASE)
- 	    {
- 	      error ("verify_flow_info: Wrong probability of edge %i->%i %i",
- 		     e->src->index, e->dest->index, e->probability);
- 	      err = 1;
- 	    }
- 	  if (e->count < 0)
- 	    {
- 	      error ("verify_flow_info: Wrong count of edge %i->%i %i",
- 		     e->src->index, e->dest->index, (int)e->count);
- 	      err = 1;
- 	    }
- 
- 	  last_visited [e->dest->index + 2] = bb;
- 
- 	  if (e->flags & EDGE_FALLTHRU)
- 	    n_fallthru++;
- 
- 	  if (e->src != bb)
- 	    {
- 	      error ("verify_flow_info: Basic block %d succ edge is corrupted",
- 		     bb->index);
- 	      fprintf (stderr, "Predecessor: ");
- 	      dump_edge_info (stderr, e, 0);
- 	      fprintf (stderr, "\nSuccessor: ");
- 	      dump_edge_info (stderr, e, 1);
- 	      fprintf (stderr, "\n");
- 	      err = 1;
- 	    }
- 
- 	  edge_checksum[e->dest->index + 2] += (size_t) e;
- 	}
-       if (n_fallthru > 1)
- 	{
- 	  error ("Wrong amount of branch edges after unconditional jump %i", bb->index);
- 	  err = 1;
- 	}
- 
-       for (e = bb->pred; e; e = e->pred_next)
- 	{
- 	  if (e->dest != bb)
- 	    {
- 	      error ("basic block %d pred edge is corrupted", bb->index);
- 	      fputs ("Predecessor: ", stderr);
- 	      dump_edge_info (stderr, e, 0);
- 	      fputs ("\nSuccessor: ", stderr);
- 	      dump_edge_info (stderr, e, 1);
- 	      fputc ('\n', stderr);
- 	      err = 1;
- 	    }
- 	  edge_checksum[e->dest->index + 2] -= (size_t) e;
- 	}
-     }
- 
-   /* Complete edge checksumming for ENTRY and EXIT.  */
-   {
-     edge e;
- 
-     for (e = ENTRY_BLOCK_PTR->succ; e ; e = e->succ_next)
-       edge_checksum[e->dest->index + 2] += (size_t) e;
- 
-     for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
-       edge_checksum[e->dest->index + 2] -= (size_t) e;
-   }
- 
-   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
-     if (edge_checksum[bb->index + 2])
-       {
- 	error ("basic block %i edge lists are corrupted", bb->index);
- 	err = 1;
-       }
- 
-   num_bb_notes = 0;
-   last_bb_seen = ENTRY_BLOCK_PTR;
- 
-   /* Clean up.  */
-   free (last_visited);
-   free (edge_checksum);
-   err |= cfg_hooks->cfgh_verify_flow_info ();
-   if (err)
-     internal_error ("verify_flow_info failed");
- }
- 
- /* Print out one basic block with live information at start and end.  */
- 
- void
- dump_bb (basic_block bb, FILE *outf)
- {
-   edge e;
- 
-   fprintf (outf, ";; Basic block %d, loop depth %d, count ",
- 	   bb->index, bb->loop_depth);
-   fprintf (outf, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) bb->count);
-   putc ('\n', outf);
-   fputs (";; Predecessors: ", outf);
-   for (e = bb->pred; e; e = e->pred_next)
-     dump_edge_info (outf, e, 0);
-   putc ('\n', outf);
- 
-   cfg_hooks->dump_bb (bb, outf);
- 
-   fputs (";; Successors: ", outf);
-   for (e = bb->succ; e; e = e->succ_next)
-     dump_edge_info (outf, e, 1);
-   putc ('\n', outf);
- }
- 
  void
  debug_bb (basic_block bb)
  {
!   dump_bb (bb, stderr);
  }
  
  basic_block
  debug_bb_n (int n)
  {
    basic_block bb = BASIC_BLOCK (n);
!   dump_bb (bb, stderr);
    return bb;
  }
--- 810,825 ----
    clear_aux_for_edges ();
  }
  
  void
  debug_bb (basic_block bb)
  {
!   dump_bb (bb, stderr, 0);
  }
  
  basic_block
  debug_bb_n (int n)
  {
    basic_block bb = BASIC_BLOCK (n);
!   dump_bb (bb, stderr, 0);
    return bb;
  }
Index: cfgcleanup.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgcleanup.c,v
retrieving revision 1.104
diff -c -3 -p -r1.104 cfgcleanup.c
*** cfgcleanup.c	25 Jan 2004 20:09:27 -0000	1.104
--- cfgcleanup.c	28 Jan 2004 10:20:44 -0000
*************** try_simplify_condjump (basic_block cbran
*** 194,201 ****
  	}
      }
    /* Delete the block with the unconditional jump, and clean up the mess.  */
!   delete_block (jump_block);
!   tidy_fallthru_edge (cbranch_jump_edge, cbranch_block, cbranch_dest_block);
  
    return true;
  }
--- 194,201 ----
  	}
      }
    /* Delete the block with the unconditional jump, and clean up the mess.  */
!   delete_basic_block (jump_block);
!   tidy_fallthru_edge (cbranch_jump_edge);
  
    return true;
  }
*************** try_crossjump_to_edge (int mode, edge e1
*** 1530,1536 ****
    to_remove = redirect_from->succ->dest;
  
    redirect_edge_and_branch_force (redirect_from->succ, redirect_to);
!   delete_block (to_remove);
  
    update_forwarder_flag (redirect_from);
  
--- 1530,1536 ----
    to_remove = redirect_from->succ->dest;
  
    redirect_edge_and_branch_force (redirect_from->succ, redirect_to);
!   delete_basic_block (to_remove);
  
    update_forwarder_flag (redirect_from);
  
*************** try_optimize_cfg (int mode)
*** 1694,1700 ****
  		    fprintf (rtl_dump_file, "Deleting block %i.\n",
  			     b->index);
  
! 		  delete_block (b);
  		  if (!(mode & CLEANUP_CFGLAYOUT))
  		    changed = true;
  		  b = c;
--- 1694,1700 ----
  		    fprintf (rtl_dump_file, "Deleting block %i.\n",
  			     b->index);
  
! 		  delete_basic_block (b);
  		  if (!(mode & CLEANUP_CFGLAYOUT))
  		    changed = true;
  		  b = c;
*************** try_optimize_cfg (int mode)
*** 1755,1761 ****
  
  		  c = b->prev_bb == ENTRY_BLOCK_PTR ? b->next_bb : b->prev_bb;
  		  redirect_edge_succ_nodup (b->pred, b->succ->dest);
! 		  delete_block (b);
  		  changed = true;
  		  b = c;
  		}
--- 1755,1761 ----
  
  		  c = b->prev_bb == ENTRY_BLOCK_PTR ? b->next_bb : b->prev_bb;
  		  redirect_edge_succ_nodup (b->pred, b->succ->dest);
! 		  delete_basic_block (b);
  		  changed = true;
  		  b = c;
  		}
*************** delete_unreachable_blocks (void)
*** 1873,1879 ****
  
        if (!(b->flags & BB_REACHABLE))
  	{
! 	  delete_block (b);
  	  changed = true;
  	}
      }
--- 1873,1879 ----
  
        if (!(b->flags & BB_REACHABLE))
  	{
! 	  delete_basic_block (b);
  	  changed = true;
  	}
      }
Index: cfghooks.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfghooks.c,v
retrieving revision 1.3
diff -c -3 -p -r1.3 cfghooks.c
*** cfghooks.c	22 Jun 2003 15:03:25 -0000	1.3
--- cfghooks.c	28 Jan 2004 10:20:44 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 26,37 ****
  #include "tree.h"
  #include "rtl.h"
  #include "basic-block.h"
! 
! extern struct cfg_hooks rtl_cfg_hooks;
! extern struct cfg_hooks cfg_layout_rtl_cfg_hooks;
  
  /* A pointer to one of the hooks containers.  */
! struct cfg_hooks *cfg_hooks;
  
  /* Initialization of functions specific to the rtl IR.  */
  void
--- 26,36 ----
  #include "tree.h"
  #include "rtl.h"
  #include "basic-block.h"
! #include "timevar.h"
! #include "toplev.h"
  
  /* A pointer to one of the hooks containers.  */
! static struct cfg_hooks *cfg_hooks;
  
  /* Initialization of functions specific to the rtl IR.  */
  void
*************** void
*** 45,48 ****
--- 44,576 ----
  cfg_layout_rtl_register_cfg_hooks (void)
  {
    cfg_hooks = &cfg_layout_rtl_cfg_hooks;
+ }
+ 
+ /* Verify the CFG consistency.
+ 
+    Currently it does following: checks edge and basic block list correctness
+    and calls into IL dependent checking then.  */
+ 
+ void
+ verify_flow_info (void)
+ {
+   size_t *edge_checksum;
+   int num_bb_notes, err = 0;
+   basic_block bb, last_bb_seen;
+   basic_block *last_visited;
+ 
+   timevar_push (TV_CFG_VERIFY);
+   last_visited = xcalloc (last_basic_block + 2, sizeof (basic_block));
+   edge_checksum = xcalloc (last_basic_block + 2, sizeof (size_t));
+ 
+   /* Check bb chain & numbers.  */
+   last_bb_seen = ENTRY_BLOCK_PTR;
+   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb, NULL, next_bb)
+     {
+       if (bb != EXIT_BLOCK_PTR
+ 	  && bb != BASIC_BLOCK (bb->index))
+ 	{
+ 	  error ("bb %d on wrong place", bb->index);
+ 	  err = 1;
+ 	}
+ 
+       if (bb->prev_bb != last_bb_seen)
+ 	{
+ 	  error ("prev_bb of %d should be %d, not %d",
+ 		 bb->index, last_bb_seen->index, bb->prev_bb->index);
+ 	  err = 1;
+ 	}
+ 
+       last_bb_seen = bb;
+     }
+ 
+   /* Now check the basic blocks (boundaries etc.) */
+   FOR_EACH_BB_REVERSE (bb)
+     {
+       int n_fallthru = 0;
+       edge e;
+ 
+       if (bb->count < 0)
+ 	{
+ 	  error ("verify_flow_info: Wrong count of block %i %i",
+ 	         bb->index, (int)bb->count);
+ 	  err = 1;
+ 	}
+       if (bb->frequency < 0)
+ 	{
+ 	  error ("verify_flow_info: Wrong frequency of block %i %i",
+ 	         bb->index, bb->frequency);
+ 	  err = 1;
+ 	}
+       for (e = bb->succ; e; e = e->succ_next)
+ 	{
+ 	  if (last_visited [e->dest->index + 2] == bb)
+ 	    {
+ 	      error ("verify_flow_info: Duplicate edge %i->%i",
+ 		     e->src->index, e->dest->index);
+ 	      err = 1;
+ 	    }
+ 	  if (e->probability < 0 || e->probability > REG_BR_PROB_BASE)
+ 	    {
+ 	      error ("verify_flow_info: Wrong probability of edge %i->%i %i",
+ 		     e->src->index, e->dest->index, e->probability);
+ 	      err = 1;
+ 	    }
+ 	  if (e->count < 0)
+ 	    {
+ 	      error ("verify_flow_info: Wrong count of edge %i->%i %i",
+ 		     e->src->index, e->dest->index, (int)e->count);
+ 	      err = 1;
+ 	    }
+ 
+ 	  last_visited [e->dest->index + 2] = bb;
+ 
+ 	  if (e->flags & EDGE_FALLTHRU)
+ 	    n_fallthru++;
+ 
+ 	  if (e->src != bb)
+ 	    {
+ 	      error ("verify_flow_info: Basic block %d succ edge is corrupted",
+ 		     bb->index);
+ 	      fprintf (stderr, "Predecessor: ");
+ 	      dump_edge_info (stderr, e, 0);
+ 	      fprintf (stderr, "\nSuccessor: ");
+ 	      dump_edge_info (stderr, e, 1);
+ 	      fprintf (stderr, "\n");
+ 	      err = 1;
+ 	    }
+ 
+ 	  edge_checksum[e->dest->index + 2] += (size_t) e;
+ 	}
+       if (n_fallthru > 1)
+ 	{
+ 	  error ("Wrong amount of branch edges after unconditional jump %i", bb->index);
+ 	  err = 1;
+ 	}
+ 
+       for (e = bb->pred; e; e = e->pred_next)
+ 	{
+ 	  if (e->dest != bb)
+ 	    {
+ 	      error ("basic block %d pred edge is corrupted", bb->index);
+ 	      fputs ("Predecessor: ", stderr);
+ 	      dump_edge_info (stderr, e, 0);
+ 	      fputs ("\nSuccessor: ", stderr);
+ 	      dump_edge_info (stderr, e, 1);
+ 	      fputc ('\n', stderr);
+ 	      err = 1;
+ 	    }
+ 	  edge_checksum[e->dest->index + 2] -= (size_t) e;
+ 	}
+     }
+ 
+   /* Complete edge checksumming for ENTRY and EXIT.  */
+   {
+     edge e;
+ 
+     for (e = ENTRY_BLOCK_PTR->succ; e ; e = e->succ_next)
+       edge_checksum[e->dest->index + 2] += (size_t) e;
+ 
+     for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
+       edge_checksum[e->dest->index + 2] -= (size_t) e;
+   }
+ 
+   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+     if (edge_checksum[bb->index + 2])
+       {
+ 	error ("basic block %i edge lists are corrupted", bb->index);
+ 	err = 1;
+       }
+ 
+   num_bb_notes = 0;
+   last_bb_seen = ENTRY_BLOCK_PTR;
+ 
+   /* Clean up.  */
+   free (last_visited);
+   free (edge_checksum);
+ 
+   if (cfg_hooks->verify_flow_info)
+     err |= cfg_hooks->verify_flow_info ();
+   if (err)
+     internal_error ("verify_flow_info failed");
+   timevar_pop (TV_CFG_VERIFY);
+ }
+ 
+ /* Print out one basic block.  This function takes care of the purely
+    graph related information.  The cfg hook for the active representation
+    should dump representation-specific information.  */
+ 
+ void
+ dump_bb (basic_block bb, FILE *outf, int indent)
+ {
+   edge e;
+   char *s_indent;
+  
+   s_indent = (char *) alloca ((size_t) indent + 1);
+   memset ((void *) s_indent, ' ', (size_t) indent);
+   s_indent[indent] = '\0';
+ 
+   fprintf (outf, ";;%s basic block %d, loop depth %d, count ",
+ 	   s_indent, bb->index, bb->loop_depth);
+   fprintf (outf, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) bb->count);
+   putc ('\n', outf);
+ 
+   fprintf (outf, ";;%s prev block ", s_indent);
+   if (bb->prev_bb)
+     fprintf (outf, "%d, ", bb->prev_bb->index);
+   else
+     fprintf (outf, "(nil), ");
+   fprintf (outf, "next block ");
+   if (bb->next_bb)
+     fprintf (outf, "%d", bb->next_bb->index);
+   else
+     fprintf (outf, "(nil)");
+   putc ('\n', outf);
+ 
+   fprintf (outf, ";;%s pred:      ", s_indent);
+   for (e = bb->pred; e; e = e->pred_next)
+     dump_edge_info (outf, e, 0);
+   putc ('\n', outf);
+ 
+   fprintf (outf, ";;%s succ:      ", s_indent);
+   for (e = bb->succ; e; e = e->succ_next)
+     dump_edge_info (outf, e, 1);
+   putc ('\n', outf);
+ 
+   if (cfg_hooks->dump_bb)
+     cfg_hooks->dump_bb (bb, outf, indent);
+ }
+ 
+ /* Redirect edge E to the given basic block DEST and update underlying program
+    representation.  Returns edge representing redirected branch (that may not
+    be equivalent to E in the case of duplicate edges being removed) or NULL
+    if edge is not easily redirectable for whatever reason.  */
+ 
+ bool
+ redirect_edge_and_branch (edge e, basic_block dest)
+ {
+   bool ret;
+ 
+   if (!cfg_hooks->redirect_edge_and_branch)
+     internal_error ("%s does not support redirect_edge_and_branch.",
+ 		    cfg_hooks->name);
+ 
+   ret = cfg_hooks->redirect_edge_and_branch (e, dest);
+ 
+   return ret;
+ }
+ 
+ /* Redirect the edge E to basic block DEST even if it requires creating
+    of a new basic block; then it returns the newly created basic block.
+    Aborts when redirection is impossible.  */
+ 
+ basic_block
+ redirect_edge_and_branch_force (edge e, basic_block dest)
+ {
+   basic_block ret;
+ 
+   if (!cfg_hooks->redirect_edge_and_branch_force)
+     internal_error ("%s does not support redirect_edge_and_branch_force.",
+ 		    cfg_hooks->name);
+ 
+   ret = cfg_hooks->redirect_edge_and_branch_force (e, dest);
+ 
+   return ret;
+ }
+ 
+ /* Splits basic block BB after the specified instruction I (but at least after
+    the labels).  If I is NULL, splits just after labels.  The newly created edge
+    is returned.  The new basic block is created just after the old one.  */
+ 
+ edge
+ split_block (basic_block bb, void *i)
+ {
+   basic_block new_bb;
+ 
+   if (!cfg_hooks->split_block)
+     internal_error ("%s does not support split_block.", cfg_hooks->name);
+ 
+   new_bb = cfg_hooks->split_block (bb, i);
+   if (!new_bb)
+     return NULL;
+ 
+   new_bb->count = bb->count;
+   new_bb->frequency = bb->frequency;
+   new_bb->loop_depth = bb->loop_depth;
+ 
+   if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
+     {
+       redirect_immediate_dominators (CDI_DOMINATORS, bb, new_bb);
+       set_immediate_dominator (CDI_DOMINATORS, new_bb, bb);
+     }
+ 
+   return make_edge (bb, new_bb, EDGE_FALLTHRU);
+ }
+ 
+ /* Splits block BB just after labels.  The newly created edge is returned.  */
+ 
+ edge
+ split_block_after_labels (basic_block bb)
+ {
+   return split_block (bb, NULL);
+ }
+ 
+ /* Moves block BB immediatelly after block AFTER.  Returns false if the
+    movement was impossible.  */
+ 
+ bool
+ move_block_after (basic_block bb, basic_block after)
+ {
+   bool ret;
+ 
+   if (!cfg_hooks->move_block_after)
+     internal_error ("%s does not support move_block_after.", cfg_hooks->name);
+ 
+   ret = cfg_hooks->move_block_after (bb, after);
+ 
+   return ret;
+ }
+ 
+ /* Deletes the basic block BB.  */
+ 
+ void
+ delete_basic_block (basic_block bb)
+ {
+   if (!cfg_hooks->delete_basic_block)
+     internal_error ("%s does not support delete_basic_block.", cfg_hooks->name);
+ 
+   cfg_hooks->delete_basic_block (bb);
+ 
+   /* Remove the edges into and out of this block.  Note that there may
+      indeed be edges in, if we are removing an unreachable loop.  */
+   while (bb->pred != NULL)
+     remove_edge (bb->pred);
+   while (bb->succ != NULL)
+     remove_edge (bb->succ);
+ 
+   bb->pred = NULL;
+   bb->succ = NULL;
+ 
+   if (dom_computed[CDI_DOMINATORS])
+     delete_from_dominance_info (CDI_DOMINATORS, bb);
+   if (dom_computed[CDI_POST_DOMINATORS])
+     delete_from_dominance_info (CDI_POST_DOMINATORS, bb);
+ 
+   /* Remove the basic block from the array.  */
+   expunge_block (bb);
+ }
+ 
+ /* Splits edge E and returns the newly created basic block.  */
+ 
+ basic_block
+ split_edge (edge e)
+ {
+   basic_block ret;
+   gcov_type count = e->count;
+   int freq = EDGE_FREQUENCY (e);
+ 
+   if (!cfg_hooks->split_edge)
+     internal_error ("%s does not support split_edge.", cfg_hooks->name);
+ 
+   ret = cfg_hooks->split_edge (e);
+   ret->count = count;
+   ret->frequency = freq;
+   ret->succ->probability = REG_BR_PROB_BASE;
+   ret->succ->count = count;
+ 
+   if (dom_computed[CDI_DOMINATORS])
+     set_immediate_dominator (CDI_DOMINATORS, ret, ret->pred->src);
+ 
+   if (dom_computed[CDI_DOMINATORS] >= DOM_NO_FAST_QUERY)
+     set_immediate_dominator (CDI_DOMINATORS, ret->succ->dest,
+ 			     recount_dominator (CDI_DOMINATORS,
+ 						ret->succ->dest));
+ 
+   return ret;
+ }
+ 
+ /* Creates a new basic block just after the basic block AFTER.
+    HEAD and END are the first and the last statement belonging
+    to the block.  If both are NULL, an empty block is created.  */
+ 
+ basic_block
+ create_basic_block (void *head, void *end, basic_block after)
+ {
+   basic_block ret;
+ 
+   if (!cfg_hooks->create_basic_block)
+     internal_error ("%s does not support create_basic_block.", cfg_hooks->name);
+ 
+   ret = cfg_hooks->create_basic_block (head, end, after);
+ 
+   if (dom_computed[CDI_DOMINATORS])
+     add_to_dominance_info (CDI_DOMINATORS, ret);
+   if (dom_computed[CDI_POST_DOMINATORS])
+     add_to_dominance_info (CDI_POST_DOMINATORS, ret);
+ 
+   return ret;
+ }
+ 
+ /* Creates an empty basic block just after basic block AFTER.  */
+ 
+ basic_block
+ create_empty_bb (basic_block after)
+ {
+   return create_basic_block (NULL, NULL, after);
+ }
+ 
+ /* Checks whether we may merge blocks BB1 and BB2.  */
+ 
+ bool
+ can_merge_blocks_p (basic_block bb1, basic_block bb2)
+ {
+   bool ret;
+ 
+   if (!cfg_hooks->can_merge_blocks_p)
+     internal_error ("%s does not support can_merge_blocks_p.", cfg_hooks->name);
+ 
+   ret = cfg_hooks->can_merge_blocks_p (bb1, bb2);
+ 
+   return ret;
+ }
+ 
+ /* Merges basic block B into basic block A.  */
+ 
+ void
+ merge_blocks (basic_block a, basic_block b)
+ {
+   edge e;
+ 
+   if (!cfg_hooks->merge_blocks)
+     internal_error ("%s does not support merge_blocks.", cfg_hooks->name);
+ 
+   cfg_hooks->merge_blocks (a, b);
+ 
+   /* Normally there should only be one successor of A and that is B, but
+      partway though the merge of blocks for conditional_execution we'll
+      be merging a TEST block with THEN and ELSE successors.  Free the
+      whole lot of them and hope the caller knows what they're doing.  */
+   while (a->succ)
+     remove_edge (a->succ);
+ 
+   /* Adjust the edges out of B for the new owner.  */
+   for (e = b->succ; e; e = e->succ_next)
+     e->src = a;
+   a->succ = b->succ;
+   a->flags |= b->flags;
+ 
+   /* B hasn't quite yet ceased to exist.  Attempt to prevent mishap.  */
+   b->pred = b->succ = NULL;
+   a->global_live_at_end = b->global_live_at_end;
+ 
+   if (dom_computed[CDI_DOMINATORS])
+     redirect_immediate_dominators (CDI_DOMINATORS, b, a);
+ 
+   if (dom_computed[CDI_DOMINATORS])
+     delete_from_dominance_info (CDI_DOMINATORS, b);
+   if (dom_computed[CDI_POST_DOMINATORS])
+     delete_from_dominance_info (CDI_POST_DOMINATORS, b);
+ 
+   expunge_block (b);
+ }
+ 
+ /* Split BB into entry part and the rest (the rest is the newly created block).
+    Redirect those edges for that REDIRECT_EDGE_P returns true to the entry
+    part.  Returns the edge connecting the entry part to the rest.  */
+ 
+ edge
+ make_forwarder_block (basic_block bb, bool (*redirect_edge_p) (edge),
+ 		      void (*new_bb_cbk) (basic_block))
+ {
+   edge e, next_e, fallthru;
+   basic_block dummy, jump;
+ 
+   if (!cfg_hooks->make_forwarder_block)
+     internal_error ("%s does not support make_forwarder_block.",
+ 		    cfg_hooks->name);
+ 
+   fallthru = split_block_after_labels (bb);
+   dummy = fallthru->src;
+   bb = fallthru->dest;
+ 
+   /* Redirect back edges we want to keep.  */
+   for (e = dummy->pred; e; e = next_e)
+     {
+       next_e = e->pred_next;
+       if (redirect_edge_p (e))
+ 	continue;
+ 
+       dummy->frequency -= EDGE_FREQUENCY (e);
+       dummy->count -= e->count;
+       if (dummy->frequency < 0)
+ 	dummy->frequency = 0;
+       if (dummy->count < 0)
+ 	dummy->count = 0;
+ 
+       jump = redirect_edge_and_branch_force (e, bb);
+       if (jump)
+ 	new_bb_cbk (jump);
+     }
+ 
+   if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
+     {
+       basic_block doms_to_fix[2];
+ 
+       doms_to_fix[0] = dummy;
+       doms_to_fix[1] = bb;
+       iterate_fix_dominators (CDI_DOMINATORS, doms_to_fix, 2);
+     }
+ 
+   cfg_hooks->make_forwarder_block (fallthru);
+ 
+   return fallthru;
+ }
+ 
+ void
+ tidy_fallthru_edge (edge e)
+ {
+   if (cfg_hooks->tidy_fallthru_edge)
+     cfg_hooks->tidy_fallthru_edge (e);
+ }
+ 
+ /* Fix up edges that now fall through, or rather should now fall through
+    but previously required a jump around now deleted blocks.  Simplify
+    the search by only examining blocks numerically adjacent, since this
+    is how find_basic_blocks created them.  */
+ 
+ void
+ tidy_fallthru_edges (void)
+ {
+   basic_block b, c;
+ 
+   if (!cfg_hooks->tidy_fallthru_edge)
+     return;
+ 
+   if (ENTRY_BLOCK_PTR->next_bb == EXIT_BLOCK_PTR)
+     return;
+ 
+   FOR_BB_BETWEEN (b, ENTRY_BLOCK_PTR->next_bb, EXIT_BLOCK_PTR->prev_bb, next_bb)
+     {
+       edge s;
+ 
+       c = b->next_bb;
+ 
+       /* We care about simple conditional or unconditional jumps with
+ 	 a single successor.
+ 
+ 	 If we had a conditional branch to the next instruction when
+ 	 find_basic_blocks was called, then there will only be one
+ 	 out edge for the block which ended with the conditional
+ 	 branch (since we do not create duplicate edges).
+ 
+ 	 Furthermore, the edge will be marked as a fallthru because we
+ 	 merge the flags for the duplicate edges.  So we do not want to
+ 	 check that the edge is not a FALLTHRU edge.  */
+ 
+       if ((s = b->succ) != NULL
+ 	  && ! (s->flags & EDGE_COMPLEX)
+ 	  && s->succ_next == NULL
+ 	  && s->dest == c)
+ 	tidy_fallthru_edge (s);
+     }
  }
Index: cfghooks.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfghooks.h,v
retrieving revision 1.8
diff -c -3 -p -r1.8 cfghooks.h
*** cfghooks.h	21 Dec 2003 14:08:32 -0000	1.8
--- cfghooks.h	28 Jan 2004 10:20:44 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 24,33 ****
  
  struct cfg_hooks
  {
!   /* Debugging.  Do not use macros to hook these so they can be called from
!      debugger!  */
!   int (*cfgh_verify_flow_info) (void);
!   void (*dump_bb) (basic_block, FILE *);
  
    /* Basic CFG manipulation.  */
  
--- 24,35 ----
  
  struct cfg_hooks
  {
!   /* Name of the corresponding ir.  */
!   const char *name;
! 
!   /* Debugging.  */
!   int (*verify_flow_info) (void);
!   void (*dump_bb) (basic_block, FILE *, int);
  
    /* Basic CFG manipulation.  */
  
*************** struct cfg_hooks
*** 44,54 ****
       on abnormal edge.  */
    basic_block (*redirect_edge_and_branch_force) (edge, basic_block);
  
!   /* Remove given basic block and all edges possibly pointing into it.  */
!   void (*delete_block) (basic_block);
  
!   /* Split basic block B after specified instruction I.  */
!   edge (*split_block) (basic_block b, void * i);
  
    /* Return true when blocks A and B can be merged into single basic block.  */
    bool (*can_merge_blocks_p) (basic_block a, basic_block b);
--- 46,60 ----
       on abnormal edge.  */
    basic_block (*redirect_edge_and_branch_force) (edge, basic_block);
  
!   /* Remove statements corresponding to a given basic block.  */
!   void (*delete_basic_block) (basic_block);
! 
!   /* Creates a new basic block just after basic block B by splitting
!      everything after specified instruction I.  */
!   basic_block (*split_block) (basic_block b, void * i);
  
!   /* Move block B immediately after block A.  */
!   bool (*move_block_after) (basic_block b, basic_block a);
  
    /* Return true when blocks A and B can be merged into single basic block.  */
    bool (*can_merge_blocks_p) (basic_block a, basic_block b);
*************** struct cfg_hooks
*** 58,80 ****
  
    /* Higher level functions representable by primitive operations above if
       we didn't have some oddities in RTL and Tree representations.  */
!   basic_block (*cfgh_split_edge) (edge);
  };
  
! #define redirect_edge_and_branch(e,b)        cfg_hooks->redirect_edge_and_branch (e,b)
! #define redirect_edge_and_branch_force(e,b)  cfg_hooks->redirect_edge_and_branch_force (e,b)
! #define split_block(e,i)                     cfg_hooks->split_block (e,i)
! #define delete_block(b)			     cfg_hooks->delete_block (b)
! #define split_edge(e)                        cfg_hooks->cfgh_split_edge (e)
! #define create_basic_block(h,e,a)            cfg_hooks->create_basic_block (h,e,a)
! #define can_merge_blocks_p(a,b)		     cfg_hooks->can_merge_blocks_p (a,b)
! #define merge_blocks(a,b)		     cfg_hooks->merge_blocks (a,b)
  
  /* Hooks containers.  */
  extern struct cfg_hooks rtl_cfg_hooks;
! 
! /* A pointer to one of the hooks containers.  */
! extern struct cfg_hooks *cfg_hooks;
  
  /* Declarations.  */
  extern void rtl_register_cfg_hooks (void);
--- 64,97 ----
  
    /* Higher level functions representable by primitive operations above if
       we didn't have some oddities in RTL and Tree representations.  */
!   basic_block (*split_edge) (edge);
!   void (*make_forwarder_block) (edge);
! 
!   /* Tries to make the edge fallthru.  */
!   void (*tidy_fallthru_edge) (edge);
  };
  
! extern void verify_flow_info (void);
! extern void dump_bb (basic_block, FILE *, int);
! extern bool redirect_edge_and_branch (edge, basic_block);
! extern basic_block redirect_edge_and_branch_force (edge, basic_block);
! extern edge split_block (basic_block, void *);
! extern edge split_block_after_labels (basic_block);
! extern bool move_block_after (basic_block, basic_block);
! extern void delete_basic_block (basic_block);
! extern basic_block split_edge (edge);
! extern basic_block create_basic_block (void *, void *, basic_block);
! extern basic_block create_empty_bb (basic_block);
! extern bool can_merge_blocks_p (basic_block, basic_block);
! extern void merge_blocks (basic_block, basic_block);
! extern edge make_forwarder_block (basic_block, bool (*)(edge),
! 				  void (*) (basic_block));
! extern void tidy_fallthru_edge (edge);
! extern void tidy_fallthru_edges (void);
  
  /* Hooks containers.  */
  extern struct cfg_hooks rtl_cfg_hooks;
! extern struct cfg_hooks cfg_layout_rtl_cfg_hooks;
  
  /* Declarations.  */
  extern void rtl_register_cfg_hooks (void);
Index: cfglayout.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfglayout.c,v
retrieving revision 1.50
diff -c -3 -p -r1.50 cfglayout.c
*** cfglayout.c	30 Dec 2003 10:40:50 -0000	1.50
--- cfglayout.c	28 Jan 2004 10:20:44 -0000
*************** copy_bbs (basic_block *bbs, unsigned n, 
*** 1268,1274 ****
        bb->rbi->duplicated = 1;
        /* Add to loop.  */
        add_bb_to_loop (new_bb, bb->loop_father->copy);
-       add_to_dominance_info (CDI_DOMINATORS, new_bb);
        /* Possibly set header.  */
        if (bb->loop_father->header == bb && bb->loop_father != base)
  	new_bb->loop_father->header = new_bb;
--- 1268,1273 ----
Index: cfgloop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgloop.c,v
retrieving revision 1.29
diff -c -3 -p -r1.29 cfgloop.c
*** cfgloop.c	2 Jan 2004 22:44:27 -0000	1.29
--- cfgloop.c	28 Jan 2004 10:20:44 -0000
*************** Software Foundation, 59 Temple Place - S
*** 33,38 ****
--- 33,41 ----
     considered to belong to inner loop with same header.  */
  #define HEAVY_EDGE_RATIO 8
  
+ #define HEADER_BLOCK(B) (* (int *) (B)->aux)
+ #define LATCH_EDGE(E) (*(int *) (E)->aux)
+ 
  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 basic_block flow_loop_pre_header_
*** 42,51 ****
  static int flow_loop_level_compute (struct loop *);
  static int flow_loops_level_compute (struct loops *);
  static void establish_preds (struct loop *);
- static basic_block make_forwarder_block (basic_block, int, int, edge, int);
  static void canonicalize_loop_headers (void);
  static bool glb_enum_p (basic_block, void *);
- static void redirect_edge_with_latch_update (edge, basic_block);
  
  /* Dump loop related CFG information.  */
  
--- 45,52 ----
*************** flow_loop_scan (struct loop *loop, int f
*** 547,624 ****
    return 1;
  }
  
! #define HEADER_BLOCK(B) (* (int *) (B)->aux)
! #define LATCH_EDGE(E) (*(int *) (E)->aux)
  
- /* Redirect edge and update latch and header info.  */
  static void
! redirect_edge_with_latch_update (edge e, basic_block to)
  {
!   basic_block jump;
! 
!   jump = redirect_edge_and_branch_force (e, to);
!   if (jump)
!     {
!       alloc_aux_for_block (jump, sizeof (int));
!       HEADER_BLOCK (jump) = 0;
!       alloc_aux_for_edge (jump->pred, sizeof (int));
!       LATCH_EDGE (jump->succ) = LATCH_EDGE (e);
!       LATCH_EDGE (jump->pred) = 0;
!     }
  }
  
! /* Split BB into entry part and rest; if REDIRECT_LATCH, redirect edges
!    marked as latch into entry part, analogically for REDIRECT_NONLATCH.
!    In both of these cases, ignore edge EXCEPT.  If CONN_LATCH, set edge
!    between created entry part and BB as latch one.  Return created entry
!    part.  */
  
! static basic_block
! make_forwarder_block (basic_block bb, int redirect_latch, int redirect_nonlatch, edge except, int conn_latch)
  {
!   edge e, next_e, fallthru;
!   basic_block dummy;
!   rtx insn;
! 
!   insn = PREV_INSN (first_insn_after_basic_block_note (bb));
! 
!   /* For empty block split_block will return NULL.  */
!   if (BB_END (bb) == insn)
!     emit_note_after (NOTE_INSN_DELETED, insn);
! 
!   fallthru = split_block (bb, insn);
!   dummy = fallthru->src;
!   bb = fallthru->dest;
! 
!   bb->aux = xmalloc (sizeof (int));
!   HEADER_BLOCK (dummy) = 0;
!   HEADER_BLOCK (bb) = 1;
! 
!   /* Redirect back edges we want to keep.  */
!   for (e = dummy->pred; e; e = next_e)
!     {
!       next_e = e->pred_next;
!       if (e == except
! 	  || !((redirect_latch && LATCH_EDGE (e))
! 	       || (redirect_nonlatch && !LATCH_EDGE (e))))
! 	{
! 	  dummy->frequency -= EDGE_FREQUENCY (e);
! 	  dummy->count -= e->count;
! 	  if (dummy->frequency < 0)
! 	    dummy->frequency = 0;
! 	  if (dummy->count < 0)
! 	    dummy->count = 0;
! 	  redirect_edge_with_latch_update (e, bb);
! 	}
!     }
  
!   alloc_aux_for_edge (fallthru, sizeof (int));
!   LATCH_EDGE (fallthru) = conn_latch;
  
!   return dummy;
  }
  
  /* Takes care of merging natural loops with shared headers.  */
  static void
  canonicalize_loop_headers (void)
  {
--- 548,588 ----
    return 1;
  }
  
! /* A callback to update latch and header info for basic block JUMP created
!    by redirecting an edge.  */
  
  static void
! update_latch_info (basic_block jump)
  {
!   alloc_aux_for_block (jump, sizeof (int));
!   HEADER_BLOCK (jump) = 0;
!   alloc_aux_for_edge (jump->pred, sizeof (int));
!   LATCH_EDGE (jump->pred) = 0;
  }
  
! /* A callback for make_forwarder block, to redirect all edges except for
!    MFB_KJ_EDGE to the entry part.  E is the edge for that we should decide
!    whether to redirect it.  */
  
! static edge mfb_kj_edge;
! static bool
! mfb_keep_just (edge e)
  {
!   return e != mfb_kj_edge;
! }
  
! /* A callback for make_forwarder block, to redirect the latch edges into an
!    entry part.  E is the edge for that we should decide whether to redirect
!    it.  */
  
! static bool
! mfb_keep_nonlatch (edge e)
! {
!   return LATCH_EDGE (e);
  }
  
  /* Takes care of merging natural loops with shared headers.  */
+ 
  static void
  canonicalize_loop_headers (void)
  {
*************** canonicalize_loop_headers (void)
*** 675,693 ****
  
    FOR_EACH_BB (header)
      {
-       int num_latch;
-       int want_join_latch;
        int max_freq, is_heavy;
!       edge heavy;
! 
!       if (!HEADER_BLOCK (header))
! 	continue;
! 
!       num_latch = HEADER_BLOCK (header);
  
!       want_join_latch = (num_latch > 1);
! 
!       if (!want_join_latch)
  	continue;
  
        /* Find a heavy edge.  */
--- 639,648 ----
  
    FOR_EACH_BB (header)
      {
        int max_freq, is_heavy;
!       edge heavy, tmp_edge;
  
!       if (HEADER_BLOCK (header) <= 1)
  	continue;
  
        /* Find a heavy edge.  */
*************** canonicalize_loop_headers (void)
*** 713,725 ****
  
        if (is_heavy)
  	{
! 	  basic_block new_header =
! 	    make_forwarder_block (header, true, true, heavy, 0);
! 	  if (num_latch > 2)
! 	    make_forwarder_block (new_header, true, false, NULL, 1);
  	}
-       else
- 	make_forwarder_block (header, true, false, NULL, 1);
      }
  
    free_aux_for_blocks ();
--- 668,695 ----
  
        if (is_heavy)
  	{
! 	  /* Split out the heavy edge, and create inner loop for it.  */
! 	  mfb_kj_edge = heavy;
! 	  tmp_edge = make_forwarder_block (header, mfb_keep_just,
! 					   update_latch_info);
! 	  alloc_aux_for_block (tmp_edge->dest, sizeof (int));
! 	  HEADER_BLOCK (tmp_edge->dest) = 1;
! 	  alloc_aux_for_edge (tmp_edge, sizeof (int));
! 	  LATCH_EDGE (tmp_edge) = 0;
! 	  HEADER_BLOCK (header)--;
! 	}
! 
!       if (HEADER_BLOCK (header) > 1)
! 	{
! 	  /* Create a new latch block.  */
! 	  tmp_edge = make_forwarder_block (header, mfb_keep_nonlatch,
! 					   update_latch_info);
! 	  alloc_aux_for_block (tmp_edge->dest, sizeof (int));
! 	  HEADER_BLOCK (tmp_edge->src) = 0;
! 	  HEADER_BLOCK (tmp_edge->dest) = 1;
! 	  alloc_aux_for_edge (tmp_edge, sizeof (int));
! 	  LATCH_EDGE (tmp_edge) = 1;
  	}
      }
  
    free_aux_for_blocks ();
Index: cfgloopanal.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgloopanal.c,v
retrieving revision 1.18
diff -c -3 -p -r1.18 cfgloopanal.c
*** cfgloopanal.c	30 Dec 2003 10:40:51 -0000	1.18
--- cfgloopanal.c	28 Jan 2004 10:20:44 -0000
*************** simple_loop_p (struct loop *loop, struct
*** 1111,1131 ****
    return any;
  }
  
  /* Marks blocks and edges that are part of non-recognized loops; i.e. we
     throw away all latch edges and mark blocks inside any remaining cycle.
     Everything is a bit complicated due to fact we do not want to do this
     for parts of cycles that only "pass" through some loop -- i.e. for
     each cycle, we want to mark blocks that belong directly to innermost
!    loop containing the whole cycle.  */
  void
  mark_irreducible_loops (struct loops *loops)
  {
-   int *dfs_in, *closed, *mr, *mri, *n_edges, *stack;
-   unsigned i;
-   edge **edges, e;
-   edge *estack;
    basic_block act;
!   int stack_top, tick, depth;
    struct loop *cloop;
  
    /* Reset the flags.  */
--- 1111,1340 ----
    return any;
  }
  
+ /* Structure representing edge of a graph.  */
+ 
+ struct edge
+ {
+   int src, dest;	/* Source and destination.  */
+   struct edge *pred_next, *succ_next;
+ 			/* Next edge in predecessor and successor lists.  */
+   void *data;		/* Data attached to the edge.  */
+ };
+ 
+ /* Structure representing vertex of a graph.  */
+ 
+ struct vertex
+ {
+   struct edge *pred, *succ;
+ 			/* Lists of predecessors and successors.  */
+   int component;	/* Number of dfs restarts before reaching the
+ 			   vertex.  */
+   int post;		/* Postorder number.  */
+ };
+ 
+ /* Structure representing a graph.  */
+ 
+ struct graph
+ {
+   int n_vertices;	/* Number of vertices.  */
+   struct vertex *vertices;
+ 			/* The vertices.  */
+ };
+ 
+ /* Dumps graph G into F.  */
+ 
+ extern void dump_graph (FILE *, struct graph *);
+ void dump_graph (FILE *f, struct graph *g)
+ {
+   int i;
+   struct edge *e;
+ 
+   for (i = 0; i < g->n_vertices; i++)
+     {
+       if (!g->vertices[i].pred
+ 	  && !g->vertices[i].succ)
+ 	continue;
+ 
+       fprintf (f, "%d (%d)\t<-", i, g->vertices[i].component);
+       for (e = g->vertices[i].pred; e; e = e->pred_next)
+ 	fprintf (f, " %d", e->src);
+       fprintf (f, "\n");
+ 
+       fprintf (f, "\t->");
+       for (e = g->vertices[i].succ; e; e = e->succ_next)
+ 	fprintf (f, " %d", e->dest);
+       fprintf (f, "\n");
+     }
+ }
+ 
+ /* Creates a new graph with N_VERTICES vertices.  */
+ 
+ static struct graph *
+ new_graph (int n_vertices)
+ {
+   struct graph *g = xmalloc (sizeof (struct graph));
+ 
+   g->n_vertices = n_vertices;
+   g->vertices = xcalloc (n_vertices, sizeof (struct vertex));
+ 
+   return g;
+ }
+ 
+ /* Adds an edge from F to T to graph G, with DATA attached.  */
+ 
+ static void
+ add_edge (struct graph *g, int f, int t, void *data)
+ {
+   struct edge *e = xmalloc (sizeof (struct edge));
+ 
+   e->src = f;
+   e->dest = t;
+   e->data = data;
+ 
+   e->pred_next = g->vertices[t].pred;
+   g->vertices[t].pred = e;
+ 
+   e->succ_next = g->vertices[f].succ;
+   g->vertices[f].succ = e;
+ }
+ 
+ /* Runs dfs search over vertices of G, from NQ vertices in queue QS.
+    The vertices in postorder are stored into QT.  If FORWARD is false,
+    backward dfs is run.  */
+ 
+ static void
+ dfs (struct graph *g, int *qs, int nq, int *qt, bool forward)
+ {
+   int i, tick = 0, v, comp = 0, top;
+   struct edge *e;
+   struct edge **stack = xmalloc (sizeof (struct edge *) * g->n_vertices);
+ 
+   for (i = 0; i < g->n_vertices; i++)
+     {
+       g->vertices[i].component = -1;
+       g->vertices[i].post = -1;
+     }
+ 
+ #define FST_EDGE(V) (forward ? g->vertices[(V)].succ : g->vertices[(V)].pred)
+ #define NEXT_EDGE(E) (forward ? (E)->succ_next : (E)->pred_next)
+ #define EDGE_SRC(E) (forward ? (E)->src : (E)->dest)
+ #define EDGE_DEST(E) (forward ? (E)->dest : (E)->src)
+ 
+   for (i = 0; i < nq; i++)
+     {
+       v = qs[i];
+       if (g->vertices[v].post != -1)
+ 	continue;
+ 
+       g->vertices[v].component = comp++;
+       e = FST_EDGE (v);
+       top = 0;
+ 
+       while (1)
+ 	{
+ 	  while (e && g->vertices[EDGE_DEST (e)].component != -1)
+ 	    e = NEXT_EDGE (e);
+ 
+ 	  if (!e)
+ 	    {
+ 	      if (qt)
+ 		qt[tick] = v;
+  	      g->vertices[v].post = tick++;
+ 
+ 	      if (!top)
+ 		break;
+ 
+ 	      e = stack[--top];
+ 	      v = EDGE_SRC (e);
+ 	      e = NEXT_EDGE (e);
+ 	      continue;
+ 	    }
+ 
+ 	  stack[top++] = e;
+ 	  v = EDGE_DEST (e);
+ 	  e = FST_EDGE (v);
+ 	  g->vertices[v].component = comp - 1;
+ 	}
+     }
+ 
+   free (stack);
+ }
+ 
+ /* Marks the edge E in graph G irreducible if it connects two vertices in the
+    same scc.  */
+ 
+ static void
+ check_irred (struct graph *g, struct edge *e)
+ {
+   edge real = e->data;
+ 
+   /* All edges should lead from a component with higher number to the
+      one with lower one.  */
+   if (g->vertices[e->src].component < g->vertices[e->dest].component)
+     abort ();
+ 
+   if (g->vertices[e->src].component != g->vertices[e->dest].component)
+     return;
+ 
+   real->flags |= EDGE_IRREDUCIBLE_LOOP;
+   if (flow_bb_inside_loop_p (real->src->loop_father, real->dest))
+     real->src->flags |= BB_IRREDUCIBLE_LOOP;
+ }
+ 
+ /* Runs CALLBACK for all edges in G.  */
+ 
+ static void
+ for_each_edge (struct graph *g,
+ 	       void (callback) (struct graph *, struct edge *))
+ {
+   struct edge *e;
+   int i;
+ 
+   for (i = 0; i < g->n_vertices; i++)
+     for (e = g->vertices[i].succ; e; e = e->succ_next)
+       callback (g, e);
+ }
+ 
+ /* Releases the memory occupied by G.  */
+ 
+ static void
+ free_graph (struct graph *g)
+ {
+   struct edge *e, *n;
+   int i;
+ 
+   for (i = 0; i < g->n_vertices; i++)
+     for (e = g->vertices[i].succ; e; e = n)
+       {
+ 	n = e->succ_next;
+ 	free (e);
+       }
+   free (g->vertices);
+   free (g);
+ }
+ 
  /* Marks blocks and edges that are part of non-recognized loops; i.e. we
     throw away all latch edges and mark blocks inside any remaining cycle.
     Everything is a bit complicated due to fact we do not want to do this
     for parts of cycles that only "pass" through some loop -- i.e. for
     each cycle, we want to mark blocks that belong directly to innermost
!    loop containing the whole cycle.
!    
!    LOOPS is the loop tree.  */
! 
! #define LOOP_REPR(LOOP) ((LOOP)->num + last_basic_block)
! #define BB_REPR(BB) ((BB)->index + 1)
! 
  void
  mark_irreducible_loops (struct loops *loops)
  {
    basic_block act;
!   edge e;
!   int i, src, dest;
!   struct graph *g;
!   int *queue1 = xmalloc ((last_basic_block + loops->num) * sizeof (int));
!   int *queue2 = xmalloc ((last_basic_block + loops->num) * sizeof (int));
!   int nq, depth;
    struct loop *cloop;
  
    /* Reset the flags.  */
*************** mark_irreducible_loops (struct loops *lo
*** 1136,1311 ****
  	e->flags &= ~EDGE_IRREDUCIBLE_LOOP;
      }
  
-   /* The first last_basic_block + 1 entries are for real blocks (including
-      entry); then we have loops->num - 1 fake blocks for loops to that we
-      assign edges leading from loops (fake loop 0 is not interesting).  */
-   dfs_in = xmalloc ((last_basic_block + loops->num) * sizeof (int));
-   closed = xmalloc ((last_basic_block + loops->num) * sizeof (int));
-   mr = xmalloc ((last_basic_block + loops->num) * sizeof (int));
-   mri = xmalloc ((last_basic_block + loops->num) * sizeof (int));
-   n_edges = xmalloc ((last_basic_block + loops->num) * sizeof (int));
-   edges = xmalloc ((last_basic_block + loops->num) * sizeof (edge *));
-   stack = xmalloc ((n_basic_blocks + loops->num) * sizeof (int));
-   estack = xmalloc ((n_basic_blocks + loops->num) * sizeof (edge));
- 
    /* Create the edge lists.  */
!   for (i = 0; i < last_basic_block + loops->num; i++)
!     n_edges[i] = 0;
    FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
      for (e = act->succ; e; e = e->succ_next)
        {
          /* Ignore edges to exit.  */
          if (e->dest == EXIT_BLOCK_PTR)
  	  continue;
  	/* And latch edges.  */
  	if (e->dest->loop_father->header == e->dest
  	    && e->dest->loop_father->latch == act)
  	  continue;
  	/* Edges inside a single loop should be left where they are.  Edges
  	   to subloop headers should lead to representative of the subloop,
! 	   but from the same place.  */
! 	if (act->loop_father == e->dest->loop_father
! 	    || act->loop_father == e->dest->loop_father->outer)
! 	  {
! 	    n_edges[act->index + 1]++;
! 	    continue;
! 	  }
! 	/* Edges exiting loops remain.  They should lead from representative
  	   of the son of nearest common ancestor of the loops in that
  	   act lays.  */
- 	depth = find_common_loop (act->loop_father, e->dest->loop_father)->depth + 1;
- 	if (depth == act->loop_father->depth)
- 	  cloop = act->loop_father;
- 	else
- 	  cloop = act->loop_father->pred[depth];
- 	n_edges[cloop->num + last_basic_block]++;
-       }
  
!   for (i = 0; i < last_basic_block + loops->num; i++)
!     {
!       edges[i] = xmalloc (n_edges[i] * sizeof (edge));
!       n_edges[i] = 0;
!     }
  
!   FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
!     for (e = act->succ; e; e = e->succ_next)
!       {
!         if (e->dest == EXIT_BLOCK_PTR)
! 	  continue;
! 	if (e->dest->loop_father->header == e->dest
! 	    && e->dest->loop_father->latch == act)
! 	  continue;
! 	if (act->loop_father == e->dest->loop_father
! 	    || act->loop_father == e->dest->loop_father->outer)
  	  {
! 	    edges[act->index + 1][n_edges[act->index + 1]++] = e;
! 	    continue;
! 	  }
! 	depth = find_common_loop (act->loop_father, e->dest->loop_father)->depth + 1;
! 	if (depth == act->loop_father->depth)
! 	  cloop = act->loop_father;
! 	else
! 	  cloop = act->loop_father->pred[depth];
! 	i = cloop->num + last_basic_block;
! 	edges[i][n_edges[i]++] = e;
!       }
  
!   /* Compute dfs numbering, starting from loop headers, and mark found
!      loops.  */
!   tick = 0;
!   for (i = 0; i < last_basic_block + loops->num; i++)
!     {
!       dfs_in[i] = -1;
!       closed[i] = 0;
!       mr[i] = last_basic_block + loops->num;
!       mri[i] = -1;
!     }
  
!   stack_top = 0;
!   for (i = 0; i < loops->num; i++)
!     if (loops->parray[i])
!       {
! 	stack[stack_top] = loops->parray[i]->header->index + 1;
! 	estack[stack_top] = NULL;
! 	stack_top++;
        }
  
!   while (stack_top)
      {
!       int idx, sidx;
! 
!       idx = stack[stack_top - 1];
!       if (dfs_in[idx] < 0)
! 	dfs_in[idx] = tick++;
! 
!       while (n_edges[idx])
! 	{
! 	  e = edges[idx][--n_edges[idx]];
! 	  sidx = e->dest->loop_father->header == e->dest
! 	           ? e->dest->loop_father->num + last_basic_block
! 	           : e->dest->index + 1;
!           if (closed[sidx])
! 	    {
! 	      if (mri[sidx] != -1 && !closed[mri[sidx]])
! 		{
! 		  if (mr[sidx] < mr[idx])
! 		    {
! 		      mr[idx] = mr[sidx];
! 		      mri[idx] = mri[sidx];
! 		    }
! 
! 		  if (mr[sidx] <= dfs_in[idx])
! 		    e->flags |= EDGE_IRREDUCIBLE_LOOP;
! 		}
! 	      continue;
! 	    }
! 	  if (dfs_in[sidx] < 0)
! 	    {
! 	      stack[stack_top] = sidx;
! 	      estack[stack_top] = e;
! 	      stack_top++;
! 	      goto next;
! 	    }
! 	  if (dfs_in[sidx] < mr[idx])
! 	    {
! 	      mr[idx] = dfs_in[sidx];
! 	      mri[idx] = sidx;
! 	    }
! 	  e->flags |= EDGE_IRREDUCIBLE_LOOP;
! 	}
! 
!       /* Return back.  */
!       closed[idx] = 1;
!       e = estack[stack_top - 1];
!       stack_top--;
!       if (e)
!         {
! 	  /* Propagate information back.  */
! 	  sidx = stack[stack_top - 1];
! 	  if (mr[sidx] > mr[idx])
! 	    {
! 	      mr[sidx] = mr[idx];
! 	      mri[sidx] = mri[idx];
! 	    }
! 	  if (mr[idx] <= dfs_in[sidx])
! 	    e->flags |= EDGE_IRREDUCIBLE_LOOP;
! 	}
!       /* Mark the block if relevant.  */
!       if (idx && idx <= last_basic_block && mr[idx] <= dfs_in[idx])
!         BASIC_BLOCK (idx - 1)->flags |= BB_IRREDUCIBLE_LOOP;
! next:;
      }
  
-   free (stack);
-   free (estack);
-   free (dfs_in);
-   free (closed);
-   free (mr);
-   free (mri);
-   for (i = 0; i < last_basic_block + loops->num; i++)
-     free (edges[i]);
-   free (edges);
-   free (n_edges);
    loops->state |= LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS;
  }
  
--- 1345,1418 ----
  	e->flags &= ~EDGE_IRREDUCIBLE_LOOP;
      }
  
    /* Create the edge lists.  */
!   g = new_graph (last_basic_block + loops->num);
! 
    FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
      for (e = act->succ; e; e = e->succ_next)
        {
          /* Ignore edges to exit.  */
          if (e->dest == EXIT_BLOCK_PTR)
  	  continue;
+ 
  	/* And latch edges.  */
  	if (e->dest->loop_father->header == e->dest
  	    && e->dest->loop_father->latch == act)
  	  continue;
+ 
  	/* Edges inside a single loop should be left where they are.  Edges
  	   to subloop headers should lead to representative of the subloop,
! 	   but from the same place.
! 
! 	   Edges exiting loops should lead from representative
  	   of the son of nearest common ancestor of the loops in that
  	   act lays.  */
  
! 	src = BB_REPR (act);
! 	dest = BB_REPR (e->dest);
  
! 	if (e->dest->loop_father->header == e->dest)
! 	  dest = LOOP_REPR (e->dest->loop_father);
! 
! 	if (!flow_bb_inside_loop_p (act->loop_father, e->dest))
  	  {
! 	    depth = find_common_loop (act->loop_father,
! 				      e->dest->loop_father)->depth + 1;
! 	    if (depth == act->loop_father->depth)
! 	      cloop = act->loop_father;
! 	    else
! 	      cloop = act->loop_father->pred[depth];
  
! 	    src = LOOP_REPR (cloop);
! 	  }
  
! 	add_edge (g, src, dest, e);
        }
  
!   /* Find the strongly connected components.  Use the algorithm of Tarjan --
!      first determine the postorder dfs numbering in reversed graph, then
!      run the dfs on the original graph in the order given by decreasing
!      numbers assigned by the previous pass.  */
!   nq = 0;
!   FOR_BB_BETWEEN (act, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
      {
!       queue1[nq++] = BB_REPR (act);
      }
+   for (i = 1; i < (int) loops->num; i++)
+     if (loops->parray[i])
+       queue1[nq++] = LOOP_REPR (loops->parray[i]);
+   dfs (g, queue1, nq, queue2, false);
+   for (i = 0; i < nq; i++)
+     queue1[i] = queue2[nq - i - 1];
+   dfs (g, queue1, nq, NULL, true);
+ 
+   /* Mark the irreducible loops.  */
+   for_each_edge (g, check_irred);
+ 
+   free_graph (g);
+   free (queue1);
+   free (queue2);
  
    loops->state |= LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS;
  }
  
Index: cfgloopmanip.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgloopmanip.c,v
retrieving revision 1.19
diff -c -3 -p -r1.19 cfgloopmanip.c
*** cfgloopmanip.c	30 Dec 2003 10:40:51 -0000	1.19
--- cfgloopmanip.c	28 Jan 2004 10:20:44 -0000
*************** split_loop_bb (basic_block bb, rtx insn)
*** 63,73 ****
    /* Add dest to loop.  */
    add_bb_to_loop (e->dest, e->src->loop_father);
  
-   /* Fix dominators.  */
-   add_to_dominance_info (CDI_DOMINATORS, e->dest);
-   redirect_immediate_dominators (CDI_DOMINATORS, e->src, e->dest);
-   set_immediate_dominator (CDI_DOMINATORS, e->dest, e->src);
- 
    return e;
  }
  
--- 63,68 ----
*************** remove_bbs (basic_block *bbs, int nbbs)
*** 88,95 ****
    for (i = 0; i < nbbs; i++)
      {
        remove_bb_from_loops (bbs[i]);
!       delete_from_dominance_info (CDI_DOMINATORS, bbs[i]);
!       delete_block (bbs[i]);
      }
  }
  
--- 83,89 ----
    for (i = 0; i < nbbs; i++)
      {
        remove_bb_from_loops (bbs[i]);
!       delete_basic_block (bbs[i]);
      }
  }
  
*************** duplicate_loop_to_header_edge (struct lo
*** 1070,1088 ****
    return true;
  }
  
  /* Creates a pre-header for a LOOP.  Returns newly created block.  Unless
     CP_SIMPLE_PREHEADERS is set in FLAGS, we only force LOOP to have single
     entry; otherwise we also force preheader block to have only one successor.
!    The function also updates dominators stored in DOM.  */
  static basic_block
  create_preheader (struct loop *loop, int flags)
  {
    edge e, fallthru;
    basic_block dummy;
-   basic_block jump, src = 0;
    struct loop *cloop, *ploop;
    int nentry = 0;
!   rtx insn;
  
    cloop = loop->outer;
  
--- 1064,1108 ----
    return true;
  }
  
+ /* A callback for make_forwarder block, to redirect all edges except for
+    MFB_KJ_EDGE to the entry part.  E is the edge for that we should decide
+    whether to redirect it.  */
+ 
+ static edge mfb_kj_edge;
+ static bool
+ mfb_keep_just (edge e)
+ {
+   return e != mfb_kj_edge;
+ }
+ 
+ /* A callback for make_forwarder block, to update data structures for a basic
+    block JUMP created by redirecting an edge (only the latch edge is being
+    redirected).  */
+ 
+ static void
+ mfb_update_loops (basic_block jump)
+ {
+   struct loop *loop = jump->succ->dest->loop_father;
+ 
+   if (dom_computed[CDI_DOMINATORS])
+     set_immediate_dominator (CDI_DOMINATORS, jump, jump->pred->src);
+   add_bb_to_loop (jump, loop);
+   loop->latch = jump;
+ }
+ 
  /* Creates a pre-header for a LOOP.  Returns newly created block.  Unless
     CP_SIMPLE_PREHEADERS is set in FLAGS, we only force LOOP to have single
     entry; otherwise we also force preheader block to have only one successor.
!    The function also updates dominators.  */
! 
  static basic_block
  create_preheader (struct loop *loop, int flags)
  {
    edge e, fallthru;
    basic_block dummy;
    struct loop *cloop, *ploop;
    int nentry = 0;
!   bool irred = false;
  
    cloop = loop->outer;
  
*************** create_preheader (struct loop *loop, int
*** 1090,1095 ****
--- 1110,1116 ----
      {
        if (e->src == loop->latch)
  	continue;
+       irred |= (e->flags & EDGE_IRREDUCIBLE_LOOP) != 0;
        nentry++;
      }
    if (!nentry)
*************** create_preheader (struct loop *loop, int
*** 1102,1118 ****
  	return NULL;
      }
  
!   insn = first_insn_after_basic_block_note (loop->header);
!   if (insn)
!     insn = PREV_INSN (insn);
!   else
!     insn = get_last_insn ();
!   if (insn == BB_END (loop->header))
!     {
!       /* Split_block would not split block after its end.  */
!       emit_note_after (NOTE_INSN_DELETED, insn);
!     }
!   fallthru = split_block (loop->header, insn);
    dummy = fallthru->src;
    loop->header = fallthru->dest;
  
--- 1123,1131 ----
  	return NULL;
      }
  
!   mfb_kj_edge = loop_latch_edge (loop);
!   fallthru = make_forwarder_block (loop->header, mfb_keep_just,
! 				   mfb_update_loops);
    dummy = fallthru->src;
    loop->header = fallthru->dest;
  
*************** create_preheader (struct loop *loop, int
*** 1122,1156 ****
      if (ploop->latch == dummy)
        ploop->latch = fallthru->dest;
  
!   add_to_dominance_info (CDI_DOMINATORS, fallthru->dest);
! 
!   /* Redirect edges.  */
    for (e = dummy->pred; e; e = e->pred_next)
!     {
!       src = e->src;
!       if (src == loop->latch)
! 	break;
!     }
!   if (!e)
!     abort ();
! 
!   dummy->frequency -= EDGE_FREQUENCY (e);
!   dummy->count -= e->count;
!   fallthru->count -= e->count;
!   jump = redirect_edge_and_branch_force (e, loop->header);
!   if (jump)
!     {
!       add_to_dominance_info (CDI_DOMINATORS, jump);
!       set_immediate_dominator (CDI_DOMINATORS, jump, src);
!       add_bb_to_loop (jump, loop);
!       loop->latch = jump;
!     }
  
-   /* Update structures.  */
-   redirect_immediate_dominators (CDI_DOMINATORS, dummy, loop->header);
-   set_immediate_dominator (CDI_DOMINATORS, loop->header, dummy);
    loop->header->loop_father = loop;
    add_bb_to_loop (dummy, cloop);
    if (rtl_dump_file)
      fprintf (rtl_dump_file, "Created preheader block for loop %i\n",
  	     loop->num);
--- 1135,1156 ----
      if (ploop->latch == dummy)
        ploop->latch = fallthru->dest;
  
!   /* Reorganize blocks so that the preheader is not stuck in the middle of the
!      loop.  */
    for (e = dummy->pred; e; e = e->pred_next)
!     if (e->src != loop->latch)
!       break;
!   move_block_after (dummy, e->src);
  
    loop->header->loop_father = loop;
    add_bb_to_loop (dummy, cloop);
+ 
+   if (irred)
+     {
+       dummy->flags |= BB_IRREDUCIBLE_LOOP;
+       dummy->succ->flags |= EDGE_IRREDUCIBLE_LOOP;
+     }
+ 
    if (rtl_dump_file)
      fprintf (rtl_dump_file, "Created preheader block for loop %i\n",
  	     loop->num);
*************** loop_split_edge_with (edge e, rtx insns)
*** 1212,1218 ****
    /* Create basic block for it.  */
  
    new_bb = split_edge (e);
-   add_to_dominance_info (CDI_DOMINATORS, new_bb);
    add_bb_to_loop (new_bb, loop_c);
    new_bb->flags = insns ? BB_SUPERBLOCK : 0;
  
--- 1212,1217 ----
*************** loop_split_edge_with (edge e, rtx insns)
*** 1225,1234 ****
  
    if (insns)
      emit_insn_after (insns, BB_END (new_bb));
- 
-   set_immediate_dominator (CDI_DOMINATORS, new_bb, src);
-   set_immediate_dominator (CDI_DOMINATORS, dest,
- 			   recount_dominator (CDI_DOMINATORS, dest));
  
    if (dest->loop_father->latch == src)
      dest->loop_father->latch = new_bb;
--- 1224,1229 ----
Index: cfgrtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgrtl.c,v
retrieving revision 1.106
diff -c -3 -p -r1.106 cfgrtl.c
*** cfgrtl.c	21 Jan 2004 20:39:52 -0000	1.106
--- cfgrtl.c	28 Jan 2004 10:20:44 -0000
*************** static rtx last_loop_beg_note (rtx);
*** 76,93 ****
  static bool back_edge_of_syntactic_loop_p (basic_block, basic_block);
  basic_block force_nonfallthru_and_redirect (edge, basic_block);
  static basic_block rtl_split_edge (edge);
  static int rtl_verify_flow_info (void);
! static edge cfg_layout_split_block (basic_block, void *);
  static bool cfg_layout_redirect_edge_and_branch (edge, basic_block);
  static basic_block cfg_layout_redirect_edge_and_branch_force (edge, basic_block);
  static void cfg_layout_delete_block (basic_block);
  static void rtl_delete_block (basic_block);
  static basic_block rtl_redirect_edge_and_branch_force (edge, basic_block);
  static bool rtl_redirect_edge_and_branch (edge, basic_block);
! static edge rtl_split_block (basic_block, void *);
! static void rtl_dump_bb (basic_block, FILE *);
  static int rtl_verify_flow_info_1 (void);
  static void mark_killed_regs (rtx, rtx, void *);
  
  /* Return true if NOTE is not one of the ones that must be kept paired,
     so that we may simply delete it.  */
--- 76,95 ----
  static bool back_edge_of_syntactic_loop_p (basic_block, basic_block);
  basic_block force_nonfallthru_and_redirect (edge, basic_block);
  static basic_block rtl_split_edge (edge);
+ static bool rtl_move_block_after (basic_block, basic_block);
  static int rtl_verify_flow_info (void);
! static basic_block cfg_layout_split_block (basic_block, void *);
  static bool cfg_layout_redirect_edge_and_branch (edge, basic_block);
  static basic_block cfg_layout_redirect_edge_and_branch_force (edge, basic_block);
  static void cfg_layout_delete_block (basic_block);
  static void rtl_delete_block (basic_block);
  static basic_block rtl_redirect_edge_and_branch_force (edge, basic_block);
  static bool rtl_redirect_edge_and_branch (edge, basic_block);
! static basic_block rtl_split_block (basic_block, void *);
! static void rtl_dump_bb (basic_block, FILE *, int);
  static int rtl_verify_flow_info_1 (void);
  static void mark_killed_regs (rtx, rtx, void *);
+ static void rtl_make_forwarder_block (edge);
  
  /* Return true if NOTE is not one of the ones that must be kept paired,
     so that we may simply delete it.  */
*************** rtl_create_basic_block (void *headp, voi
*** 337,343 ****
    basic_block bb;
  
    /* Place the new block just after the end.  */
!   VARRAY_GROW (basic_block_info, last_basic_block+1);
  
    n_basic_blocks++;
  
--- 339,345 ----
    basic_block bb;
  
    /* Place the new block just after the end.  */
!   VARRAY_GROW (basic_block_info, last_basic_block + 1);
  
    n_basic_blocks++;
  
*************** rtl_delete_block (basic_block b)
*** 407,425 ****
    /* Selectively delete the entire chain.  */
    BB_HEAD (b) = NULL;
    delete_insn_chain (insn, end);
- 
-   /* Remove the edges into and out of this block.  Note that there may
-      indeed be edges in, if we are removing an unreachable loop.  */
-   while (b->pred != NULL)
-     remove_edge (b->pred);
-   while (b->succ != NULL)
-     remove_edge (b->succ);
- 
-   b->pred = NULL;
-   b->succ = NULL;
- 
-   /* Remove the basic block from the array.  */
-   expunge_block (b);
  }
  
  /* Records the basic block struct in BLOCK_FOR_INSN for every insn.  */
--- 409,414 ----
*************** update_bb_for_insn (basic_block bb)
*** 470,497 ****
      }
  }
  
! /* Split a block BB after insn INSN creating a new fallthru edge.
!    Return the new edge.  Note that to keep other parts of the compiler happy,
!    this function renumbers all the basic blocks so that the new
!    one has a number one greater than the block split.  */
  
! static edge
  rtl_split_block (basic_block bb, void *insnp)
  {
    basic_block new_bb;
-   edge new_edge;
-   edge e;
    rtx insn = insnp;
  
!   /* There is no point splitting the block after its end.  */
!   if (BB_END (bb) == insn)
!     return 0;
  
    /* Create the new basic block.  */
    new_bb = create_basic_block (NEXT_INSN (insn), BB_END (bb), bb);
-   new_bb->count = bb->count;
-   new_bb->frequency = bb->frequency;
-   new_bb->loop_depth = bb->loop_depth;
    BB_END (bb) = insn;
  
    /* Redirect the outgoing edges.  */
--- 459,492 ----
      }
  }
  
! /* Creates a new basic block just after basic block B by splitting
!    everything after specified instruction I.  */
  
! static basic_block
  rtl_split_block (basic_block bb, void *insnp)
  {
    basic_block new_bb;
    rtx insn = insnp;
+   edge e;
  
!   if (!insn)
!     {
!       insn = first_insn_after_basic_block_note (bb);
! 
!       if (insn)
! 	insn = PREV_INSN (insn);
!       else
! 	insn = get_last_insn ();
!     }
! 
!   /* We probably should check type of the insn so that we do not create
!      inconsistent cfg.  It is checked in verify_flow_info anyway, so do not
!      bother.  */
!   if (insn == BB_END (bb))
!     emit_note_after (NOTE_INSN_DELETED, insn);
  
    /* Create the new basic block.  */
    new_bb = create_basic_block (NEXT_INSN (insn), BB_END (bb), bb);
    BB_END (bb) = insn;
  
    /* Redirect the outgoing edges.  */
*************** rtl_split_block (basic_block bb, void *i
*** 500,507 ****
    for (e = new_bb->succ; e; e = e->succ_next)
      e->src = new_bb;
  
-   new_edge = make_single_succ_edge (bb, new_bb, EDGE_FALLTHRU);
- 
    if (bb->global_live_at_start)
      {
        new_bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
--- 495,500 ----
*************** rtl_split_block (basic_block bb, void *i
*** 528,561 ****
  #endif
      }
  
!   return new_edge;
! }
! 
! /* Assume that the code of basic block B has been merged into A.
!    Do corresponding CFG updates:  redirect edges accordingly etc.  */
! static void
! update_cfg_after_block_merging (basic_block a, basic_block b)
! {
!   edge e;
! 
!   /* Normally there should only be one successor of A and that is B, but
!      partway though the merge of blocks for conditional_execution we'll
!      be merging a TEST block with THEN and ELSE successors.  Free the
!      whole lot of them and hope the caller knows what they're doing.  */
!   while (a->succ)
!     remove_edge (a->succ);
! 
!   /* Adjust the edges out of B for the new owner.  */
!   for (e = b->succ; e; e = e->succ_next)
!     e->src = a;
!   a->succ = b->succ;
!   a->flags |= b->flags;
! 
!   /* B hasn't quite yet ceased to exist.  Attempt to prevent mishap.  */
!   b->pred = b->succ = NULL;
!   a->global_live_at_end = b->global_live_at_end;
! 
!   expunge_block (b);
  }
  
  /* Blocks A and B are to be merged into a single block A.  The insns
--- 521,527 ----
  #endif
      }
  
!   return new_bb;
  }
  
  /* Blocks A and B are to be merged into a single block A.  The insns
*************** rtl_merge_blocks (basic_block a, basic_b
*** 625,634 ****
    else if (GET_CODE (NEXT_INSN (a_end)) == BARRIER)
      del_first = NEXT_INSN (a_end);
  
-   update_cfg_after_block_merging (a, b);
- 
    /* Delete everything marked above as well as crap that might be
       hanging out between the two blocks.  */
    delete_insn_chain (del_first, del_last);
  
    /* Reassociate the insns of B with A.  */
--- 591,599 ----
    else if (GET_CODE (NEXT_INSN (a_end)) == BARRIER)
      del_first = NEXT_INSN (a_end);
  
    /* Delete everything marked above as well as crap that might be
       hanging out between the two blocks.  */
+   BB_HEAD (b) = NULL;
    delete_insn_chain (del_first, del_last);
  
    /* Reassociate the insns of B with A.  */
*************** rtl_redirect_edge_and_branch_force (edge
*** 1159,1168 ****
  /* The given edge should potentially be a fallthru edge.  If that is in
     fact true, delete the jump and barriers that are in the way.  */
  
! void
! tidy_fallthru_edge (edge e, basic_block b, basic_block c)
  {
    rtx q;
  
    /* ??? In a late-running flow pass, other folks may have deleted basic
       blocks by nopping out blocks, leaving multiple BARRIERs between here
--- 1124,1139 ----
  /* The given edge should potentially be a fallthru edge.  If that is in
     fact true, delete the jump and barriers that are in the way.  */
  
! static void
! rtl_tidy_fallthru_edge (edge e)
  {
    rtx q;
+   basic_block b = e->src, c = b->next_bb;
+ 
+   /* If the jump insn has side effects, we can't tidy the edge.  */
+   if (GET_CODE (BB_END (b)) == JUMP_INSN
+       && !onlyjump_p (BB_END (b)))
+     return;
  
    /* ??? In a late-running flow pass, other folks may have deleted basic
       blocks by nopping out blocks, leaving multiple BARRIERs between here
*************** tidy_fallthru_edge (edge e, basic_block 
*** 1208,1255 ****
  
    e->flags |= EDGE_FALLTHRU;
  }
- 
- /* Fix up edges that now fall through, or rather should now fall through
-    but previously required a jump around now deleted blocks.  Simplify
-    the search by only examining blocks numerically adjacent, since this
-    is how find_basic_blocks created them.  */
- 
- void
- tidy_fallthru_edges (void)
- {
-   basic_block b, c;
- 
-   if (ENTRY_BLOCK_PTR->next_bb == EXIT_BLOCK_PTR)
-     return;
- 
-   FOR_BB_BETWEEN (b, ENTRY_BLOCK_PTR->next_bb, EXIT_BLOCK_PTR->prev_bb, next_bb)
-     {
-       edge s;
- 
-       c = b->next_bb;
- 
-       /* We care about simple conditional or unconditional jumps with
- 	 a single successor.
- 
- 	 If we had a conditional branch to the next instruction when
- 	 find_basic_blocks was called, then there will only be one
- 	 out edge for the block which ended with the conditional
- 	 branch (since we do not create duplicate edges).
- 
- 	 Furthermore, the edge will be marked as a fallthru because we
- 	 merge the flags for the duplicate edges.  So we do not want to
- 	 check that the edge is not a FALLTHRU edge.  */
- 
-       if ((s = b->succ) != NULL
- 	  && ! (s->flags & EDGE_COMPLEX)
- 	  && s->succ_next == NULL
- 	  && s->dest == c
- 	  /* If the jump insn has side effects, we can't tidy the edge.  */
- 	  && (GET_CODE (BB_END (b)) != JUMP_INSN
- 	      || onlyjump_p (BB_END (b))))
- 	tidy_fallthru_edge (s, b, c);
-     }
- }
  
  /* Helper function for split_edge.  Return true in case edge BB2 to BB1
     is back edge of syntactic loop.  */
--- 1179,1184 ----
*************** back_edge_of_syntactic_loop_p (basic_blo
*** 1285,1290 ****
--- 1214,1228 ----
    return count >= 0;
  }
  
+ /* Should move basic block BB after basic block AFTER.  NIY.  */
+ 
+ static bool
+ rtl_move_block_after (basic_block bb ATTRIBUTE_UNUSED,
+ 		      basic_block after ATTRIBUTE_UNUSED)
+ {
+   return false;
+ }
+ 
  /* Split a (typically critical) edge.  Return the new block.
     Abort on abnormal edges.
  
*************** rtl_split_edge (edge edge_in)
*** 1347,1354 ****
      before = NULL_RTX;
  
    bb = create_basic_block (before, NULL, edge_in->dest->prev_bb);
-   bb->count = edge_in->count;
-   bb->frequency = EDGE_FREQUENCY (edge_in);
  
    /* ??? This info is likely going to be out of date very soon.  */
    if (edge_in->dest->global_live_at_start)
--- 1285,1290 ----
*************** commit_edge_insertions_watch_calls (void
*** 1714,1728 ****
    sbitmap_free (blocks);
  }
  
! /* Print out one basic block with live information at start and end.  */
  
  static void
! rtl_dump_bb (basic_block bb, FILE *outf)
  {
    rtx insn;
    rtx last;
  
!   fputs (";; Registers live at start:", outf);
    dump_regset (bb->global_live_at_start, outf);
    putc ('\n', outf);
  
--- 1650,1670 ----
    sbitmap_free (blocks);
  }
  
! /* Print out RTL-specific basic block information (live information
!    at start and end).  */
  
  static void
! rtl_dump_bb (basic_block bb, FILE *outf, int indent)
  {
    rtx insn;
    rtx last;
+   char *s_indent;
  
!   s_indent = (char *) alloca ((size_t) indent + 1);
!   memset ((void *) s_indent, ' ', (size_t) indent);
!   s_indent[indent] = '\0';
! 
!   fprintf (outf, ";;%s Registers live at start: ", s_indent);
    dump_regset (bb->global_live_at_start, outf);
    putc ('\n', outf);
  
*************** rtl_dump_bb (basic_block bb, FILE *outf)
*** 1730,1736 ****
         insn = NEXT_INSN (insn))
      print_rtl_single (outf, insn);
  
!   fputs (";; Registers live at end:", outf);
    dump_regset (bb->global_live_at_end, outf);
    putc ('\n', outf);
  }
--- 1672,1678 ----
         insn = NEXT_INSN (insn))
      print_rtl_single (outf, insn);
  
!   fprintf (outf, ";;%s Registers live at end: ", s_indent);
    dump_regset (bb->global_live_at_end, outf);
    putc ('\n', outf);
  }
*************** update_br_prob_note (basic_block bb)
*** 1847,1852 ****
--- 1789,1795 ----
  
     In future it can be extended check a lot of other stuff as well
     (reachability of basic blocks, life information, etc. etc.).  */
+ 
  static int
  rtl_verify_flow_info_1 (void)
  {
*************** purge_all_dead_edges (int update_life_p)
*** 2412,2427 ****
  }
  
  /* Same as split_block but update cfg_layout structures.  */
! static edge
  cfg_layout_split_block (basic_block bb, void *insnp)
  {
    rtx insn = insnp;
  
!   edge fallthru = rtl_split_block (bb, insn);
  
!   fallthru->dest->rbi->footer = fallthru->src->rbi->footer;
!   fallthru->src->rbi->footer = NULL;
!   return fallthru;
  }
  
  
--- 2355,2371 ----
  }
  
  /* Same as split_block but update cfg_layout structures.  */
! 
! static basic_block
  cfg_layout_split_block (basic_block bb, void *insnp)
  {
    rtx insn = insnp;
+   basic_block new_bb = rtl_split_block (bb, insn);
  
!   new_bb->rbi->footer = bb->rbi->footer;
!   bb->rbi->footer = NULL;
  
!   return new_bb;
  }
  
  
*************** cfg_layout_redirect_edge_and_branch_forc
*** 2511,2517 ****
    return NULL;
  }
  
! /* Same as flow_delete_block but update cfg_layout structures.  */
  static void
  cfg_layout_delete_block (basic_block bb)
  {
--- 2455,2462 ----
    return NULL;
  }
  
! /* Same as delete_basic_block but update cfg_layout structures.  */
! 
  static void
  cfg_layout_delete_block (basic_block bb)
  {
*************** cfg_layout_merge_blocks (basic_block a, 
*** 2693,2703 ****
    if (rtl_dump_file)
      fprintf (rtl_dump_file, "Merged blocks %d and %d.\n",
  	     a->index, b->index);
- 
-   update_cfg_after_block_merging (a, b);
  }
  
  /* Split edge E.  */
  static basic_block
  cfg_layout_split_edge (edge e)
  {
--- 2638,2647 ----
    if (rtl_dump_file)
      fprintf (rtl_dump_file, "Merged blocks %d and %d.\n",
  	     a->index, b->index);
  }
  
  /* Split edge E.  */
+ 
  static basic_block
  cfg_layout_split_edge (edge e)
  {
*************** cfg_layout_split_edge (edge e)
*** 2707,2725 ****
  			? NEXT_INSN (BB_END (e->src)) : get_insns (),
  			NULL_RTX, e->src);
  
-   new_bb->count = e->count;
-   new_bb->frequency = EDGE_FREQUENCY (e);
- 
    new_e = make_edge (new_bb, e->dest, EDGE_FALLTHRU);
-   new_e->probability = REG_BR_PROB_BASE;
-   new_e->count = e->count;
    redirect_edge_and_branch_force (e, new_bb);
  
    return new_bb;
  }
  
  /* Implementation of CFG manipulation for linearized RTL.  */
  struct cfg_hooks rtl_cfg_hooks = {
    rtl_verify_flow_info,
    rtl_dump_bb,
    rtl_create_basic_block,
--- 2651,2672 ----
  			? NEXT_INSN (BB_END (e->src)) : get_insns (),
  			NULL_RTX, e->src);
  
    new_e = make_edge (new_bb, e->dest, EDGE_FALLTHRU);
    redirect_edge_and_branch_force (e, new_bb);
  
    return new_bb;
  }
  
+ /* Do postprocessing after making a forwarder block joined by edge FALLTHRU.  */
+ 
+ static void
+ rtl_make_forwarder_block (edge fallthru ATTRIBUTE_UNUSED)
+ {
+ }
+ 
  /* Implementation of CFG manipulation for linearized RTL.  */
  struct cfg_hooks rtl_cfg_hooks = {
+   "rtl",
    rtl_verify_flow_info,
    rtl_dump_bb,
    rtl_create_basic_block,
*************** struct cfg_hooks rtl_cfg_hooks = {
*** 2727,2735 ****
    rtl_redirect_edge_and_branch_force,
    rtl_delete_block,
    rtl_split_block,
    rtl_can_merge_blocks,  /* can_merge_blocks_p */
    rtl_merge_blocks,
!   rtl_split_edge
  };
  
  /* Implementation of CFG manipulation for cfg layout RTL, where
--- 2674,2685 ----
    rtl_redirect_edge_and_branch_force,
    rtl_delete_block,
    rtl_split_block,
+   rtl_move_block_after,
    rtl_can_merge_blocks,  /* can_merge_blocks_p */
    rtl_merge_blocks,
!   rtl_split_edge,
!   rtl_make_forwarder_block,
!   rtl_tidy_fallthru_edge
  };
  
  /* Implementation of CFG manipulation for cfg layout RTL, where
*************** struct cfg_hooks rtl_cfg_hooks = {
*** 2737,2742 ****
--- 2687,2693 ----
     This representation will hopefully become the default one in future
     version of the compiler.  */
  struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
+   "cfglayout mode",
    rtl_verify_flow_info_1,
    rtl_dump_bb,
    cfg_layout_create_basic_block,
*************** struct cfg_hooks cfg_layout_rtl_cfg_hook
*** 2744,2750 ****
    cfg_layout_redirect_edge_and_branch_force,
    cfg_layout_delete_block,
    cfg_layout_split_block,
    cfg_layout_can_merge_blocks_p,
    cfg_layout_merge_blocks,
!   cfg_layout_split_edge
  };
--- 2695,2704 ----
    cfg_layout_redirect_edge_and_branch_force,
    cfg_layout_delete_block,
    cfg_layout_split_block,
+   rtl_move_block_after,
    cfg_layout_can_merge_blocks_p,
    cfg_layout_merge_blocks,
!   cfg_layout_split_edge,
!   rtl_make_forwarder_block,
!   NULL
  };
Index: flow.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flow.c,v
retrieving revision 1.573
diff -c -3 -p -r1.573 flow.c
*** flow.c	25 Jan 2004 03:52:41 -0000	1.573
--- flow.c	28 Jan 2004 10:20:44 -0000
*************** verify_wide_reg (int regno, basic_block 
*** 517,523 ****
    if (rtl_dump_file)
      {
        fprintf (rtl_dump_file, "Register %d died unexpectedly.\n", regno);
!       dump_bb (bb, rtl_dump_file);
      }
    abort ();
  }
--- 517,523 ----
    if (rtl_dump_file)
      {
        fprintf (rtl_dump_file, "Register %d died unexpectedly.\n", regno);
!       dump_bb (bb, rtl_dump_file, 0);
      }
    abort ();
  }
*************** verify_local_live_at_start (regset new_l
*** 541,547 ****
  		       bb->index);
  	      debug_bitmap_file (rtl_dump_file, new_live_at_start);
  	      fputs ("Old:\n", rtl_dump_file);
! 	      dump_bb (bb, rtl_dump_file);
  	    }
  	  abort ();
  	}
--- 541,547 ----
  		       bb->index);
  	      debug_bitmap_file (rtl_dump_file, new_live_at_start);
  	      fputs ("Old:\n", rtl_dump_file);
! 	      dump_bb (bb, rtl_dump_file, 0);
  	    }
  	  abort ();
  	}
*************** verify_local_live_at_start (regset new_l
*** 562,568 ****
  		{
  		  fprintf (rtl_dump_file,
  			   "Register %d died unexpectedly.\n", i);
! 		  dump_bb (bb, rtl_dump_file);
  		}
  	      abort ();
  	    }
--- 562,568 ----
  		{
  		  fprintf (rtl_dump_file,
  			   "Register %d died unexpectedly.\n", i);
! 		  dump_bb (bb, rtl_dump_file, 0);
  		}
  	      abort ();
  	    }
Index: ifcvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ifcvt.c,v
retrieving revision 1.137
diff -c -3 -p -r1.137 ifcvt.c
*** ifcvt.c	25 Jan 2004 03:52:42 -0000	1.137
--- ifcvt.c	28 Jan 2004 10:20:44 -0000
*************** merge_if_block (struct ce_if_block * ce_
*** 2103,2110 ****
  	{
  	  bb = fallthru;
  	  fallthru = block_fallthru (bb);
- 	  if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
- 	    delete_from_dominance_info (CDI_POST_DOMINATORS, bb);
  	  merge_blocks (combo_bb, bb);
  	  num_true_changes++;
  	}
--- 2103,2108 ----
*************** merge_if_block (struct ce_if_block * ce_
*** 2120,2127 ****
        if (combo_bb->global_live_at_end)
  	COPY_REG_SET (combo_bb->global_live_at_end,
  		      then_bb->global_live_at_end);
-       if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
- 	delete_from_dominance_info (CDI_POST_DOMINATORS, then_bb);
        merge_blocks (combo_bb, then_bb);
        num_true_changes++;
      }
--- 2118,2123 ----
*************** merge_if_block (struct ce_if_block * ce_
*** 2131,2138 ****
       get their addresses taken.  */
    if (else_bb)
      {
-       if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
-        	delete_from_dominance_info (CDI_POST_DOMINATORS, else_bb);
        merge_blocks (combo_bb, else_bb);
        num_true_changes++;
      }
--- 2127,2132 ----
*************** merge_if_block (struct ce_if_block * ce_
*** 2188,2195 ****
  	COPY_REG_SET (combo_bb->global_live_at_end,
  		      join_bb->global_live_at_end);
  
-       if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
- 	delete_from_dominance_info (CDI_POST_DOMINATORS, join_bb);
        merge_blocks (combo_bb, join_bb);
        num_true_changes++;
      }
--- 2182,2187 ----
*************** merge_if_block (struct ce_if_block * ce_
*** 2205,2211 ****
  
        /* Remove the jump and cruft from the end of the COMBO block.  */
        if (join_bb != EXIT_BLOCK_PTR)
! 	tidy_fallthru_edge (combo_bb->succ, combo_bb, join_bb);
      }
  
    num_updated_if_blocks++;
--- 2197,2203 ----
  
        /* Remove the jump and cruft from the end of the COMBO block.  */
        if (join_bb != EXIT_BLOCK_PTR)
! 	tidy_fallthru_edge (combo_bb->succ);
      }
  
    num_updated_if_blocks++;
*************** find_cond_trap (basic_block test_bb, edg
*** 2643,2653 ****
    /* Delete the trap block if possible.  */
    remove_edge (trap_bb == then_bb ? then_edge : else_edge);
    if (trap_bb->pred == NULL)
!     {
!       if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
! 	delete_from_dominance_info (CDI_POST_DOMINATORS, trap_bb);
!       delete_block (trap_bb);
!     }
  
    /* If the non-trap block and the test are now adjacent, merge them.
       Otherwise we must insert a direct branch.  */
--- 2635,2641 ----
    /* Delete the trap block if possible.  */
    remove_edge (trap_bb == then_bb ? then_edge : else_edge);
    if (trap_bb->pred == NULL)
!     delete_basic_block (trap_bb);
  
    /* If the non-trap block and the test are now adjacent, merge them.
       Otherwise we must insert a direct branch.  */
*************** find_if_case_1 (basic_block test_bb, edg
*** 2829,2837 ****
  
    new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb), else_bb);
    then_bb_index = then_bb->index;
!   if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
!     delete_from_dominance_info (CDI_POST_DOMINATORS, then_bb);
!   delete_block (then_bb);
  
    /* Make rest of code believe that the newly created block is the THEN_BB
       block we removed.  */
--- 2817,2823 ----
  
    new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb), else_bb);
    then_bb_index = then_bb->index;
!   delete_basic_block (then_bb);
  
    /* Make rest of code believe that the newly created block is the THEN_BB
       block we removed.  */
*************** find_if_case_1 (basic_block test_bb, edg
*** 2839,2846 ****
      {
        new_bb->index = then_bb_index;
        BASIC_BLOCK (then_bb_index) = new_bb;
-       if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
- 	add_to_dominance_info (CDI_POST_DOMINATORS, new_bb);
      }
    /* We've possibly created jump to next insn, cleanup_cfg will solve that
       later.  */
--- 2825,2830 ----
*************** find_if_case_2 (basic_block test_bb, edg
*** 2909,2917 ****
  		    then_bb->global_live_at_start,
  		    else_bb->global_live_at_end, BITMAP_IOR);
  
!   if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY)
!     delete_from_dominance_info (CDI_POST_DOMINATORS, else_bb);
!   delete_block (else_bb);
  
    num_true_changes++;
    num_updated_if_blocks++;
--- 2893,2899 ----
  		    then_bb->global_live_at_start,
  		    else_bb->global_live_at_end, BITMAP_IOR);
  
!   delete_basic_block (else_bb);
  
    num_true_changes++;
    num_updated_if_blocks++;
Index: loop-unswitch.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/loop-unswitch.c,v
retrieving revision 1.11
diff -c -3 -p -r1.11 loop-unswitch.c
*** loop-unswitch.c	30 Dec 2003 10:40:54 -0000	1.11
--- loop-unswitch.c	28 Jan 2004 10:20:44 -0000
*************** unswitch_loop (struct loops *loops, stru
*** 381,387 ****
        switch_bb->succ->flags &= ~EDGE_IRREDUCIBLE_LOOP;
        switch_bb->succ->succ_next->flags &= ~EDGE_IRREDUCIBLE_LOOP;
      }
-   add_to_dominance_info (CDI_DOMINATORS, switch_bb);
    unswitch_on->rbi->copy = unswitch_on_alt;
  
    /* Loopify from the copy of LOOP body, constructing the new loop.  */
--- 381,386 ----
Index: timevar.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/timevar.def,v
retrieving revision 1.22
diff -c -3 -p -r1.22 timevar.def
*** timevar.def	21 Nov 2003 04:05:05 -0000	1.22
--- timevar.def	28 Jan 2004 10:20:44 -0000
*************** DEFTIMEVAR (TV_CGRAPHOPT             , "
*** 45,50 ****
--- 45,51 ----
  DEFTIMEVAR (TV_CFG                   , "cfg construction")
  /* Time spent by cleaning up CFG.  */
  DEFTIMEVAR (TV_CLEANUP_CFG           , "cfg cleanup")
+ DEFTIMEVAR (TV_CFG_VERIFY            , "CFG verifier")
  DEFTIMEVAR (TV_DELETE_TRIVIALLY_DEAD , "trivially dead code")
  /* Time spent by life analysis.  */
  DEFTIMEVAR (TV_LIFE		     , "life analysis")


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