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]

PATCH to fix exception-handling with loop-unrolling



Currently, exception-handling and loop-unrolling do not play
together nicely at all.  In particular, consider something like:

  for (int i = 0; i < 10; ++i) {
    try {
      f ();
    } catch (...) { 
      g ();
    }
  }

The body of the catch-clause is logically a part of the loop, and, if
the loop is unrolled this piece must be copied, too.  But, since the
instructions for the handler are emitted off to the side (near the
function end), we don't process them at present.  This is badly
broken.  In good cases, we get compile-time crashes; in bad cases, we
get silently generated bad code.

This patch attempts to repair the brokenness.  I believe it to be
correct, the compiler bootstraps, the C++ tests pass with `-O2
-funroll-loops', and the generated assembly looks right for small test
cases.

Much of this patch is straightforward:

  o We no longer need gen_exception_label, since it is now just
    another name for gen_label_rtx.  I removed it.

  o We need to (recursively) descend into catch clauses when
    unrolling loops.  Thus, copy_region and mark_labels were split out
    from copy_loop_body and unroll_loop, so that they could call
    themselves recursively.  And copy_region needs to know whether its
    actually doing the loop or a handler so that it can know whether
    to try to update bivs/givs, etc.  (By the way, does loop check 
    to see whether handlers modify a variable  before deciding it
    is a biv/giv?  If not, that's a bug.)
   
Unfortunately, to accomplish the recursive walks into handlers we have
to know where the *end* of each group of handlers is.  There is no way
to determine this at present.

I added a CODE_LABEL at the end of each group of handlers (which is
marked as reachable whenever the handler is).  Thus, we can scan from
the handler start to these CODE_LABELs.  These additional labels are
only generated if we're unrolling, and they are removed after
unrolling.  These labels are a bit of a hack.  What we really want is
NOTE_INSN_HANDLER_END, but I expect that adding a new kind of note is
going to cause much more widespread effects.
 
May I check this patch in?

-- 
Mark Mitchell 			mark@markmitchell.com
Mark Mitchell Consulting	http://www.markmitchell.com

Wed Dec 16 15:59:17 1998  Mark Mitchell  <mark@markmitchell.com>

	* except.h: Fix typo in commment.
	(func_eh_entry ): Move here from except.c.  
	(duplicate_eh_handlers): Change prototype.
	(rethrow_symbol_map): Likewise.
	(get_eh_region): New function.
	(gen_exception_label): Remove.
	(remove_end_of_handler_labels): New function.
	* integrate.h (duplicate_eh_note): New function.
	* except.c (expand_end_handler): New function.
	(gen_exception_label): Remove.
	(push_eh_entry): Use gen_label_rtx, not gen_exception_label.
	(func_eh_entry): Remove.
	(new_eh_region_entry): Tidy.  Initialize `last_insn'.
	(get_eh_region): Define.
	(get_first_handler): Use it.
	(duplicate_eh_handlers): Duplicate the last_insns, too.  Add
	duplicated labels to exception_handler_lables, if appropriate.
	Use new interface to remapping function.
	(rethrow_symbol_map): Use new interface to remapping functions. 
	(expand_leftover_cleanups): Use expand_end_handler.
	(start_catch_handler): Use gen_label_rtx, not gen_exception_label.
	(expand_end_all_catch): Use expand_end_handler.  Fix comment.
	(output_exception_table): Move comment to proper spot.
	(find_exception_handler_labels): Add last_insn labels, too.
	(remove_end_of_handler_labels): Define.
	(init_eh): Use gen_label_rtx, not gen_exception_label.
	* integrate.c (remap_eh_label_from_labelmap): New function.
	(save_for_inline_eh_labelmap): Use new, non-global variable,
	interface. 
	(save_for_inline_copying): Pass it that way.
	(copy_for_inline): Likewise.
	(eif_eh_map): Remove.
	(expand_inline_function_eh_labelmap): Remove to
	remap_eh_label_from_labelmap, and use new interface.
	(duplicate_eh_note): Break out, and modify, from ...
	(expand_inline_function): Here.
	(copy_rtx_and_substitute): Use new rethrow_symbol_map interface.
	* unroll.c Include except.h.
	(unroll_types): Add UNROLL_NONE.
	(copy_region): New function, broken out from copy_loop_body.
	(mark_labels): New function, broken out from unroll_loop.
	(unroll_loop): Call mark_labels.
	(copy_loop_body): Call copy_region.
	* flow.c (make_edges): Put edges to the last_insn in the handlers,
	too. 
	* toplev.c (rest_of_compilation): Call
	remove_end_of_handler_labels after loop.
	
Index: except.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/except.h,v
retrieving revision 1.26
diff -c -p -r1.26 except.h
*** except.h	1998/12/09 06:15:17	1.26
--- except.h	1998/12/16 23:54:35
*************** extern rtx catch_clauses;
*** 152,157 ****
--- 152,170 ----
  
  #endif
  
+ /* Information about each exception region.  */
+ 
+ struct func_eh_entry 
+ {
+   int range_number;   /* EH region number from EH NOTE insn's */
+   rtx rethrow_label;  /* Label for rethrow */
+   struct handler_info *handlers;
+   rtx last_insn;      /* The last instruction in the last handler.
+ 			 NULL if there are no handlers, if loop
+ 			 unrolling is not being done, and after loop
+ 			 optimization is complete.  */
+ };
+ 
  /* Test: is exception handling turned on? */
  
  extern int doing_eh				       PROTO ((int));
*************** void set_exception_version_code         
*** 163,170 ****
  
  /* A list of handlers asocciated with an exception region. HANDLER_LABEL
     is the the label that control should be transfered to if the data
!    in TYPE_INFO matches an exception. a value of NULL_TREE for TYPE_INFO
!    means This is a cleanup, and must always be called. A value of
     CATCH_ALL_TYPE works like a cleanup, but a call to the runtime matcher
     is still performed to avoid being caught by a different language
     exception. NEXT is a pointer to the next handler for this region. 
--- 176,183 ----
  
  /* A list of handlers asocciated with an exception region. HANDLER_LABEL
     is the the label that control should be transfered to if the data
!    in TYPE_INFO matches an exception.  A value of NULL_TREE for TYPE_INFO
!    means that this is a cleanup, and must always be called. A value of
     CATCH_ALL_TYPE works like a cleanup, but a call to the runtime matcher
     is still performed to avoid being caught by a different language
     exception. NEXT is a pointer to the next handler for this region. 
*************** struct handler_info *get_new_handler    
*** 203,213 ****
  /* Make a duplicate of an exception region by copying all the handlers
     for an exception region. Return the new handler index. */
  
! int duplicate_eh_handlers                       PROTO((int, int, rtx (*)(rtx)));
  
  /* map symbol refs for rethrow */
  
! rtx rethrow_symbol_map                          PROTO((rtx, rtx (*)(rtx)));
  
  /* Is the rethrow label for a region used? */
  
--- 216,230 ----
  /* Make a duplicate of an exception region by copying all the handlers
     for an exception region. Return the new handler index. */
  
! int duplicate_eh_handlers                       PROTO((int, int, 
! 						       rtx (*)(rtx, void *),
! 						       void *));
  
  /* map symbol refs for rethrow */
  
! rtx rethrow_symbol_map                          PROTO((rtx, 
! 						       rtx (*)(rtx, void *),
! 						       void *));
  
  /* Is the rethrow label for a region used? */
  
*************** int rethrow_used                        
*** 217,222 ****
--- 234,243 ----
  
  int eh_region_from_symbol                       PROTO((rtx));
  
+ /* Return the entry for the indicated REGION.  */
+ 
+ struct func_eh_entry *get_eh_region             PROTO((int));
+ 
  /* Get a pointer to the first handler in an exception region's list. */
  
  struct handler_info *get_first_handler          PROTO((int));
*************** extern void init_eh				PROTO((void));
*** 231,240 ****
  
  extern void init_eh_for_function		PROTO((void));
  
- /* Generate an exception label. Use instead of gen_label_rtx */
- 
- extern rtx gen_exception_label                  PROTO((void));
- 
  /* Adds an EH table entry for EH entry number N. Called from
     final_scan_insn for NOTE_INSN_EH_REGION_BEG.  */
  
--- 252,257 ----
*************** extern void find_exception_handler_label
*** 312,317 ****
--- 329,339 ----
  /* Determine if an arbitrary label is an exception label */
  
  extern int is_exception_handler_label           PROTO((int));
+ 
+ /* Remove exception handler labels used to mark the end of handlers
+    when they are no longer needed.  */
+ 
+ extern void remove_end_of_handler_labels        PROTO((void));
  
  /* Performs sanity checking on the check_exception_handler_labels
     list.  */
Index: integrate.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/integrate.h,v
retrieving revision 1.4
diff -c -p -r1.4 integrate.h
*** integrate.h	1998/04/04 17:38:11	1.4
--- integrate.h	1998/12/16 23:54:35
*************** extern void mark_stores PROTO((rtx, rtx)
*** 125,130 ****
--- 125,132 ----
  /* Return the label indicated.  */
  extern rtx get_label_from_map PROTO((struct inline_remap *, int));
  
+ extern rtx duplicate_eh_note PROTO((rtx, struct inline_remap *));
+ 
  /* Set the label indicated.  */
  #define set_label_in_map(MAP, I, X) ((MAP)->label_map[I] = (X))
  
Index: except.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/except.c,v
retrieving revision 1.75
diff -c -p -r1.75 except.c
*** except.c	1998/12/09 07:27:21	1.75
--- except.c	1998/12/16 23:54:38
*************** static void set_insn_eh_region	PROTO((rt
*** 530,535 ****
--- 530,536 ----
  #ifdef DONT_USE_BUILTIN_SETJMP
  static void jumpif_rtx		PROTO((rtx, rtx));
  #endif
+ static void expand_end_handler  PROTO((int));
  
  rtx expand_builtin_return_addr	PROTO((enum built_in_function, int, rtx));
  
*************** top_label_entry (stack)
*** 610,625 ****
    return (*stack)->u.tlabel;
  }
  
- /* get an exception label. These must be on the permanent obstack */
- 
- rtx
- gen_exception_label ()
- {
-   rtx lab;
-   lab = gen_label_rtx ();
-   return lab;
- }
- 
  /* Push a new eh_node entry onto STACK.  */
  
  static void
--- 611,616 ----
*************** push_eh_entry (stack)
*** 629,635 ****
    struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
    struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
  
!   rtx rlab = gen_exception_label ();
    entry->finalization = NULL_TREE;
    entry->label_used = 0;
    entry->exception_handler_label = rlab;
--- 620,626 ----
    struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
    struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
  
!   rtx rlab = gen_label_rtx ();
    entry->finalization = NULL_TREE;
    entry->label_used = 0;
    entry->exception_handler_label = rlab;
*************** receive_exception_label (handler_label)
*** 738,751 ****
  }
  
  
- struct func_eh_entry 
- {
-   int range_number;   /* EH region number from EH NOTE insn's */
-   rtx rethrow_label;  /* Label for rethrow */
-   struct handler_info *handlers;
- };
- 
- 
  /* table of function eh regions */
  static struct func_eh_entry *function_eh_regions = NULL;
  static int num_func_eh_entries = 0;
--- 729,734 ----
*************** new_eh_region_entry (note_eh_region, ret
*** 763,768 ****
--- 746,753 ----
       int note_eh_region;
       rtx rethrow;
  {
+   struct func_eh_entry *fee;
+ 
    if (current_func_eh_entry == num_func_eh_entries) 
      {
        if (num_func_eh_entries == 0)
*************** new_eh_region_entry (note_eh_region, ret
*** 778,790 ****
              realloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries));
          }
      }
!   function_eh_regions[current_func_eh_entry].range_number = note_eh_region;
    if (rethrow == NULL_RTX)
!     function_eh_regions[current_func_eh_entry].rethrow_label = 
!                                           create_rethrow_ref (note_eh_region);
!   else
!     function_eh_regions[current_func_eh_entry].rethrow_label = rethrow;
!   function_eh_regions[current_func_eh_entry].handlers = NULL;
  
    return current_func_eh_entry++;
  }
--- 763,777 ----
              realloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries));
          }
      }
! 
!   /* Initialize the new entry.  */
!   fee = &function_eh_regions[current_func_eh_entry];
!   fee->range_number = note_eh_region;
    if (rethrow == NULL_RTX)
!     rethrow = create_rethrow_ref (note_eh_region);
!   fee->rethrow_label = rethrow;
!   fee->handlers = NULL;
!   fee->last_insn = NULL_RTX;
  
    return current_func_eh_entry++;
  }
*************** find_func_region (insn_region)
*** 944,956 ****
    return -1;
  }
  
  /* Get a pointer to the first handler in an exception region's list. */
  
  struct handler_info *
  get_first_handler (region)
       int region;
  {
!   return function_eh_regions[find_func_region (region)].handlers;
  }
  
  /* Clean out the function_eh_region table and free all memory */
--- 931,952 ----
    return -1;
  }
  
+ /* Return the entry for the indicated REGION.  */
+ 
+ struct func_eh_entry *
+ get_eh_region (region)
+      int region;
+ {
+   return &function_eh_regions[find_func_region (region)];
+ }
+ 
  /* Get a pointer to the first handler in an exception region's list. */
  
  struct handler_info *
  get_first_handler (region)
       int region;
  {
!   return get_eh_region (region)->handlers;
  }
  
  /* Clean out the function_eh_region table and free all memory */
*************** clear_function_eh_region ()
*** 972,1006 ****
  }
  
  /* Make a duplicate of an exception region by copying all the handlers
!    for an exception region. Return the new handler index. The final
!    parameter is a routine which maps old labels to new ones. */
  
  int 
! duplicate_eh_handlers (old_note_eh_region, new_note_eh_region, map)
       int old_note_eh_region, new_note_eh_region;
!      rtx (*map) PARAMS ((rtx));
  {
    struct handler_info *ptr, *new_ptr;
    int new_region, region;
!   rtx tmp;
! 
    region = find_func_region (old_note_eh_region);
    if (region == -1)
      fatal ("Cannot duplicate non-existant exception region.");
  
    /* duplicate_eh_handlers may have been called during a symbol remap. */
    new_region = find_func_region (new_note_eh_region);
    if (new_region != -1)
      return (new_region);
- 
    new_region = new_eh_region_entry (new_note_eh_region, NULL_RTX);
! 
!   ptr = function_eh_regions[region].handlers;
  
!   for ( ; ptr; ptr = ptr->next) 
!     {
!       new_ptr = get_new_handler (map (ptr->handler_label), ptr->type_info);
        add_new_handler (new_region, new_ptr);
      }
  
    return new_region;
--- 968,1030 ----
  }
  
  /* Make a duplicate of an exception region by copying all the handlers
!    for an exception region. Return the new handler index. MAP is a
!    routine which maps old labels to new ones.  DATA is passed to MAP
!    whenever it is called.  */
  
  int 
! duplicate_eh_handlers (old_note_eh_region, new_note_eh_region, map, data)
       int old_note_eh_region, new_note_eh_region;
!      rtx (*map) PARAMS ((rtx, void *));
!      void *data;
  {
    struct handler_info *ptr, *new_ptr;
    int new_region, region;
!   struct func_eh_entry *fee;
!   struct func_eh_entry *new_fee;
!   
    region = find_func_region (old_note_eh_region);
    if (region == -1)
      fatal ("Cannot duplicate non-existant exception region.");
+   fee = &function_eh_regions[region];
  
    /* duplicate_eh_handlers may have been called during a symbol remap. */
    new_region = find_func_region (new_note_eh_region);
    if (new_region != -1)
      return (new_region);
    new_region = new_eh_region_entry (new_note_eh_region, NULL_RTX);
!   new_fee = &function_eh_regions[new_region];
  
!   /* Loop through each of the handlers, duplicating the start labels
!      for each.  */
!   for (ptr = fee->handlers; ptr; ptr = ptr->next) 
!     {
!       /* Create a new handler, duplicating the old handler, and add it
! 	 to the region we're duplicating.  */
!       new_ptr = get_new_handler (map (ptr->handler_label, data), 
! 				 ptr->type_info);
        add_new_handler (new_region, new_ptr);
+ 
+       /* The new label is an exception handler label, so we must add
+ 	 it to the list, if we're maintaining one.  */
+       if (exception_handler_labels)
+ 	exception_handler_labels 
+ 	  = gen_rtx_EXPR_LIST (VOIDmode,
+ 			       new_ptr->handler_label, 
+ 			       exception_handler_labels);
+     }
+ 
+   /* Remap the last instruction in the handler.  */
+   if (fee->last_insn)
+     {
+       new_fee->last_insn = map (fee->last_insn, data);
+ 
+       /* That new label is an exception handler label, too.  */
+       if (exception_handler_labels)
+ 	exception_handler_labels 
+ 	  = gen_rtx_EXPR_LIST (VOIDmode,
+ 			       new_fee->last_insn,
+ 			       exception_handler_labels);
      }
  
    return new_region;
*************** eh_region_from_symbol (sym)
*** 1023,1035 ****
  
  
  /* When inlining/unrolling, we have to map the symbols passed to
!    __rethrow as well. This performs the remap. If a symbol isn't foiund,
!    the original one is returned. This is not an efficient routine,
!    so don't call it on everything!! */
  rtx 
! rethrow_symbol_map (sym, map)
       rtx sym;
!      rtx (*map) PARAMS ((rtx));
  {
    int x, y;
    for (x = 0; x < current_func_eh_entry; x++)
--- 1047,1061 ----
  
  
  /* When inlining/unrolling, we have to map the symbols passed to
!    __rethrow as well. This performs the remap. If a symbol isn't
!    found, the original one is returned. This is not an efficient
!    routine, so don't call it on everything!!  DATA is passed to MAP
!    whenever it is called.  */
  rtx 
! rethrow_symbol_map (sym, map, data)
       rtx sym;
!      rtx (*map) PARAMS ((rtx, void *));
!      void *data;
  {
    int x, y;
    for (x = 0; x < current_func_eh_entry; x++)
*************** rethrow_symbol_map (sym, map)
*** 1038,1049 ****
          /* We've found the original region, now lets determine which region
             this now maps to. */
          rtx l1 = function_eh_regions[x].handlers->handler_label;
!         rtx l2 = map (l1);
          y = CODE_LABEL_NUMBER (l2); /* This is the new region number */
          x = find_func_region (y);  /* Get the new permanent region */
          if (x == -1)  /* Hmm, Doesn't exist yet */
            {
!             x = duplicate_eh_handlers (CODE_LABEL_NUMBER (l1), y, map);
              /* Since we're mapping it, it must be used. */
              SYMBOL_REF_USED (function_eh_regions[x].rethrow_label) = 1;
            }
--- 1064,1076 ----
          /* We've found the original region, now lets determine which region
             this now maps to. */
          rtx l1 = function_eh_regions[x].handlers->handler_label;
!         rtx l2 = map (l1, data);
          y = CODE_LABEL_NUMBER (l2); /* This is the new region number */
          x = find_func_region (y);  /* Get the new permanent region */
          if (x == -1)  /* Hmm, Doesn't exist yet */
            {
!             x = duplicate_eh_handlers (CODE_LABEL_NUMBER (l1), y, map,
! 				       data);
              /* Since we're mapping it, it must be used. */
              SYMBOL_REF_USED (function_eh_regions[x].rethrow_label) = 1;
            }
*************** expand_internal_throw ()
*** 1668,1673 ****
--- 1695,1728 ----
    emit_throw ();
  }
  
+ /* Emit a CODE_LABEL to mark the end of the exception region indicated
+    by REGION.  */
+ 
+ static void
+ expand_end_handler (region)
+      int region;
+ {
+   if (!flag_unroll_loops)
+     /* For now, at least, we only need to know where the end of a
+        region is when unrolling loops.  */
+     ;
+   else
+     {
+       /* We don't really need a CODE_LABEL here; nothing will ever
+ 	 jump to it.  Ideally, we could use a new kind of NOTE, say
+ 	 NOTE_INSN_EH_HANDLER_END.  But, then we would have to teach
+ 	 the entire compiler about those notes, and we would need to
+ 	 teach the remappers to deal with these as well.  So, we just
+ 	 use a CODE_LABEL.  We mark these labels as part of the
+ 	 exception_handler_labels list so that they will not be
+ 	 removed, but remove them from the list when they are
+ 	 no longer needed so that they can be pruned from the
+ 	 instruction stream at that point.  */
+       rtx label = emit_label (gen_label_rtx ());
+       function_eh_regions[region].last_insn = label;
+     }
+ }
+ 
  /* Called from expand_exception_blocks and expand_end_catch_block to
     emit any pending handlers/cleanups queued from expand_eh_region_end.  */
  
*************** expand_leftover_cleanups ()
*** 1679,1684 ****
--- 1734,1740 ----
    while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
      {
        rtx prev;
+       int region;
  
        /* A leftover try block. Shouldn't be one here.  */
        if (entry->finalization == integer_zero_node)
*************** expand_leftover_cleanups ()
*** 1689,1697 ****
        receive_exception_label (entry->exception_handler_label);
  
        /* register a handler for this cleanup region */
!       add_new_handler (
!         find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)), 
!         get_new_handler (entry->exception_handler_label, NULL));
  
        /* And now generate the insns for the handler.  */
        expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
--- 1745,1755 ----
        receive_exception_label (entry->exception_handler_label);
  
        /* register a handler for this cleanup region */
!       region = find_func_region (CODE_LABEL_NUMBER 
! 				 (entry->exception_handler_label));
!       add_new_handler (region, 
! 		       get_new_handler (entry->exception_handler_label, 
! 					NULL));
  
        /* And now generate the insns for the handler.  */
        expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
*************** expand_leftover_cleanups ()
*** 1702,1707 ****
--- 1760,1768 ----
  	   the end of the handler.  */
  	expand_rethrow (entry->outer_context);
  
+       /* Now, mark the end the handler.  */
+       expand_end_handler (region);
+ 
        do_pending_stack_adjust ();
        free (entry);
      }
*************** start_catch_handler (rtime)
*** 1736,1742 ****
  
    /* If we've already issued this label, pick a new one */
    if (catchstack.top->entry->label_used)
!     handler_label = gen_exception_label ();
    else
      catchstack.top->entry->label_used = 1;
  
--- 1797,1803 ----
  
    /* If we've already issued this label, pick a new one */
    if (catchstack.top->entry->label_used)
!     handler_label = gen_label_rtx ();
    else
      catchstack.top->entry->label_used = 1;
  
*************** start_catch_handler (rtime)
*** 1758,1764 ****
  
        if (catchstack.top->entry->false_label != NULL_RTX)
          fatal ("Compiler Bug: Never issued previous false_label");
!       catchstack.top->entry->false_label = gen_exception_label ();
  
        rtime_address = expand_expr (rtime, NULL_RTX, Pmode, EXPAND_INITIALIZER);
        rtime_address = force_reg (Pmode, rtime_address);
--- 1819,1825 ----
  
        if (catchstack.top->entry->false_label != NULL_RTX)
          fatal ("Compiler Bug: Never issued previous false_label");
!       catchstack.top->entry->false_label = gen_label_rtx ();
  
        rtime_address = expand_expr (rtime, NULL_RTX, Pmode, EXPAND_INITIALIZER);
        rtime_address = force_reg (Pmode, rtime_address);
*************** expand_end_all_catch ()
*** 1902,1915 ****
--- 1963,1989 ----
  {
    rtx new_catch_clause;
    struct eh_entry *entry;
+   int region;
  
    if (! doing_eh (1))
      return;
  
    /* Dequeue the current catch clause region. */
    entry = pop_eh_entry (&catchstack);
+   region = find_func_region (CODE_LABEL_NUMBER 
+ 			     (entry->exception_handler_label));
    free (entry);
  
+   /* Code to throw out to outer context, if we fall off end of catch
+      handlers.  This is rethrow (Lresume, same id, same obj) in the
+      documentation. We use Lresume because we know that it will throw
+      to the correct context.
+ 
+      In other words, if the catch handler doesn't exit or return, we
+      do a "throw" (using the address of Lresume as the point being
+      thrown from) so that the outer EH region can then try to process
+      the exception.  */
+ 
    if (! exceptions_via_longjmp)
      {
        rtx outer_context = ehstack.top->entry->outer_context;
*************** expand_end_all_catch ()
*** 1923,1938 ****
      }
    else 
      expand_rethrow (NULL_RTX);
- 
-   /* Code to throw out to outer context, if we fall off end of catch
-      handlers.  This is rethrow (Lresume, same id, same obj) in the
-      documentation. We use Lresume because we know that it will throw
-      to the correct context.
  
!      In other words, if the catch handler doesn't exit or return, we
!      do a "throw" (using the address of Lresume as the point being
!      thrown from) so that the outer EH region can then try to process
!      the exception.  */
  
    /* Now we have the complete catch sequence.  */
    new_catch_clause = get_insns ();
--- 1997,2005 ----
      }
    else 
      expand_rethrow (NULL_RTX);
  
!   /* Terminate the handler.  */
!   expand_end_handler (region);
  
    /* Now we have the complete catch sequence.  */
    new_catch_clause = get_insns ();
*************** output_exception_table_entry (file, n)
*** 2169,2176 ****
      }
  }
  
- /* Output the exception table if we have and need one.  */
- 
  static short language_code = 0;
  static short version_code = 0; 
  
--- 2236,2241 ----
*************** set_exception_version_code (code)
*** 2190,2195 ****
--- 2255,2261 ----
    version_code = code;
  }
  
+ /* Output the exception table if we have and need one.  */
  
  void
  output_exception_table ()
*************** find_exception_handler_labels ()
*** 2315,2343 ****
    /* If we aren't doing exception handling, there isn't much to check.  */
    if (! doing_eh (0))
      return;
- 
-   /* For each start of a region, add its label to the list.  */
  
    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
!     {
!       struct handler_info* ptr;
!       if (GET_CODE (insn) == NOTE
! 	  && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
! 	{
!           ptr = get_first_handler (NOTE_BLOCK_NUMBER (insn));
!           for ( ; ptr; ptr = ptr->next) 
!             {
!               /* make sure label isn't in the list already */
!               rtx x;
!               for (x = exception_handler_labels; x; x = XEXP (x, 1))
!                 if (XEXP (x, 0) == ptr->handler_label)
!                   break;
!               if (! x)
!                 exception_handler_labels = gen_rtx_EXPR_LIST (VOIDmode,
!                                ptr->handler_label, exception_handler_labels);
!             }
! 	}
!     }
  }
  
  /* Return a value of 1 if the parameter label number is an exception handler
--- 2381,2419 ----
    /* If we aren't doing exception handling, there isn't much to check.  */
    if (! doing_eh (0))
      return;
  
+   /* Go through the INSN chain, finding each EH region in turn.  */
    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
!     if (GET_CODE (insn) == NOTE
! 	&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
!       {
! 	struct handler_info* ptr;
! 	struct func_eh_entry *fee
! 	  = get_eh_region (NOTE_BLOCK_NUMBER (insn));
! 
! 	/* Add the CODE_LABEL that begins each of the handlers.  */
! 	for (ptr = fee->handlers ; ptr; ptr = ptr->next) 
! 	  {
! 	    /* make sure label isn't in the list already */
! 	    rtx x;
! 	    for (x = exception_handler_labels; x; x = XEXP (x, 1))
! 	      if (XEXP (x, 0) == ptr->handler_label)
! 		break;
! 	    if (! x)
! 	      exception_handler_labels 
! 		= gen_rtx_EXPR_LIST (VOIDmode,
! 				     ptr->handler_label, 
! 				     exception_handler_labels);
! 	  }
! 
! 	/* And add the CODE_LABEL that marks the end of the last
! 	   handler.  */
! 	if (fee->last_insn != NULL_RTX)
! 	  exception_handler_labels 
! 	    = gen_rtx_EXPR_LIST (VOIDmode,
! 				 fee->last_insn,
! 				 exception_handler_labels);
!       }
  }
  
  /* Return a value of 1 if the parameter label number is an exception handler
*************** is_exception_handler_label (lab)
*** 2354,2359 ****
--- 2430,2474 ----
    return 0;
  }
  
+ /* Remove exception handler labels used to mark the end of handlers
+    when they are no longer needed.  */
+ 
+ void
+ remove_end_of_handler_labels ()
+ {
+   int i;
+ 
+   /* We count backwards through this loop because the entries for
+      higher number regions should be on the front of the
+      exception_handler_labels list.  Thus, even though this loop loops
+      like it's O(N^2) it should really be only O(N).  */
+   for (i = current_func_eh_entry - 1; i >= 0; --i)
+     if (function_eh_regions[i].last_insn)
+       {
+ 	/* Remove this label from the handler labels.  */
+ 	rtx *x;
+ 	for (x = &exception_handler_labels ; *x ; x = &XEXP (*x, 1))
+ 	  if (XEXP (*x, 0) == function_eh_regions[i].last_insn)
+ 	    {
+ 	      *x = XEXP (*x, 1);
+ 	      break;
+ 	    }
+ 
+ 	/* This label is no longer used.  We don't just delete it,
+ 	   though; flow will probably have decided that this
+ 	   instruction consists of a basic block all its own, and when
+ 	   schedule_insns tries to insert a note after the end of the
+ 	   block, emit_note_after will abort, since the instruction
+ 	   being inserted after is delted.  Perhaps jump_optimize will
+ 	   remove the label, now that it is no longer used.  */
+ 	LABEL_NUSES (function_eh_regions[i].last_insn) = 0;
+ 
+ 	/* Clear this out; no-one should be looking at these any
+ 	   more.  */
+ 	function_eh_regions[i].last_insn = NULL_RTX;
+       }
+ }
+ 
  /* Perform sanity checking on the exception_handler_labels list.
  
     Can be called after find_exception_handler_labels is called to
*************** void
*** 2395,2401 ****
  init_eh ()
  {
    first_rethrow_symbol = create_rethrow_ref (0);
!   final_rethrow = gen_exception_label ();
    last_rethrow_symbol = create_rethrow_ref (CODE_LABEL_NUMBER (final_rethrow));
  }
  
--- 2510,2516 ----
  init_eh ()
  {
    first_rethrow_symbol = create_rethrow_ref (0);
!   final_rethrow = gen_label_rtx ();
    last_rethrow_symbol = create_rethrow_ref (CODE_LABEL_NUMBER (final_rethrow));
  }
  
Index: integrate.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/integrate.c,v
retrieving revision 1.42
diff -c -p -r1.42 integrate.c
*** integrate.c	1998/12/15 11:56:34	1.42
--- integrate.c	1998/12/16 23:54:40
*************** static void process_reg_param		PROTO((st
*** 85,90 ****
--- 85,91 ----
  
  void set_decl_abstract_flags		PROTO((tree, int));
  static tree copy_and_set_decl_abstract_origin PROTO((tree));
+ static rtx remap_eh_label_from_labelmap PROTO((rtx, void *));
  
  /* Returns the Ith entry in the label_map contained in MAP.  If the
     Ith entry has not yet been set, return a fresh label.  This function
*************** static int in_nonparm_insns;
*** 263,273 ****
  /* subroutines passed to duplicate_eh_handlers to map exception labels */
  
  static rtx 
! save_for_inline_eh_labelmap (label)
       rtx label;
  {
    int index = CODE_LABEL_NUMBER (label);
!   return label_map[index];
  }
  
  /* Subroutine for `save_for_inline{copying,nocopy}'.  Performs initialization
--- 264,275 ----
  /* subroutines passed to duplicate_eh_handlers to map exception labels */
  
  static rtx 
! save_for_inline_eh_labelmap (label, data)
       rtx label;
+      void *data;
  {
    int index = CODE_LABEL_NUMBER (label);
!   return ((rtx *) data)[index];
  }
  
  /* Subroutine for `save_for_inline{copying,nocopy}'.  Performs initialization
*************** save_for_inline_copying (fndecl)
*** 673,679 ****
                /* we have to duplicate the handlers for the original */
                if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG) 
                  duplicate_eh_handlers (NOTE_BLOCK_NUMBER (copy), new_region,
!                                        save_for_inline_eh_labelmap);
                  
  	      /* We have to forward these both to match the new exception
  		 region.  */
--- 675,682 ----
                /* we have to duplicate the handlers for the original */
                if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG) 
                  duplicate_eh_handlers (NOTE_BLOCK_NUMBER (copy), new_region,
!                                        save_for_inline_eh_labelmap,
! 				       label_map);
                  
  	      /* We have to forward these both to match the new exception
  		 region.  */
*************** copy_for_inline (orig)
*** 1076,1082 ****
      case SYMBOL_REF:
        if (! SYMBOL_REF_NEED_ADJUST (x))
          return x;
!       return rethrow_symbol_map (x, save_for_inline_eh_labelmap);
  
      case CONST_DOUBLE:
        /* We have to make a new CONST_DOUBLE to ensure that we account for
--- 1079,1085 ----
      case SYMBOL_REF:
        if (! SYMBOL_REF_NEED_ADJUST (x))
          return x;
!       return rethrow_symbol_map (x, save_for_inline_eh_labelmap, label_map);
  
      case CONST_DOUBLE:
        /* We have to make a new CONST_DOUBLE to ensure that we account for
*************** process_reg_param (map, loc, copy)
*** 1337,1353 ****
    map->reg_map[REGNO (loc)] = copy;
  }
  
! /* Used by duplicate_eh_handlers to map labels for the exception table */
! static struct inline_remap *eif_eh_map;
  
  static rtx 
! expand_inline_function_eh_labelmap (label)
     rtx label;
  {
    int index = CODE_LABEL_NUMBER (label);
!   return get_label_from_map (eif_eh_map, index);
  }
  
  /* Integrate the procedure defined by FNDECL.  Note that this function
     may wind up calling itself.  Since the static variables are not
     reentrant, we do not assign them until after the possibility
--- 1340,1395 ----
    map->reg_map[REGNO (loc)] = copy;
  }
  
! /* Use the DATA (which is really a `struct inline_remap*') to remap
!    the indicated EH label.  Passed to duplicate_eh_handlers.  */
  
  static rtx 
! remap_eh_label_from_labelmap (label, data)
     rtx label;
+    void *data;
  {
    int index = CODE_LABEL_NUMBER (label);
!   return get_label_from_map ((struct inline_remap *) data, index);
  }
  
+ /* The indicated EH_NOTE is a NOTE_INSN_EH_REGION_BEG or
+    NOTE_INSN_EH_REGION_END note that is being copied as part of the
+    duplication of some larger piece of code (e.g., during loop
+    unrolling or function inlining.)  We must create a new, but
+    equivalent exception region, duplicating the handlers as
+    appropriate.  MAP is the table we are using to remap labels as
+    needed.
+ 
+    Returns a new NOTE_INSN corresponding to EH_NOTE.  */
+ 
+ rtx
+ duplicate_eh_note (eh_note, map)
+      rtx eh_note;
+      struct inline_remap *map;
+ {
+   rtx copy;
+   rtx label;
+ 
+   /* Figure out what new CODE_LABEL corresponds to the old exception
+      region.  */
+   label = get_label_from_map (map, NOTE_BLOCK_NUMBER (eh_note));
+ 
+   /* If this is the start of the region, copy the handlers.  */
+   if (NOTE_LINE_NUMBER (eh_note) == NOTE_INSN_EH_REGION_BEG)
+     duplicate_eh_handlers (NOTE_BLOCK_NUMBER (eh_note),
+ 			   CODE_LABEL_NUMBER (label),
+ 			   remap_eh_label_from_labelmap,
+ 			   map);
+ 
+   /* Now, create the new note.  */
+   copy = emit_note (NOTE_SOURCE_FILE (eh_note), 
+ 		    NOTE_LINE_NUMBER (eh_note));
+   /* And update its block number so as to indicate the copied region.  */
+   NOTE_BLOCK_NUMBER (copy) = CODE_LABEL_NUMBER (label);
+ 
+   return copy;
+ }
+ 
  /* Integrate the procedure defined by FNDECL.  Note that this function
     may wind up calling itself.  Since the static variables are not
     reentrant, we do not assign them until after the possibility
*************** expand_inline_function (fndecl, parms, t
*** 2044,2085 ****
  	  break;
  
  	case NOTE:
! 	  /* It is important to discard function-end and function-beg notes,
! 	     so we have only one of each in the current function.
! 	     Also, NOTE_INSN_DELETED notes aren't useful (save_for_inline
! 	     deleted these in the copy used for continuing compilation,
! 	     not the copy used for inlining).  */
! 	  if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END
! 	      && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG
! 	      && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED)
! 	    {
! 	      copy = emit_note (NOTE_SOURCE_FILE (insn),
! 				NOTE_LINE_NUMBER (insn));
! 	      if (copy
! 		  && (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG
! 		      || NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END))
! 		{
! 		  rtx label
! 		    = get_label_from_map (map, NOTE_BLOCK_NUMBER (copy));
! 
!                   /* we have to duplicate the handlers for the original */
!                   if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
!                     {
!                       /* We need to duplicate the handlers for the EH region
!                          and we need to indicate where the label map is */
!                       eif_eh_map = map;
!                       duplicate_eh_handlers (NOTE_BLOCK_NUMBER (copy), 
!                                              CODE_LABEL_NUMBER (label),
!                                              expand_inline_function_eh_labelmap);
!                     }
! 
! 		  /* We have to forward these both to match the new exception
! 		     region.  */
! 		  NOTE_BLOCK_NUMBER (copy) = CODE_LABEL_NUMBER (label);
! 		}
! 	    }
! 	  else
  	    copy = 0;
  	  break;
  
  	default:
--- 2086,2110 ----
  	  break;
  
  	case NOTE:
! 	  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END
! 	      || NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
! 	    /* It is important to discard function-end and function-beg notes,
! 	       so we have only one of each in the current function.  */
! 	    copy = 0;
! 	  else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
! 	    /* Also, NOTE_INSN_DELETED notes aren't useful
! 	       (save_for_inline deleted these in the copy used for
! 	       continuing compilation, not the copy used for
! 	       inlining).  */ 
  	    copy = 0;
+ 	  else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
+ 		   || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
+ 	    /* Remap the exception region.  */
+ 	    copy = duplicate_eh_note (insn, map);
+ 	  else
+ 	    /* Just copy the note.  */
+ 	    copy = emit_note (NOTE_SOURCE_FILE (insn),
+ 			      NOTE_LINE_NUMBER (insn));
  	  break;
  
  	default:
*************** copy_rtx_and_substitute (orig, map)
*** 2548,2560 ****
  								   map)),
  			 0);
  	}
!       else
!         if (SYMBOL_REF_NEED_ADJUST (orig)) 
!           {
!             eif_eh_map = map;
!             return rethrow_symbol_map (orig, 
!                                        expand_inline_function_eh_labelmap);
!           }
  
        return orig;
  
--- 2573,2581 ----
  								   map)),
  			 0);
  	}
!       else if (SYMBOL_REF_NEED_ADJUST (orig)) 
! 	return rethrow_symbol_map (orig, remap_eh_label_from_labelmap,
! 				   map);
  
        return orig;
  
Index: unroll.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/unroll.c,v
retrieving revision 1.38
diff -c -p -r1.38 unroll.c
*** unroll.c	1998/12/15 20:31:18	1.38
--- unroll.c	1998/12/16 23:54:43
*************** struct _factor { int factor, count; } fa
*** 144,150 ****
        
  /* Describes the different types of loop unrolling performed.  */
  
! enum unroll_types { UNROLL_COMPLETELY, UNROLL_MODULO, UNROLL_NAIVE };
  
  #include "config.h"
  #include "system.h"
--- 144,164 ----
        
  /* Describes the different types of loop unrolling performed.  */
  
! enum unroll_types { 
!   UNROLL_COMPLETELY, /* Completely unroll the loop.  At the end, there
! 			will be no loop; just a series of copies of
! 			the loop body.  Obviously, we can do this only
! 			if we can determine the number of iterations
! 			that will occur.  */
!   UNROLL_MODULO,     /* Unroll the loop N times for some N dividing the
! 			number of iterations.  */
!   UNROLL_NAIVE,      /* Unroll the loop some number of times, but not
! 			based on any information about the number of
! 			iterations.  */
!   UNROLL_NONE        /* Used only to indicate to copy_region that the
! 			region copied is not being unrolled; rather it
! 			is some other piece of code outside the loop.  */
! };
  
  #include "config.h"
  #include "system.h"
*************** enum unroll_types { UNROLL_COMPLETELY, U
*** 157,162 ****
--- 171,177 ----
  #include "expr.h"
  #include "loop.h"
  #include "toplev.h"
+ #include "except.h"
  
  /* This controls which loops are unrolled, and by how much we unroll
     them.  */
*************** static int reg_dead_after_loop PROTO((rt
*** 203,209 ****
--- 218,291 ----
  static rtx fold_rtx_mult_add PROTO((rtx, rtx, rtx, enum machine_mode));
  static int verify_addresses PROTO((struct induction *, rtx, int));
  static rtx remap_split_bivs PROTO((rtx));
+ static void copy_region PROTO((rtx, rtx, struct inline_remap*,
+ 			       rtx, int, enum unroll_types, rtx));
+ static void mark_labels PROTO((rtx, rtx, char*, struct inline_remap*));
+ 
+ /* Look at all the instructions in the range [START, END).  If one of
+    these instructions is a CODE_LABEL with CODE_LABEL_NUMBER `i', then
+    set LOCAL_LABEL[i].  Furthermore, setup the LABEL_MAP in MAP to map any
+    labels mentioned, but located, in the range to themselves.  Recurse
+    into exception handlers in this range as well; they are logically a
+    part of the sequence.  */
  
+ static void
+ mark_labels (start, end, local_label, map)
+      rtx start;
+      rtx end;
+      char *local_label;
+      struct inline_remap *map;
+ {
+   rtx insn;
+ 
+   for (insn = start; insn != end; insn = NEXT_INSN (insn))
+     {
+       rtx note;
+ 
+       if (GET_CODE (insn) == CODE_LABEL)
+ 	local_label[CODE_LABEL_NUMBER (insn)] = 1;
+       else if (GET_CODE (insn) == JUMP_INSN)
+ 	{
+ 	  if (JUMP_LABEL (insn))
+ 	    set_label_in_map (map,
+ 			      CODE_LABEL_NUMBER (JUMP_LABEL (insn)),
+ 			      JUMP_LABEL (insn));
+ 	  else if (GET_CODE (PATTERN (insn)) == ADDR_VEC
+ 		   || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
+ 	    {
+ 	      rtx pat = PATTERN (insn);
+ 	      int diff_vec_p = GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC;
+ 	      int len = XVECLEN (pat, diff_vec_p);
+ 	      rtx label;
+ 	      int i;
+ 
+ 	      for (i = 0; i < len; i++)
+ 		{
+ 		  label = XEXP (XVECEXP (pat, diff_vec_p, i), 0);
+ 		  set_label_in_map (map,
+ 				    CODE_LABEL_NUMBER (label),
+ 				    label);
+ 		}
+ 	    }
+ 	}
+       else if ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)))
+ 	set_label_in_map (map, CODE_LABEL_NUMBER (XEXP (note, 0)),
+ 			  XEXP (note, 0));
+       else if (GET_CODE (insn) == NOTE
+ 	       && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+ 	{
+ 	  /* Recurse into the exception handler.  */
+ 	  struct func_eh_entry* fee;
+ 
+ 	  fee = get_eh_region (NOTE_BLOCK_NUMBER (insn));
+ 	  if (fee->handlers)
+ 	    mark_labels (fee->handlers->handler_label,
+ 			 NEXT_INSN (fee->last_insn),
+ 			 local_label, map);
+ 	}
+     }
+ }
+ 
  /* Try to unroll one loop and split induction variables in the loop.
  
     The loop is described by the arguments LOOP_END, INSN_COUNT, and
*************** unroll_loop (loop_end, insn_count, loop_
*** 699,739 ****
       If they happen to be local their label_map entries will be overwritten
       before the loop body is copied.  The label_map entries for local labels
       will be set to a different value each time the loop body is copied.  */
  
-   for (insn = copy_start; insn != loop_end; insn = NEXT_INSN (insn))
-     {
-       rtx note;
- 
-       if (GET_CODE (insn) == CODE_LABEL)
- 	local_label[CODE_LABEL_NUMBER (insn)] = 1;
-       else if (GET_CODE (insn) == JUMP_INSN)
- 	{
- 	  if (JUMP_LABEL (insn))
- 	    set_label_in_map (map,
- 			      CODE_LABEL_NUMBER (JUMP_LABEL (insn)),
- 			      JUMP_LABEL (insn));
- 	  else if (GET_CODE (PATTERN (insn)) == ADDR_VEC
- 		   || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
- 	    {
- 	      rtx pat = PATTERN (insn);
- 	      int diff_vec_p = GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC;
- 	      int len = XVECLEN (pat, diff_vec_p);
- 	      rtx label;
- 
- 	      for (i = 0; i < len; i++)
- 		{
- 		  label = XEXP (XVECEXP (pat, diff_vec_p, i), 0);
- 		  set_label_in_map (map,
- 				    CODE_LABEL_NUMBER (label),
- 				    label);
- 		}
- 	    }
- 	}
-       else if ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)))
- 	set_label_in_map (map, CODE_LABEL_NUMBER (XEXP (note, 0)),
- 			  XEXP (note, 0));
-     }
- 
    /* Allocate space for the insn map.  */
  
    map->insn_map = (rtx *) alloca (max_insnno * sizeof (rtx));
--- 781,788 ----
       If they happen to be local their label_map entries will be overwritten
       before the loop body is copied.  The label_map entries for local labels
       will be set to a different value each time the loop body is copied.  */
+   mark_labels (copy_start, loop_end, local_label, map);
  
    /* Allocate space for the insn map.  */
  
    map->insn_map = (rtx *) alloca (max_insnno * sizeof (rtx));
*************** final_reg_note_copy (notes, map)
*** 1636,1681 ****
        XEXP (note, 0) = map->insn_map[INSN_UID (XEXP (note, 0))];
  }
  
- /* Copy each instruction in the loop, substituting from map as appropriate.
-    This is very similar to a loop in expand_inline_function.  */
-   
  static void
! copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
! 		unroll_type, start_label, loop_end, insert_before,
! 		copy_notes_from)
       rtx copy_start, copy_end;
       struct inline_remap *map;
       rtx exit_label;
       int last_iteration;
       enum unroll_types unroll_type;
!      rtx start_label, loop_end, insert_before, copy_notes_from;
  {
!   rtx insn, pattern;
!   rtx set, tem, copy;
!   int dest_reg_was_split, i;
  #ifdef HAVE_cc0
    rtx cc0_insn = 0;
  #endif
-   rtx final_label = 0;
    rtx giv_inc, giv_dest_reg, giv_src_reg;
  
-   /* If this isn't the last iteration, then map any references to the
-      start_label to final_label.  Final label will then be emitted immediately
-      after the end of this loop body if it was ever used.
- 
-      If this is the last iteration, then map references to the start_label
-      to itself.  */
-   if (! last_iteration)
-     {
-       final_label = gen_label_rtx ();
-       set_label_in_map (map, CODE_LABEL_NUMBER (start_label),
- 			final_label); 
-     }
-   else
-     set_label_in_map (map, CODE_LABEL_NUMBER (start_label), start_label);
- 
-   start_sequence ();
-   
    insn = copy_start;
    do
      {
--- 1685,1712 ----
        XEXP (note, 0) = map->insn_map[INSN_UID (XEXP (note, 0))];
  }
  
  static void
! copy_region (copy_start, copy_end, map, exit_label, last_iteration,
! 	     unroll_type, start_label)
       rtx copy_start, copy_end;
       struct inline_remap *map;
       rtx exit_label;
       int last_iteration;
       enum unroll_types unroll_type;
!      rtx start_label;
  {
!   rtx insn;
!   rtx pattern;
!   rtx set;
!   rtx tem;
!   rtx copy;
!   int dest_reg_was_split;
!   int i;
  #ifdef HAVE_cc0
    rtx cc0_insn = 0;
  #endif
    rtx giv_inc, giv_dest_reg, giv_src_reg;
  
    insn = copy_start;
    do
      {
*************** copy_loop_body (copy_start, copy_end, ma
*** 1698,1704 ****
  	     Do this before splitting the giv, since that may map the
  	     SET_DEST to a new register.  */
  	  
! 	  if ((set = single_set (insn))
  	      && GET_CODE (SET_DEST (set)) == REG
  	      && addr_combined_regs[REGNO (SET_DEST (set))])
  	    {
--- 1729,1736 ----
  	     Do this before splitting the giv, since that may map the
  	     SET_DEST to a new register.  */
  	  
! 	  if (unroll_type != UNROLL_NONE
! 	      && (set = single_set (insn))
  	      && GET_CODE (SET_DEST (set)) == REG
  	      && addr_combined_regs[REGNO (SET_DEST (set))])
  	    {
*************** copy_loop_body (copy_start, copy_end, ma
*** 1789,1795 ****
  	  
  	  dest_reg_was_split = 0;
  	  
! 	  if ((set = single_set (insn))
  	      && GET_CODE (SET_DEST (set)) == REG
  	      && splittable_regs[REGNO (SET_DEST (set))])
  	    {
--- 1821,1828 ----
  	  
  	  dest_reg_was_split = 0;
  	  
! 	  if (unroll_type != UNROLL_NONE
! 	      && (set = single_set (insn))
  	      && GET_CODE (SET_DEST (set)) == REG
  	      && splittable_regs[REGNO (SET_DEST (set))])
  	    {
*************** copy_loop_body (copy_start, copy_end, ma
*** 1951,1957 ****
  	  REG_NOTES (copy) = initial_reg_note_copy (REG_NOTES (insn), map);
  
  	  if (JUMP_LABEL (insn) == start_label && insn == copy_end
! 	      && ! last_iteration)
  	    {
  	      /* This is a branch to the beginning of the loop; this is the
  		 last insn being copied; and this is not the last iteration.
--- 1984,1990 ----
  	  REG_NOTES (copy) = initial_reg_note_copy (REG_NOTES (insn), map);
  
  	  if (JUMP_LABEL (insn) == start_label && insn == copy_end
! 	      && (unroll_type == UNROLL_NONE || !last_iteration))
  	    {
  	      /* This is a branch to the beginning of the loop; this is the
  		 last insn being copied; and this is not the last iteration.
*************** copy_loop_body (copy_start, copy_end, ma
*** 2116,2131 ****
  	  break;
  	  
  	case NOTE:
! 	  /* VTOP notes are valid only before the loop exit test.  If placed
! 	     anywhere else, loop may generate bad code.  */
! 	     
! 	  if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
! 	      && (NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP
! 		  || (last_iteration && unroll_type != UNROLL_COMPLETELY)))
  	    copy = emit_note (NOTE_SOURCE_FILE (insn),
  			      NOTE_LINE_NUMBER (insn));
! 	  else
! 	    copy = 0;
  	  break;
  	  
  	default:
--- 2149,2222 ----
  	  break;
  	  
  	case NOTE:
! 
! 	  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_VTOP
! 	      && (!last_iteration || unroll_type == UNROLL_COMPLETELY))
! 	    /* VTOP notes are valid only before the loop exit test.
! 	       If placed anywhere else, loop may generate bad code.
! 	       And, if we're unrolling the loop completely then
! 	       there's no loop left, and hence no need for VTOP
! 	       notes.  */
! 	    copy = 0;
! 	  else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
! 	    /* There's no need to copy a deleted instruction.  */
! 	    copy = 0;
! 	  else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
! 		   || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
! 	    {
! 	      rtx handler_body;
! 	      rtx end_of_handler_label;
! 
! 	      /* Remap the exception region.  */
! 	      copy = duplicate_eh_note (insn, map);
! 
! 	      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
! 		{
! 		  struct func_eh_entry* fee;
! 
! 		  /* Now, we must duplicate the code for the body of
! 		     the exception handler as well.  (Logically, it is
! 		     within the loop body, even though it is actually
! 		     emitted at the end of the function.).  */
! 		  fee = get_eh_region (NOTE_BLOCK_NUMBER (insn));
! 		  if (fee->handlers)
! 		    {
! 		      /* Start a new sequence for the copied handler.  */
! 		      start_sequence ();
! 
! 		      /* Jump around the code we're about to
! 			 generate.  */
! 		      end_of_handler_label = gen_label_rtx ();
! 		      emit_jump (end_of_handler_label);
! 
! 		      /* Copy the handler itself.  */
! 		      copy_region (PREV_INSN (fee->handlers->handler_label), 
! 				   fee->last_insn,
! 				   map, exit_label, last_iteration,
! 				   UNROLL_NONE, start_label);
! 
! 		      /* Insert the target of the jump generated
! 			 above.  We assume that it's impossible to
! 			 fall off the end of a handler, because the
! 			 handlers are emitted off to the side.  */
! 		      emit_label (end_of_handler_label);
! 		      
! 		      /* Get the body that we have just built up.  */
! 		      handler_body = gen_sequence ();
! 		      end_sequence (); 
! 
! 		      /* Insert the sequence before the original
!                          handler.  */
! 		      emit_insn_before (handler_body, 
! 					fee->handlers->handler_label);
! 		    }
! 		}
! 	    }
! 	  else
! 	    /* Just copy the note.  */
  	    copy = emit_note (NOTE_SOURCE_FILE (insn),
  			      NOTE_LINE_NUMBER (insn));
! 
  	  break;
  	  
  	default:
*************** copy_loop_body (copy_start, copy_end, ma
*** 2148,2153 ****
--- 2239,2284 ----
  	final_reg_note_copy (REG_NOTES (map->insn_map[INSN_UID (insn)]), map);
      }
    while (insn != copy_end);
+ }     
+ 
+ /* Copy each instruction in the loop, substituting from map as appropriate.
+    This is very similar to a loop in expand_inline_function.  */
+   
+ static void
+ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
+ 		unroll_type, start_label, loop_end, insert_before,
+ 		copy_notes_from)
+      rtx copy_start, copy_end;
+      struct inline_remap *map;
+      rtx exit_label;
+      int last_iteration;
+      enum unroll_types unroll_type;
+      rtx start_label, loop_end, insert_before, copy_notes_from;
+ {
+   rtx insn;
+   rtx final_label = 0;
+   rtx tem;
+ 
+   /* If this isn't the last iteration, then map any references to the
+      start_label to final_label.  Final label will then be emitted immediately
+      after the end of this loop body if it was ever used.
+ 
+      If this is the last iteration, then map references to the start_label
+      to itself.  */
+   if (! last_iteration)
+     {
+       final_label = gen_label_rtx ();
+       set_label_in_map (map, CODE_LABEL_NUMBER (start_label),
+ 			final_label); 
+     }
+   else
+     set_label_in_map (map, CODE_LABEL_NUMBER (start_label), start_label);
+ 
+   start_sequence ();
+ 
+   /* Copy the body of the loop.  */
+   copy_region (copy_start, copy_end, map, exit_label, last_iteration,
+ 	       unroll_type, start_label);
  
    /* There may be notes between copy_notes_from and loop_end.  Emit a copy of
       each of these notes here, since there may be some important ones, such as
Index: flow.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/flow.c,v
retrieving revision 1.90
diff -c -p -r1.90 flow.c
*** flow.c	1998/12/13 00:59:37	1.90
--- flow.c	1998/12/16 23:54:46
*************** make_edges (i)
*** 808,813 ****
--- 808,814 ----
                   outer region, or hasn't been seen yet, so defer it */
                if (nested_eh_region[region] != 0) 
                  {
+ 		  struct func_eh_entry* fee = get_eh_region (region);
                    /* start with the first region OUTSIDE the one specified 
                       in the rethrow parameter. (since a rethrow behaves
                       as if a handler in the region didn't handle the 
*************** make_edges (i)
*** 816,825 ****
  		  for ( region = nested_eh_region[region]; region; 
  			region = nested_eh_region[region]) 
  		    {
! 		      handler_info *ptr = get_first_handler (region);
  		      for ( ; ptr ; ptr = ptr->next)
                          add_edge_to_label (i, ptr->handler_label);
  		    }
                  }
                else 
                  {
--- 817,828 ----
  		  for ( region = nested_eh_region[region]; region; 
  			region = nested_eh_region[region]) 
  		    {
! 		      handler_info *ptr = fee->handlers;
  		      for ( ; ptr ; ptr = ptr->next)
                          add_edge_to_label (i, ptr->handler_label);
  		    }
+ 		  if (fee->last_insn)
+ 		    add_edge_to_label (i, fee->last_insn);
                  }
                else 
                  {
*************** make_edges (i)
*** 841,854 ****
  	    {
  	      if (active_eh_region[INSN_UID (insn)]) 
  		{
! 		  int region;
  		  handler_info *ptr;
- 		  region = active_eh_region[INSN_UID (insn)];
  		  for ( ; region; region = nested_eh_region[region])
  		    {
! 		      ptr = get_first_handler (region);
  		      for ( ; ptr ; ptr = ptr->next)
  			add_edge_to_label (i, ptr->handler_label);
  		    }
  		}
  	      if (! asynchronous_exceptions)
--- 844,859 ----
  	    {
  	      if (active_eh_region[INSN_UID (insn)]) 
  		{
! 		  int region = active_eh_region[INSN_UID (insn)];
  		  handler_info *ptr;
  		  for ( ; region; region = nested_eh_region[region])
  		    {
! 		      struct func_eh_entry* fee = get_eh_region (region);
! 		      ptr = fee->handlers;
  		      for ( ; ptr ; ptr = ptr->next)
  			add_edge_to_label (i, ptr->handler_label);
+ 		      if (fee->last_insn)
+ 			add_edge_to_label (BLOCK_NUM (insn), fee->last_insn);
  		    }
  		}
  	      if (! asynchronous_exceptions)
*************** make_edges (i)
*** 872,886 ****
        rtx insn = XEXP (pending_eh_region, 0);
        rtx note = find_reg_note (insn, REG_EH_RETHROW, NULL_RTX);
        int region = XINT (XEXP (note, 0), 0);
        /* start with the first region OUTSIDE the one specified 
           in the rethrow parameter */
        for ( region = nested_eh_region[region]; region; 
              region = nested_eh_region[region]) 
          {
!           handler_info *ptr = get_first_handler (region);
            for ( ; ptr ; ptr = ptr->next)
              add_edge_to_label (BLOCK_NUM (insn), ptr->handler_label);
          }
        pending_eh_region = XEXP (pending_eh_region, 1);
      }
  
--- 877,895 ----
        rtx insn = XEXP (pending_eh_region, 0);
        rtx note = find_reg_note (insn, REG_EH_RETHROW, NULL_RTX);
        int region = XINT (XEXP (note, 0), 0);
+       struct func_eh_entry* fee = get_eh_region (region);
        /* start with the first region OUTSIDE the one specified 
           in the rethrow parameter */
        for ( region = nested_eh_region[region]; region; 
              region = nested_eh_region[region]) 
          {
!           handler_info *ptr = fee->handlers;
            for ( ; ptr ; ptr = ptr->next)
              add_edge_to_label (BLOCK_NUM (insn), ptr->handler_label);
          }
+       if (fee->last_insn)
+ 	add_edge_to_label (BLOCK_NUM (insn), fee->last_insn);
+ 
        pending_eh_region = XEXP (pending_eh_region, 1);
      }
  
Index: toplev.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/toplev.c,v
retrieving revision 1.136
diff -c -p -r1.136 toplev.c
*** toplev.c	1998/12/13 00:59:38	1.136
--- toplev.c	1998/12/16 23:54:49
*************** rest_of_compilation (decl)
*** 3731,3736 ****
--- 3731,3743 ----
  	       reg_scan (insns, max_reg_num (), 1);
  	     }
  	   loop_optimize (insns, rtl_dump_file, flag_unroll_loops, 1);
+ 
+ 	   /* Now, the labels we added at the end of every exception
+ 	      handler are no longer needed; we only needed them to
+ 	      mark the extent of a handler during loop unrolling.
+ 	      Remove them from the exception_handler_labels list now.  */
+ 	   if (flag_unroll_loops)
+ 	     remove_end_of_handler_labels ();
  	 });
  
        /* Dump rtl code after loop opt, if we are doing that.  */


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