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]

[tree-ssa] Loop header copying


Hello,

this patch moves the loop header copying pass from rtl to trees.  It is
is neccessary to do it early since it increases effectivity of code
motion optimizations.  It also kills a particulary ugly piece of rtl
loop optimization code.

I would slightly prefer to run this optimization after the first dce
pass so that the code size estimate is more accurate, but the problem
is that updating of ssa form after code duplication is nontrivial; so
the pass has to be run before rewriting into ssa for now.

It bootstraps on i686 and passes regtesting except for

gcc.c-torture/execute/builtin-bitops-1.c execution,  -O3 -fomit-frame-pointer
gcc.c-torture/execute/builtin-bitops-1.c execution,  -O3 -fomit-frame-pointer -funroll-all-loops -finline-functions
gcc.c-torture/execute/builtin-bitops-1.c execution,  -O3 -fomit-frame-pointer -funroll-loops
gcc.c-torture/execute/builtin-bitops-1.c execution,  -O3 -g;

there it exposes a bug described in

http://gcc.gnu.org/ml/gcc-patches/2003-12/msg00786.html

that I don't know how to fix (the patch in the message is wrong).

Zdenek

	* Makefile.in (tree-ssa-loop.o): Add cfgloop.h and tree-inline.h
	dependency.
	* cfghooks.h (struct cfg_hooks): Add split_block_after_labels and
	move_block_after fields.
	(split_block_after_labels, move_block_after): New macros.
	* cfgloopmanip.c (create_preheader): Use split_block_after_labels.
	Do not update dominators when not asked to.
	(loop_split_edge_with): Do not update dominators when not asked to.
	* cfgrtl.c (rtl_split_block_after_labels): New.
	(rtl_cfg_hooks): Add rtl_split_block_after_labels.
	* jump.c (next_nonnote_insn_in_loop, duplicate_loop_exit_test,
	copy_loop_headers): Removed.
	* rtl.h (copy_loop_headers): Declaration removed.
	* toplev.c (rest_of_compilation): Do not call copy_loop_headers.
	* tree-cfg.c (create_bb): Create annotations for newly created
	blocks.
	(create_blocks_annotations): Removed.
	(build_tree_cfg): Call to create_blocks_annotations removed.
	(tree_split_edge): Let create_bb create the bb annotations.
	(tree_split_block_after_labels, tree_duplicate_bb,
	tree_move_block_after): New.
	(tree_cfg_hooks): Add split_block_after_labels.
	* tree-dump.c (dump_files): Add tree-copy-headers dump.
	* tree-flow.h (tree_duplicate_bb, copy_loop_headers): Declare.
	* tree-optimize.c (optimize_function_tree): Call copy_loop_headers.
	* tree-ssa-loop.c: Include cfgloop.h and tree-inline.h.
	(call_expr_p, should_duplicate_loop_header_p, copy_loop_headers): New.
	* tree.h (enum tree_dump_index): Add TDI_copy_headers.
	* doc/invoke.texi (-fdump-tree-copy-headers): Document.

	* testsuite/gcc.dg/tree-ssa/20030711-1.c: Update expected results.
	* testsuite/gcc.dg/tree-ssa/20030714-2.c: Ditto.
	* testsuite/gcc.dg/tree-ssa/copy-headers.c: New test.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.903.2.153
diff -c -3 -p -r1.903.2.153 Makefile.in
*** Makefile.in	8 Dec 2003 13:52:58 -0000	1.903.2.153
--- Makefile.in	8 Dec 2003 20:28:03 -0000
*************** tree-eh.o : tree-eh.c $(TREE_FLOW_H) $(C
*** 1590,1596 ****
     $(RTL_H) $(TREE_H) $(TM_H) flags.h function.h except.h langhooks.h \
     $(GGC_H) gt-tree-eh.h
  tree-ssa-loop.o : tree-ssa-loop.c $(TREE_FLOW_H) $(CONFIG_H) \
!    $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) \
     output.h diagnostic.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H)
  tree-optimize.o : tree-optimize.c $(TREE_FLOW_H) $(CONFIG_H) \
     $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) \
--- 1590,1596 ----
     $(RTL_H) $(TREE_H) $(TM_H) flags.h function.h except.h langhooks.h \
     $(GGC_H) gt-tree-eh.h
  tree-ssa-loop.o : tree-ssa-loop.c $(TREE_FLOW_H) $(CONFIG_H) \
!    $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) cfgloop.h tree-inline.h \
     output.h diagnostic.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H)
  tree-optimize.o : tree-optimize.c $(TREE_FLOW_H) $(CONFIG_H) \
     $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) \
Index: cfghooks.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfghooks.h,v
retrieving revision 1.1.2.6
diff -c -3 -p -r1.1.2.6 cfghooks.h
*** cfghooks.h	3 Nov 2003 17:47:35 -0000	1.1.2.6
--- cfghooks.h	8 Dec 2003 20:28:03 -0000
*************** struct cfg_hooks
*** 51,56 ****
--- 51,62 ----
    /* Split basic block B after specified instruction I.  */
    edge (*split_block) (basic_block b, void * i);
  
+   /* Split basic block B immediatelly after labels.  */
+   edge (*split_block_after_labels) (basic_block b);
+ 
+   /* Move block B immediatelly after block A.  */
+   void (*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
*** 67,73 ****
  
  #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_basic_block(b)                cfg_hooks->delete_basic_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)
--- 73,81 ----
  
  #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(b,i)                     cfg_hooks->split_block (b,i)
! #define split_block_after_labels(b)          cfg_hooks->split_block_after_labels (b)
! #define move_block_after(b, a)               cfg_hooks->move_block_after (b, a)
  #define delete_basic_block(b)                cfg_hooks->delete_basic_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)
Index: cfgloopmanip.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgloopmanip.c,v
retrieving revision 1.3.2.9
diff -c -3 -p -r1.3.2.9 cfgloopmanip.c
*** cfgloopmanip.c	13 Nov 2003 02:37:37 -0000	1.3.2.9
--- cfgloopmanip.c	8 Dec 2003 20:28:03 -0000
*************** create_preheader (struct loop *loop, dom
*** 1101,1107 ****
    basic_block jump, src = 0;
    struct loop *cloop, *ploop;
    int nentry = 0;
-   rtx insn;
  
    cloop = loop->outer;
  
--- 1101,1106 ----
*************** create_preheader (struct loop *loop, dom
*** 1121,1137 ****
  	return NULL;
      }
  
!   insn = first_insn_after_basic_block_note (loop->header);
!   if (insn)
!     insn = PREV_INSN (insn);
!   else
!     insn = get_last_insn ();
!   if (insn == loop->header->end)
!     {
!       /* 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;
  
--- 1120,1126 ----
  	return NULL;
      }
  
!   fallthru = split_block_after_labels (loop->header);
    dummy = fallthru->src;
    loop->header = fallthru->dest;
  
*************** create_preheader (struct loop *loop, dom
*** 1141,1147 ****
      if (ploop->latch == dummy)
        ploop->latch = fallthru->dest;
  
!   add_to_dominance_info (dom, fallthru->dest);
  
    /* Redirect edges.  */
    for (e = dummy->pred; e; e = e->pred_next)
--- 1130,1147 ----
      if (ploop->latch == dummy)
        ploop->latch = fallthru->dest;
  
!   /* Reorganize blocks so that the preheader is not stuck in the middle of the
!      loop.  */
!   if (cfg_hooks->move_block_after)
!     {
!       for (e = dummy->pred; e; e = e->pred_next)
! 	{
! 	  src = e->src;
! 	  if (src != loop->latch)
! 	    break;
! 	}
!       move_block_after (dummy, e->src);
!     }
  
    /* Redirect edges.  */
    for (e = dummy->pred; e; e = e->pred_next)
*************** create_preheader (struct loop *loop, dom
*** 1159,1173 ****
    jump = redirect_edge_and_branch_force (e, loop->header);
    if (jump)
      {
!       add_to_dominance_info (dom, jump);
!       set_immediate_dominator (dom, jump, src);
        add_bb_to_loop (jump, loop);
        loop->latch = jump;
      }
  
    /* Update structures.  */
!   redirect_immediate_dominators (dom, dummy, loop->header);
!   set_immediate_dominator (dom, loop->header, dummy);
    loop->header->loop_father = loop;
    add_bb_to_loop (dummy, cloop);
    if (rtl_dump_file)
--- 1159,1181 ----
    jump = redirect_edge_and_branch_force (e, loop->header);
    if (jump)
      {
!       if (dom)
! 	{
! 	  add_to_dominance_info (dom, jump);
! 	  set_immediate_dominator (dom, jump, src);
! 	}
        add_bb_to_loop (jump, loop);
        loop->latch = jump;
      }
  
    /* Update structures.  */
!   if (dom)
!     {
!       add_to_dominance_info (dom, fallthru->dest);
!       redirect_immediate_dominators (dom, dummy, loop->header);
!       set_immediate_dominator (dom, loop->header, dummy);
!     }
! 
    loop->header->loop_father = loop;
    add_bb_to_loop (dummy, cloop);
    if (rtl_dump_file)
*************** loop_split_edge_with (edge e, rtx insns,
*** 1231,1237 ****
    /* Create basic block for it.  */
  
    new_bb = split_edge (e);
!   add_to_dominance_info (loops->cfg.dom, new_bb);
    add_bb_to_loop (new_bb, loop_c);
    new_bb->flags = insns ? BB_SUPERBLOCK : 0;
  
--- 1239,1246 ----
    /* Create basic block for it.  */
  
    new_bb = split_edge (e);
!   if (loops->cfg.dom)
!     add_to_dominance_info (loops->cfg.dom, new_bb);
    add_bb_to_loop (new_bb, loop_c);
    new_bb->flags = insns ? BB_SUPERBLOCK : 0;
  
*************** loop_split_edge_with (edge e, rtx insns,
*** 1245,1253 ****
    if (insns)
      emit_insn_after (insns, new_bb->end);
  
!   set_immediate_dominator (loops->cfg.dom, new_bb, src);
!   set_immediate_dominator (loops->cfg.dom, dest,
!     recount_dominator (loops->cfg.dom, dest));
  
    if (dest->loop_father->latch == src)
      dest->loop_father->latch = new_bb;
--- 1254,1265 ----
    if (insns)
      emit_insn_after (insns, new_bb->end);
  
!   if (loops->cfg.dom)
!     {
!       set_immediate_dominator (loops->cfg.dom, new_bb, src);
!       set_immediate_dominator (loops->cfg.dom, dest,
! 			       recount_dominator (loops->cfg.dom, dest));
!     }
  
    if (dest->loop_father->latch == src)
      dest->loop_father->latch = new_bb;
Index: cfgrtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgrtl.c,v
retrieving revision 1.57.2.20
diff -c -3 -p -r1.57.2.20 cfgrtl.c
*** cfgrtl.c	8 Dec 2003 12:58:22 -0000	1.57.2.20
--- cfgrtl.c	8 Dec 2003 20:28:03 -0000
*************** static rtx last_loop_beg_note (rtx);
*** 76,81 ****
--- 76,82 ----
  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 edge rtl_split_block_after_labels (basic_block);
  static int rtl_verify_flow_info (void);
  static edge cfg_layout_split_block (basic_block, void *);
  static edge cfg_layout_redirect_edge_and_branch (edge, basic_block);
*************** redirect_edge_with_latch_update (edge e,
*** 2784,2789 ****
--- 2785,2810 ----
      }
  }
  
+ /* Splits block BB immediately after the initial label.  */
+ 
+ static edge
+ rtl_split_block_after_labels (basic_block bb)
+ {
+   rtx insn = first_insn_after_basic_block_note (bb);
+ 
+   if (insn)
+     insn = PREV_INSN (insn);
+   else
+     insn = get_last_insn ();
+   if (insn == bb->end)
+     {
+       /* Split_block would not split block after its end.  */
+       emit_note_after (NOTE_INSN_DELETED, insn);
+     }
+ 
+   return split_block (bb, insn);
+ }
+ 
  /* Declarations from cfgloop.h.  */
  extern struct loops *rtl_loop_optimizer_init (FILE *);
  extern void rtl_loop_optimizer_finalize (struct loops *, FILE *);
*************** struct cfg_hooks rtl_cfg_hooks = {
*** 2797,2802 ****
--- 2818,2825 ----
    rtl_redirect_edge_and_branch_force,
    rtl_delete_block,
    rtl_split_block,
+   rtl_split_block_after_labels,
+   NULL,
    rtl_can_merge_blocks,  /* can_merge_blocks_p */
    rtl_merge_blocks,
    rtl_split_edge,
*************** struct cfg_hooks cfg_layout_rtl_cfg_hook
*** 2817,2822 ****
--- 2840,2847 ----
    cfg_layout_redirect_edge_and_branch_force,
    cfg_layout_delete_block,
    cfg_layout_split_block,
+   rtl_split_block_after_labels,
+   NULL,
    cfg_layout_can_merge_blocks_p,
    cfg_layout_merge_blocks,
    cfg_layout_split_edge,
Index: jump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/jump.c,v
retrieving revision 1.210.2.17
diff -c -3 -p -r1.210.2.17 jump.c
*** jump.c	14 Nov 2003 00:24:28 -0000	1.210.2.17
--- jump.c	8 Dec 2003 20:28:03 -0000
*************** Software Foundation, 59 Temple Place - S
*** 63,72 ****
     or even change what is live at any point.
     So perhaps let combiner do it.  */
  
- static rtx next_nonnote_insn_in_loop (rtx);
  static void init_label_info (rtx);
  static void mark_all_labels (rtx);
- static int duplicate_loop_exit_test (rtx);
  static void delete_computation (rtx);
  static void redirect_exp_1 (rtx *, rtx, rtx, rtx);
  static int redirect_exp (rtx, rtx, rtx);
--- 63,70 ----
*************** cleanup_barriers (void)
*** 123,177 ****
      }
  }
  
- /* Return the next insn after INSN that is not a NOTE and is in the loop,
-    i.e. when there is no such INSN before NOTE_INSN_LOOP_END return NULL_RTX.
-    This routine does not look inside SEQUENCEs.  */
- 
- static rtx
- next_nonnote_insn_in_loop (rtx insn)
- {
-   while (insn)
-     {
-       insn = NEXT_INSN (insn);
-       if (insn == 0 || GET_CODE (insn) != NOTE)
- 	break;
-       if (GET_CODE (insn) == NOTE
- 	  && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
- 	return NULL_RTX;
-     }
- 
-   return insn;
- }
- 
- void
- copy_loop_headers (rtx f)
- {
-   rtx insn, next;
-   /* Now iterate optimizing jumps until nothing changes over one pass.  */
-   for (insn = f; insn; insn = next)
-     {
-       rtx temp, temp1;
- 
-       next = NEXT_INSN (insn);
- 
-       /* See if this is a NOTE_INSN_LOOP_BEG followed by an unconditional
- 	 jump.  Try to optimize by duplicating the loop exit test if so.
- 	 This is only safe immediately after regscan, because it uses
- 	 the values of regno_first_uid and regno_last_uid.  */
-       if (GET_CODE (insn) == NOTE
- 	  && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
- 	  && (temp1 = next_nonnote_insn_in_loop (insn)) != 0
- 	  && any_uncondjump_p (temp1) && onlyjump_p (temp1))
- 	{
- 	  temp = PREV_INSN (insn);
- 	  if (duplicate_loop_exit_test (insn))
- 	    {
- 	      next = NEXT_INSN (temp);
- 	    }
- 	}
-     }
- }
- 
  void
  purge_line_number_notes (rtx f)
  {
--- 121,126 ----
*************** mark_all_labels (rtx f)
*** 288,531 ****
        }
  }
  
- /* LOOP_START is a NOTE_INSN_LOOP_BEG note that is followed by an unconditional
-    jump.  Assume that this unconditional jump is to the exit test code.  If
-    the code is sufficiently simple, make a copy of it before INSN,
-    followed by a jump to the exit of the loop.  Then delete the unconditional
-    jump after INSN.
- 
-    Return 1 if we made the change, else 0.
- 
-    This is only safe immediately after a regscan pass because it uses the
-    values of regno_first_uid and regno_last_uid.  */
- 
- static int
- duplicate_loop_exit_test (rtx loop_start)
- {
-   rtx insn, set, reg, p, link;
-   rtx copy = 0, first_copy = 0;
-   int num_insns = 0;
-   rtx exitcode
-     = NEXT_INSN (JUMP_LABEL (next_nonnote_insn_in_loop (loop_start)));
-   rtx lastexit;
-   int max_reg = max_reg_num ();
-   rtx *reg_map = 0;
-   rtx loop_pre_header_label;
- 
-   /* Scan the exit code.  We do not perform this optimization if any insn:
- 
-          is a CALL_INSN
- 	 is a CODE_LABEL
- 	 has a REG_RETVAL or REG_LIBCALL note (hard to adjust)
- 	 is a NOTE_INSN_LOOP_BEG because this means we have a nested loop
- 
-      We also do not do this if we find an insn with ASM_OPERANDS.  While
-      this restriction should not be necessary, copying an insn with
-      ASM_OPERANDS can confuse asm_noperands in some cases.
- 
-      Also, don't do this if the exit code is more than 20 insns.  */
- 
-   for (insn = exitcode;
-        insn
-        && ! (GET_CODE (insn) == NOTE
- 	     && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END);
-        insn = NEXT_INSN (insn))
-     {
-       switch (GET_CODE (insn))
- 	{
- 	case CODE_LABEL:
- 	case CALL_INSN:
- 	  return 0;
- 	case NOTE:
- 
- 	  if (optimize < 2
- 	      && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
- 		  || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
- 	    /* If we were to duplicate this code, we would not move
- 	       the BLOCK notes, and so debugging the moved code would
- 	       be difficult.  Thus, we only move the code with -O2 or
- 	       higher.  */
- 	    return 0;
- 
- 	  break;
- 	case JUMP_INSN:
- 	case INSN:
- 	  if (++num_insns > 20
- 	      || find_reg_note (insn, REG_RETVAL, NULL_RTX)
- 	      || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
- 	    return 0;
- 	  break;
- 	default:
- 	  break;
- 	}
-     }
- 
-   /* Unless INSN is zero, we can do the optimization.  */
-   if (insn == 0)
-     return 0;
- 
-   lastexit = insn;
- 
-   /* See if any insn sets a register only used in the loop exit code and
-      not a user variable.  If so, replace it with a new register.  */
-   for (insn = exitcode; insn != lastexit; insn = NEXT_INSN (insn))
-     if (GET_CODE (insn) == INSN
- 	&& (set = single_set (insn)) != 0
- 	&& ((reg = SET_DEST (set), GET_CODE (reg) == REG)
- 	    || (GET_CODE (reg) == SUBREG
- 		&& (reg = SUBREG_REG (reg), GET_CODE (reg) == REG)))
- 	&& REGNO (reg) >= FIRST_PSEUDO_REGISTER
- 	&& REGNO_FIRST_UID (REGNO (reg)) == INSN_UID (insn))
-       {
- 	for (p = NEXT_INSN (insn); p != lastexit; p = NEXT_INSN (p))
- 	  if (REGNO_LAST_UID (REGNO (reg)) == INSN_UID (p))
- 	    break;
- 
- 	if (p != lastexit)
- 	  {
- 	    /* We can do the replacement.  Allocate reg_map if this is the
- 	       first replacement we found.  */
- 	    if (reg_map == 0)
- 	      reg_map = xcalloc (max_reg, sizeof (rtx));
- 
- 	    REG_LOOP_TEST_P (reg) = 1;
- 
- 	    reg_map[REGNO (reg)] = gen_reg_rtx (GET_MODE (reg));
- 	  }
-       }
-   loop_pre_header_label = gen_label_rtx ();
- 
-   /* Now copy each insn.  */
-   for (insn = exitcode; insn != lastexit; insn = NEXT_INSN (insn))
-     {
-       switch (GET_CODE (insn))
- 	{
- 	case BARRIER:
- 	  copy = emit_barrier_before (loop_start);
- 	  break;
- 	case NOTE:
- 	  /* Only copy line-number notes.  */
- 	  if (NOTE_LINE_NUMBER (insn) >= 0)
- 	    {
- 	      copy = emit_note_before (NOTE_LINE_NUMBER (insn), loop_start);
- 	      NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn);
- 	    }
- 	  break;
- 
- 	case INSN:
- 	  copy = emit_insn_before (copy_insn (PATTERN (insn)), loop_start);
- 	  if (reg_map)
- 	    replace_regs (PATTERN (copy), reg_map, max_reg, 1);
- 
- 	  mark_jump_label (PATTERN (copy), copy, 0);
- 	  INSN_LOCATOR (copy) = INSN_LOCATOR (insn);
- 
- 	  /* Copy all REG_NOTES except REG_LABEL since mark_jump_label will
- 	     make them.  */
- 	  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
- 	    if (REG_NOTE_KIND (link) != REG_LABEL)
- 	      {
- 		if (GET_CODE (link) == EXPR_LIST)
- 		  REG_NOTES (copy)
- 		    = copy_insn_1 (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
- 						      XEXP (link, 0),
- 						      REG_NOTES (copy)));
- 		else
- 		  REG_NOTES (copy)
- 		    = copy_insn_1 (gen_rtx_INSN_LIST (REG_NOTE_KIND (link),
- 						      XEXP (link, 0),
- 						      REG_NOTES (copy)));
- 	      }
- 
- 	  if (reg_map && REG_NOTES (copy))
- 	    replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);
- 	  break;
- 
- 	case JUMP_INSN:
- 	  copy = emit_jump_insn_before (copy_insn (PATTERN (insn)),
- 					loop_start);
- 	  INSN_LOCATOR (copy) = INSN_LOCATOR (insn);
- 	  if (reg_map)
- 	    replace_regs (PATTERN (copy), reg_map, max_reg, 1);
- 	  mark_jump_label (PATTERN (copy), copy, 0);
- 	  if (REG_NOTES (insn))
- 	    {
- 	      REG_NOTES (copy) = copy_insn_1 (REG_NOTES (insn));
- 	      if (reg_map)
- 		replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);
- 	    }
- 
- 	  /* Predict conditional jump that do make loop looping as taken.
- 	     Other jumps are probably exit conditions, so predict
- 	     them as untaken.  */
- 	  if (any_condjump_p (copy))
- 	    {
- 	      rtx label = JUMP_LABEL (copy);
- 	      if (label)
- 		{
- 		  /* The jump_insn after loop_start should be followed
- 		     by barrier and loopback label.  */
- 		  if (prev_nonnote_insn (label)
- 		      && (prev_nonnote_insn (prev_nonnote_insn (label))
- 			  == next_nonnote_insn (loop_start)))
- 		    {
- 		      predict_insn_def (copy, PRED_LOOP_HEADER, TAKEN);
- 		      /* To keep pre-header, we need to redirect all loop
- 		         entrances before the LOOP_BEG note.  */
- 		      redirect_jump (copy, loop_pre_header_label, 0);
- 		    }
- 		  else
- 		    predict_insn_def (copy, PRED_LOOP_HEADER, NOT_TAKEN);
- 		}
- 	    }
- 	  break;
- 
- 	default:
- 	  abort ();
- 	}
- 
-       /* Record the first insn we copied.  We need it so that we can
- 	 scan the copied insns for new pseudo registers.  */
-       if (! first_copy)
- 	first_copy = copy;
-     }
- 
-   /* Now clean up by emitting a jump to the end label and deleting the jump
-      at the start of the loop.  */
-   if (! copy || GET_CODE (copy) != BARRIER)
-     {
-       copy = emit_jump_insn_before (gen_jump (get_label_after (insn)),
- 				    loop_start);
- 
-       /* Record the first insn we copied.  We need it so that we can
- 	 scan the copied insns for new pseudo registers.   This may not
- 	 be strictly necessary since we should have copied at least one
- 	 insn above.  But I am going to be safe.  */
-       if (! first_copy)
- 	first_copy = copy;
- 
-       mark_jump_label (PATTERN (copy), copy, 0);
-       emit_barrier_before (loop_start);
-     }
- 
-   emit_label_before (loop_pre_header_label, loop_start);
- 
-   /* Now scan from the first insn we copied to the last insn we copied
-      (copy) for new pseudo registers.  Do this after the code to jump to
-      the end label since that might create a new pseudo too.  */
-   reg_scan_update (first_copy, copy, max_reg);
- 
-   /* Mark the exit code as the virtual top of the converted loop.  */
-   emit_note_before (NOTE_INSN_LOOP_VTOP, exitcode);
- 
-   delete_related_insns (next_nonnote_insn (loop_start));
- 
-   /* Clean up.  */
-   if (reg_map)
-     free (reg_map);
- 
-   return 1;
- }
  
  /* Move all block-beg, block-end, loop-beg, loop-cont, loop-vtop, loop-end,
     notes between START and END out before START.  START and END may be such
--- 237,242 ----
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.362.2.30
diff -c -3 -p -r1.362.2.30 rtl.h
*** rtl.h	1 Dec 2003 19:38:38 -0000	1.362.2.30
--- rtl.h	8 Dec 2003 20:28:03 -0000
*************** extern enum rtx_code reversed_comparison
*** 2025,2031 ****
  extern void delete_for_peephole (rtx, rtx);
  extern int condjump_in_parallel_p (rtx);
  extern void purge_line_number_notes (rtx);
- extern void copy_loop_headers (rtx);
  
  /* In emit-rtl.c.  */
  extern int max_reg_num (void);
--- 2025,2030 ----
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.654.2.82
diff -c -3 -p -r1.654.2.82 toplev.c
*** toplev.c	6 Dec 2003 12:31:27 -0000	1.654.2.82
--- toplev.c	8 Dec 2003 20:28:03 -0000
*************** rest_of_compilation (tree decl)
*** 3286,3297 ****
  
    create_loop_notes ();
  
-   if (optimize)
-     {
-       free_bb_for_insn ();
-       copy_loop_headers (insns);
-       find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
-     }
    purge_line_number_notes (insns);
  
    timevar_pop (TV_JUMP);
--- 3286,3291 ----
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.234
diff -c -3 -p -r1.1.4.234 tree-cfg.c
*** tree-cfg.c	8 Dec 2003 13:52:59 -0000	1.1.4.234
--- tree-cfg.c	8 Dec 2003 20:28:03 -0000
*************** static GTY(()) tree factored_computed_go
*** 83,89 ****
  
  /* Basic blocks and flowgraphs.  */
  static basic_block create_bb (tree, basic_block);
- static void create_blocks_annotations (void);
  static void create_block_annotation (basic_block);
  static void free_blocks_annotations (void);
  static void clear_blocks_annotations (void);
--- 83,88 ----
*************** build_tree_cfg (tree *fnbody)
*** 167,174 ****
        /* Adjust the size of the array.  */
        VARRAY_GROW (basic_block_info, n_basic_blocks);
  
!       /* Create block annotations.  */
!       create_blocks_annotations ();
  
        /* Create the edges of the flowgraph.  */
        make_edges ();
--- 166,173 ----
        /* Adjust the size of the array.  */
        VARRAY_GROW (basic_block_info, n_basic_blocks);
  
!       create_block_annotation (ENTRY_BLOCK_PTR);
!       create_block_annotation (EXIT_BLOCK_PTR);
  
        /* Create the edges of the flowgraph.  */
        make_edges ();
*************** factor_computed_gotos (void)
*** 271,286 ****
      }
  }
  
- /* Create annotations for all the basic blocks.  */
- 
- static void create_blocks_annotations (void)
- {
-   basic_block bb;
-   
-   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
-     create_block_annotation (bb);
- }
- 
  /* Create annotations for a single basic block.  */
  
  static void create_block_annotation (basic_block bb)
--- 270,275 ----
*************** create_bb (tree stmt_list, basic_block a
*** 385,390 ****
--- 374,381 ----
    /* Add the newly created block to the array.  */
    BASIC_BLOCK (n_basic_blocks) = bb;
  
+   create_block_annotation (bb);
+ 
    n_basic_blocks++;
    last_basic_block++;
  
*************** tree_split_edge (edge edge_in)
*** 2712,2718 ****
      after_bb = edge_in->src;
  
    new_bb = create_bb (NULL, after_bb);
-   create_block_annotation (new_bb);
    new_edge = make_edge (new_bb, dest, EDGE_FALLTHRU);
  
    if (!tree_redirect_edge_and_branch_1 (edge_in, new_bb, true))
--- 2703,2708 ----
*************** tree_make_forwarder_block (basic_block b
*** 3168,3205 ****
  {
    edge e, next_e, new_e, fallthru;
    basic_block dummy;
!   tree phi, new_phi, var, label;
    bool first;
-   block_stmt_iterator bsi, bsi_tgt;
- 
-   dummy = create_bb (NULL, bb->prev_bb);
-   create_block_annotation (dummy);
-   dummy->count = bb->count;
-   dummy->frequency = bb->frequency;
-   dummy->loop_depth = bb->loop_depth;
  
!   /* Redirect the incoming edges.  */
!   dummy->pred = bb->pred;
!   bb->pred = NULL;
!   for (e = dummy->pred; e; e = e->pred_next)
!     e->dest = dummy;
! 
!   /* Move the phi nodes to the dummy block.  */
!   set_phi_nodes (dummy, phi_nodes (bb));
!   set_phi_nodes (bb, NULL_TREE);
! 
!   /* Move the labels to the new basic block.  */
!   for (bsi = bsi_start (bb), bsi_tgt = bsi_start (dummy); !bsi_end_p (bsi); )
!     {
!       label = bsi_stmt (bsi);
!       if (TREE_CODE (label) != LABEL_EXPR)
! 	break;
! 
!       bsi_remove (&bsi);
!       bsi_insert_after (&bsi_tgt, label, BSI_NEW_STMT);
!     }
! 
!   fallthru = make_edge (dummy, bb, EDGE_FALLTHRU);
  
    alloc_aux_for_block (dummy, sizeof (int));
    HEADER_BLOCK (dummy) = 0;
--- 3158,3169 ----
  {
    edge e, next_e, new_e, fallthru;
    basic_block dummy;
!   tree phi, new_phi, var;
    bool first;
  
!   fallthru = split_block (bb, NULL);
!   dummy = fallthru->src;
!   bb = fallthru->dest;
  
    alloc_aux_for_block (dummy, sizeof (int));
    HEADER_BLOCK (dummy) = 0;
*************** tree_loop_optimizer_init (FILE *dumpfile
*** 3291,3302 ****
    free (loops->cfg.dfs_order);
    loops->cfg.dfs_order = NULL;
  
- #if 0
-   /* Does not work just now.  It will be easier to fix it in the no-gotos
-      form.  */
    /* Force all latches to have only single successor.  */
    force_single_succ_latches (loops);
- #endif
  
    /* Mark irreducible loops.  */
    mark_irreducible_loops (loops);
--- 3255,3262 ----
*************** tree_redirect_edge_and_branch_force (edg
*** 3680,3685 ****
--- 3640,3755 ----
    return NULL;
  }
  
+ /* Splits basic block BB after statement STMT (but at least after the
+    labels).  If STMT is NULL, the BB is split just after the labels.  */
+ 
+ static edge
+ tree_split_block (basic_block bb, void *stmt)
+ {
+   block_stmt_iterator bsi, bsi_tgt;
+   tree last, label;
+   basic_block dummy;
+   edge e;
+ 
+   dummy = create_bb (NULL, bb->prev_bb);
+   dummy->count = bb->count;
+   dummy->frequency = bb->frequency;
+   dummy->loop_depth = bb->loop_depth;
+ 
+   /* Redirect the incoming edges.  */
+   dummy->pred = bb->pred;
+   bb->pred = NULL;
+   for (e = dummy->pred; e; e = e->pred_next)
+     e->dest = dummy;
+ 
+   /* Move the phi nodes to the dummy block.  */
+   set_phi_nodes (dummy, phi_nodes (bb));
+   set_phi_nodes (bb, NULL_TREE);
+ 
+   /* Move everything up to BSI to the new basic block.  */
+   last = NULL_TREE;
+   for (bsi = bsi_start (bb), bsi_tgt = bsi_start (dummy); !bsi_end_p (bsi); )
+     {
+       label = bsi_stmt (bsi);
+       if (TREE_CODE (label) != LABEL_EXPR)
+ 	break;
+ 
+       bsi_remove (&bsi);
+       bsi_insert_after (&bsi_tgt, label, BSI_NEW_STMT);
+       if (label == stmt)
+ 	last = label;
+     }
+ 
+   while (!bsi_end_p (bsi) && last != stmt)
+     {
+       last = bsi_stmt (bsi);
+       bsi_remove (&bsi);
+       bsi_insert_after (&bsi_tgt, last, BSI_NEW_STMT);
+     }
+ 
+   return make_edge (dummy, bb, EDGE_FALLTHRU);
+ }
+ 
+ /* Splits block BB immediatelly after initial labels.  */
+ 
+ static edge
+ tree_split_block_after_labels (basic_block bb)
+ {
+   return tree_split_block (bb, NULL);
+ }
+ 
+ /* Moves basic block BB after block AFTER.  */
+ 
+ static void
+ tree_move_block_after (basic_block bb, basic_block after)
+ {
+   if (bb->prev_bb == after)
+     return;
+ 
+   unlink_block (bb);
+   link_block (bb, after);
+ }
+ 
+ /* Create a duplicate of the basic block BB and redirect edge E into it.  Does
+    not work over ssa.  */
+ 
+ basic_block
+ tree_duplicate_bb (basic_block bb, edge e)
+ {
+   edge s, n;
+   basic_block new_bb;
+   block_stmt_iterator bsi, bsi_tgt;
+ 
+   if (e->dest != bb)
+     abort ();
+ 
+   new_bb = create_bb (NULL, e->src);
+   bsi_tgt = bsi_start (new_bb);
+   for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+     {
+       tree stmt = bsi_stmt (bsi);
+ 
+       if (TREE_CODE (stmt) == LABEL_EXPR)
+ 	continue;
+ 
+       bsi_insert_after (&bsi_tgt, unshare_expr (stmt), BSI_NEW_STMT);
+     }
+ 
+   new_bb->loop_depth = bb->loop_depth;
+   new_bb->flags = bb->flags;
+   for (s = bb->succ; s; s = s->succ_next)
+     {
+       /* Since we are creating edges from a new block to successors
+ 	 of another block (which therefore are known to be disjoint), there
+ 	 is no need to actually check for duplicated edges.  */
+       n = unchecked_make_edge (new_bb, s->dest, s->flags);
+     }
+ 
+   redirect_edge_and_branch_force (e, new_bb);
+ 
+   return new_bb;
+ }
+ 
  /* Dump FUNCTION_DECL FN to file FILE using FLAGS (see TDF_* in tree.h)  */
  
  void
*************** struct cfg_hooks tree_cfg_hooks = {
*** 3792,3798 ****
    tree_redirect_edge_and_branch,/* redirect_edge_and_branch  */
    tree_redirect_edge_and_branch_force,/* redirect_edge_and_branch_force  */
    NULL,				/* delete_basic_block  */
!   NULL,				/* split_block  */
    NULL,				/* can_merge_blocks_p  */
    NULL,				/* merge_blocks  */
    tree_split_edge,		/* cfgh_split_edge  */
--- 3862,3870 ----
    tree_redirect_edge_and_branch,/* redirect_edge_and_branch  */
    tree_redirect_edge_and_branch_force,/* redirect_edge_and_branch_force  */
    NULL,				/* delete_basic_block  */
!   tree_split_block,		/* split_block  */
!   tree_split_block_after_labels,/* split_block_after_labels  */
!   tree_move_block_after,	/* move_block_after  */
    NULL,				/* can_merge_blocks_p  */
    NULL,				/* merge_blocks  */
    tree_split_edge,		/* cfgh_split_edge  */
Index: tree-dump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-dump.c,v
retrieving revision 1.6.2.58
diff -c -3 -p -r1.6.2.58 tree-dump.c
*** tree-dump.c	7 Dec 2003 10:07:45 -0000	1.6.2.58
--- tree-dump.c	8 Dec 2003 20:28:03 -0000
*************** static struct dump_file_info dump_files[
*** 660,665 ****
--- 660,666 ----
    {".dot", "tree-dot", 0, 0},
    {".pta", "tree-pta", 0, 0},
    {".alias", "tree-alias", 0, 0},
+   {".ch", "tree-copy-headers", 0, 0},
    {".ssa1", "tree-ssa1", 0, 0},
    {".thread", "tree-jumpthread", 0, 0},
    {".dom1", "tree-dom1", 0, 0},
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.167
diff -c -3 -p -r1.1.4.167 tree-flow.h
*** tree-flow.h	8 Dec 2003 12:58:22 -0000	1.1.4.167
--- tree-flow.h	8 Dec 2003 20:28:03 -0000
*************** extern void clear_special_calls (void);
*** 449,454 ****
--- 448,454 ----
  extern void compute_dominance_frontiers (bitmap *, dominance_info);
  extern bool verify_stmt (tree);
  extern void verify_stmts (void);
+ extern basic_block tree_duplicate_bb (basic_block, edge);
  
  /* In tree-pretty-print.c.  */
  extern void dump_generic_bb (FILE *, basic_block, int, int);
*************** void tree_ssa_dce (tree, enum tree_dump_
*** 543,548 ****
--- 543,549 ----
  
  /* In tree-ssa-loop.c  */
  void tree_ssa_loop_opt (tree, enum tree_dump_index);
+ void copy_loop_headers (tree, enum tree_dump_index);
  
  /* In tree-flow-inline.h  */
  static inline int phi_arg_from_edge (tree, edge);
Index: tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 1.1.4.90
diff -c -3 -p -r1.1.4.90 tree-optimize.c
*** tree-optimize.c	7 Dec 2003 16:44:01 -0000	1.1.4.90
--- tree-optimize.c	8 Dec 2003 20:28:03 -0000
*************** optimize_function_tree (tree fndecl, tre
*** 79,84 ****
--- 79,87 ----
        verify_stmts ();
  #endif
  
+       /* Copy the loop headers.  */
+       copy_loop_headers (fndecl, TDI_copy_headers);
+ 
        /* Initialize common SSA structures.  */
        init_tree_ssa ();
  
Index: tree-ssa-loop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-loop.c,v
retrieving revision 1.1.2.2
diff -c -3 -p -r1.1.2.2 tree-ssa-loop.c
*** tree-ssa-loop.c	7 Dec 2003 15:12:13 -0000	1.1.2.2
--- tree-ssa-loop.c	8 Dec 2003 20:28:03 -0000
*************** Software Foundation, 59 Temple Place - S
*** 33,44 ****
  #include "tree-flow.h"
  #include "tree-dump.h"
  #include "timevar.h"
  
  /* Dump file and flags.  */
- #if defined ENABLE_CHECKING
  static FILE *dump_file;
  static int dump_flags;
- #endif
  
  /* The main entry into loop optimization pass.  PHASE indicates which dump file
     from the DUMP_FILES array to use when dumping debugging information.
--- 33,44 ----
  #include "tree-flow.h"
  #include "tree-dump.h"
  #include "timevar.h"
+ #include "cfgloop.h"
+ #include "tree-inline.h"
  
  /* Dump file and flags.  */
  static FILE *dump_file;
  static int dump_flags;
  
  /* The main entry into loop optimization pass.  PHASE indicates which dump file
     from the DUMP_FILES array to use when dumping debugging information.
*************** tree_ssa_loop_opt (tree fndecl ATTRIBUTE
*** 68,71 ****
--- 68,226 ----
        dump_end (phase, dump_file);
      }
  #endif
+ }
+ 
+ /* Checks whether the STMT is a call, and if so, returns the call_expr.  */
+ static tree
+ call_expr_p (tree stmt)
+ {
+   if (TREE_CODE (stmt) == MODIFY_EXPR)
+     stmt = TREE_OPERAND (stmt, 1);
+ 
+   return TREE_CODE (stmt) == CALL_EXPR ? stmt : NULL_TREE;
+ }
+ 
+ /* Check whether we should duplicate header of LOOP.  At most *LIMIT
+    instructions should be duplicated, limit is decreased by the actual
+    amount.  */
+ 
+ static bool
+ should_duplicate_loop_header_p (struct loop *loop, int *limit)
+ {
+   block_stmt_iterator bsi;
+   basic_block header = loop->header;
+   tree last;
+ 
+   if (!header->succ)
+     abort ();
+   if (!header->succ->succ_next)
+     return false;
+   if (header->succ->succ_next->succ_next)
+     return false;
+   if (flow_bb_inside_loop_p (loop, header->succ->dest)
+       && flow_bb_inside_loop_p (loop, header->succ->succ_next->dest))
+     return false;
+ 
+   last = last_stmt (header);
+   if (TREE_CODE (last) != COND_EXPR)
+     return false;
+ 
+   /* Aproximately copy the conditions that used to be used in jump.c --
+      at most 20 insns and no calls.  */
+   for (bsi = bsi_start (header); !bsi_end_p (bsi); bsi_next (&bsi))
+     {
+       last = bsi_stmt (bsi);
+ 
+       if (TREE_CODE (last) == LABEL_EXPR)
+ 	continue;
+ 
+       if (call_expr_p (last))
+ 	return false;
+ 
+       *limit -= estimate_num_insns (last);
+       if (*limit < 0)
+ 	return false;
+     }
+ 
+   return true;
+ }
+ 
+ /* For all loops, copy the condition at the end of the loop body in front
+    of the loop.  PHASE indicates which dump file from the DUMP_FILES array
+    to use when dumping debugging information.  FNDECL is the current function
+    decl.  */
+ 
+ void
+ copy_loop_headers (tree fndecl, enum tree_dump_index phase)
+ {
+   struct loops *loops;
+   unsigned i;
+   struct loop *loop;
+   basic_block header_copy, preheader, new_header;
+   edge preheader_edge, succ_in_loop;
+ 
+   timevar_push (TV_TREE_LOOP);
+ 
+   loops = loop_optimizer_init (dump_file);
+   if (!loops)
+     {
+       timevar_pop (TV_TREE_LOOP);
+       return;
+     }
+   
+   dump_file = dump_begin (phase, &dump_flags);
+ 
+   /* We are not going need or update dominators.  */
+   free_dominance_info (loops->cfg.dom);
+   loops->cfg.dom = NULL;
+ 
+   create_preheaders (loops, CP_SIMPLE_PREHEADERS);
+ 
+   /* We do not try to keep the information about irreductible regions
+      up-to-date.  */
+   loops->state &= ~LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS;
+ 
+ #ifdef ENABLE_CHECKING
+   verify_loop_structure (loops);
+ #endif
+ 
+   for (i = 1; i < loops->num; i++)
+     {
+       /* Copy at most 20 insns.  */
+       int limit = 20;
+ 
+       loop = loops->parray[i];
+ 
+       /* Iterate the header copying up to limit; this takes care of the cases
+ 	 like while (a && b) {...}, where we want to have both of the conditions
+ 	 copied.  */
+       while (should_duplicate_loop_header_p (loop, &limit))
+ 	{
+ 	  preheader_edge = loop_preheader_edge (loop);
+ 	  preheader = preheader_edge->src;
+ 
+ 	  /* Find a successor of header that is inside a loop; i.e. the new
+ 	     header after the condition is copied.  */
+ 	  if (flow_bb_inside_loop_p (loop, loop->header->succ->dest))
+ 	    succ_in_loop = loop->header->succ;
+ 	  else
+ 	    succ_in_loop = loop->header->succ->succ_next;
+ 
+ 	  /* But if it has more than one predecessor, split the edge so that
+ 	     we do not create loops with multiple latch edges.  */
+ 	  if (!succ_in_loop->dest->pred->pred_next)
+ 	    new_header = succ_in_loop->dest;
+ 	  else
+ 	    new_header = loop_split_edge_with (succ_in_loop, NULL, loops);
+ 
+ 	  /* Copy the condition and update the loop structures.  */
+ 	  header_copy = tree_duplicate_bb (loop->header, preheader_edge);
+ 	  add_bb_to_loop (header_copy, preheader->loop_father);
+ 	  loop->latch = loop->header;
+ 	  loop->header = new_header;
+ 
+ 	  /* Ensure that the latch has just a single successor.  */
+ 	  loop_split_edge_with (loop_latch_edge (loop), NULL, loops);
+ 	}
+     }
+ 
+ #ifdef ENABLE_CHECKING
+   verify_loop_structure (loops);
+ #endif
+ 
+   loop_optimizer_finalize (loops,
+ 			   (dump_flags & TDF_DETAILS) ? dump_file : NULL);
+ 
+   timevar_pop (TV_TREE_LOOP);
+ 
+   /* Cleanup here regardless of whether we have done anything, in order to
+      cleanup the blocks created in order to get the loops into a canonical
+      shape.  */
+   cleanup_tree_cfg ();
+ 
+   if (dump_file)
+     {
+       dump_function_to_file (fndecl, dump_file, dump_flags);
+       dump_end (phase, dump_file);
+     }
  }
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.149
diff -c -3 -p -r1.342.2.149 tree.h
*** tree.h	7 Dec 2003 10:07:45 -0000	1.342.2.149
--- tree.h	8 Dec 2003 20:28:03 -0000
*************** enum tree_dump_index
*** 3586,3591 ****
--- 3586,3592 ----
  
    /* Optimization passes.  The ordering and numbering of these phases must
       be the same as the one in optimize_function_tree.  */
+   TDI_copy_headers,
    TDI_ssa_1,
    TDI_thread_jumps,
    TDI_dom_1,
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.152.2.62
diff -c -3 -p -r1.152.2.62 invoke.texi
*** doc/invoke.texi	6 Dec 2003 12:31:28 -0000	1.152.2.62
--- doc/invoke.texi	8 Dec 2003 20:28:04 -0000
*************** in the following sections.
*** 251,256 ****
--- 251,257 ----
  -fdump-tree-optimized@r{[}-@var{n}@r{]} @gol
  -fdump-tree-inlined@r{[}-@var{n}@r{]} @gol
  -fdump-tree-cfg -fdump-tree-dot -fdump-tree-alias @gol
+ -fdump-tree-copy-headers @gol
  -fdump-tree-ssa@r{[}-@var{n}@r{]} -fdump-tree-pre@r{[}-@var{n}@r{]} @gol
  -fdump-tree-ccp@r{[}-@var{n}@r{]} -fdump-tree-dce@r{[}-@var{n}@r{]} @gol
  -fdump-tree-gimple@r{[}-raw@r{]} -fdump-tree-mudflap@r{[}-@var{n}@r{]} @gol
*************** made by appending @file{.cfg} to the sou
*** 3521,3526 ****
--- 3522,3535 ----
  @opindex fdump-tree-dot
  Dump a dot language representation of the control flow graph to a file.  The
  file name is made by appending @file{.dot} to the source file name.
+ 
+ @item copy-headers
+ @opindex fdump-tree-copy-headers
+ Dump each function after copying loop headers.  The file name is made by
+ appending @file{.ch} to the source file name.
+ 
+ Dump the control flow graph of each function to a file.  The file name is
+ made by appending @file{.cfg} to the source file name.
  
  @item ssa
  @opindex fdump-tree-ssa
Index: testsuite/gcc.dg/tree-ssa/20030711-1.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/tree-ssa/Attic/20030711-1.c,v
retrieving revision 1.1.2.4
diff -c -3 -p -r1.1.2.4 20030711-1.c
*** testsuite/gcc.dg/tree-ssa/20030711-1.c	21 Sep 2003 22:14:30 -0000	1.1.2.4
--- testsuite/gcc.dg/tree-ssa/20030711-1.c	8 Dec 2003 20:28:05 -0000
*************** record_component_aliases (type)
*** 42,53 ****
  /* The call to blah can not be eliminated.
  /* { dg-final { scan-tree-dump-times "blah \\(\\)" 1 "dom2" } } */
     
! /* There should be three IF conditionals.  */
! /* { dg-final { scan-tree-dump-times "if " 3 "dom2"} } */
                                                                                  
  /* There should be two loads of type.binfo.  */
  /* { dg-final { scan-tree-dump-times "type\\.binfo" 2 "dom2"} } */
   
! /* There should be three loads of vec.length.  */
! /* { dg-final { scan-tree-dump-times "vec.length" 3 "dom2"} } */
  
--- 42,53 ----
  /* The call to blah can not be eliminated.
  /* { dg-final { scan-tree-dump-times "blah \\(\\)" 1 "dom2" } } */
     
! /* There should be four IF conditionals.  */
! /* { dg-final { scan-tree-dump-times "if " 4 "dom2"} } */
                                                                                  
  /* There should be two loads of type.binfo.  */
  /* { dg-final { scan-tree-dump-times "type\\.binfo" 2 "dom2"} } */
   
! /* There should be four loads of vec.length.  */
! /* { dg-final { scan-tree-dump-times "vec.length" 4 "dom2"} } */
  
Index: testsuite/gcc.dg/tree-ssa/20030714-2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/tree-ssa/Attic/20030714-2.c,v
retrieving revision 1.1.2.2
diff -c -3 -p -r1.1.2.2 20030714-2.c
*** testsuite/gcc.dg/tree-ssa/20030714-2.c	21 Sep 2003 22:14:30 -0000	1.1.2.2
--- testsuite/gcc.dg/tree-ssa/20030714-2.c	8 Dec 2003 20:28:05 -0000
*************** get_alias_set (t)
*** 32,39 ****
      }
  }
  
! /* There should be exactly three IF conditionals if we thread jumps
     properly.  */
! /* { dg-final { scan-tree-dump-times "if " 3 "dom2"} } */
   
  
--- 32,39 ----
      }
  }
  
! /* There should be exactly four IF conditionals if we thread jumps
     properly.  */
! /* { dg-final { scan-tree-dump-times "if " 4 "dom2"} } */
   
  
Index: testsuite/gcc.dg/tree-ssa/copy-headers.c
===================================================================
RCS file: testsuite/gcc.dg/tree-ssa/copy-headers.c
diff -N testsuite/gcc.dg/tree-ssa/copy-headers.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/gcc.dg/tree-ssa/copy-headers.c	8 Dec 2003 20:28:05 -0000
***************
*** 0 ****
--- 1,18 ----
+ /* { dg-do compile } */ 
+ /* { dg-options "-O2 -fdump-tree-dom1-details" } */
+ 
+ extern void link_error (void);
+ 
+ void bla (void)
+ {
+   int i, j = 1;
+ 
+   for (i = 0; i < 100; i++)
+     j = 0;
+ 
+   if (j)
+     link_error ();
+ }
+ 
+ /* There should be no link_error call in the dom1 dump.  */
+ /* { dg-final { scan-tree-dump-times "link_error" 0 "dom1"} } */


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