Reducing the cost of exception handling

Bruno Haible haible@ilog.fr
Tue Feb 10 03:34:00 GMT 1998


Hi,

Currently the exception handling code is emitted by gcc in the text
section, thus enlarging the applications' text segment by 0%-80%,
depending on C++ programming style.

Here is a patch which causes all the exception handling code to be
emitted to an extra section, called ".eh_text" on ELF systems.
The patch causes no regressions in the testsuite (on i586-linux)
and works well with inline functions.

For a library which uses many stack-allocated variables of class type,
I got the following figures:

       .text        572925 bytes
       .eh_text     387104 bytes

Moving the exception code "out of the way" therefore reduces the working
set size by 40%.

The .eh_frame section increases for the moment, but I already have patches
which will drastically reduce that section's size.

As a side-effect, the jumps over the cleanup code near the end of the
function is optimized away in most cases.

For programs which don't use exceptions much, I expect an improvement in the
paging performance. You can test "-fexception-section" vs.
"-fno-exception-section". Can we put this patch in?

What about the following points:

 - Is it possible to define an EH_TEXT_SECTION_ASM_OP for other platforms
   than ELF?

 - How do debuggers react on the fact that a function consists of two
   totally disjoint address ranges? Should "-g" generally imply
   "-fno-exception-section" ?

                    Bruno


------------------------------------------------------------------------------
Note: The patch below contains ^L characters which are not properly
displayed by Emacs.

For ChangeLog:

Sat Jan 10 04:23:00 1998  Bruno Haible  <bruno@linuix.mathematik.uni-karlsruhe.de>

        * except.h (extra_section_for_exceptions): New variable.
        * toplev.c (f_options): New flag -fexception-section.
          (compile_file): Initialize extra_section_for_exceptions.
        * rtl.h (NOTE_INSN_EH_HANDLER_{BEG,END}): Define.
        * rtl.c (note_insn_name): Add NOTE_INSN_EH_HANDLER_{BEG,END}.
        * except.c (extra_section_for_exceptions): Define.
          (expand_eh_region_end): Enclose the rethrow stub in EH_HANDLER notes.
          (add_eh_table_entry, exception_table_p): Adapt for multiple sections.
          (output_exception_table_entry, output_exception_table): Likewise.
        * function.c (expand_function_end): Enclose the cleanup code in
          EH_HANDLER notes.
        * jump.c (jump_optimize): Insert moved insns immediately before target
          label.
        * final.c (*eh_region*, eh_handler*): New variables.
          (init_final, final_start_function): Initialize them.
          (final_section_merge, final_jump_optimize): New functions.
          (final): Call them.
          (final_scan_insn): Change EH_REGION_* handling. Add EH_HANDLER_*
          handling.
        * tree.h (dwarf2out_goto_section): Declare.
        * dwarf2out.c (force_call_frame_info, current_section): New variables.
          (dwarf2out_goto_section): New function.
          (add_fde_cfi, output_call_frame_info): Adapt for multiple sections.
          (dwarf2out_begin_prologue, dwarf2out_end_epilogue): Likewise.
        * output.h (function_eh_section): Declare.
        * varasm.c (eh_text_section, function_eh_section): New functions.
        * frame.c (fde_insert, add_fdes, frame_init): Use two-stack insertion
          sort algorithm.

For cp/ChangeLog:

Sat Jan 10 04:23:00 1998  Bruno Haible  <bruno@linuix.mathematik.uni-karlsruhe.de>

        * except.c (expand_exception_blocks): Enclose a TRY's exception
          blocks in EH_HANDLER notes.

*** egcs-971225/gcc/except.h.bak	Sat Dec 20 01:13:52 1997
--- egcs-971225/gcc/except.h	Tue Jan  6 02:18:49 1998
*************** extern void init_eh				PROTO((void));
*** 147,160 ****
  
  extern void init_eh_for_function		PROTO((void));
  
! /* Adds an EH table entry for EH entry number N. Called from
!    final_scan_insn for NOTE_INSN_EH_REGION_BEG.  */
  
! extern void add_eh_table_entry			PROTO((int n));
  
! /* Returns a non-zero value if we need to output an exception table.  */
  
! extern int exception_table_p			PROTO((void));
  
  /* Outputs the exception table if we have one.  */
  
--- 147,162 ----
  
  extern void init_eh_for_function		PROTO((void));
  
! /* Adds an EH table entry for EH handler number N, protecting EH inverval
!    number I. Called from final_scan_insn for NOTE_INSN_EH_REGION_BEG
!    and NOTE_INSN_EH_HANDLER_BEG.  */
  
! extern void add_eh_table_entry			PROTO((int n, int i, int section));
  
! /* Returns a non-zero value if we need to output an exception table for
!    a specified section.  */
  
! extern int exception_table_p			PROTO((int section));
  
  /* Outputs the exception table if we have one.  */
  
*************** extern int exceptions_via_longjmp;
*** 270,275 ****
--- 272,281 ----
  /* One to enable asynchronous exception support.  */
  
  extern int asynchronous_exceptions;
+ 
+ /* One to emit exception handler code in a separate section.  */
+ 
+ extern int extra_section_for_exceptions;
  
  /* One to protect cleanup actions with a handler that calls
     __terminate, zero otherwise.  */
*** egcs-971225/gcc/toplev.c.bak	Sat Jan  3 20:26:13 1998
--- egcs-971225/gcc/toplev.c	Thu Jan  8 23:50:22 1998
*************** struct { char *string; int *variable; in
*** 749,754 ****
--- 749,755 ----
    {"exceptions", &flag_exceptions, 1},
    {"sjlj-exceptions", &exceptions_via_longjmp, 1},
    {"asynchronous-exceptions", &asynchronous_exceptions, 1},
+   {"exception-section", &extra_section_for_exceptions, 1},
    {"profile-arcs", &profile_arc_flag, 1},
    {"test-coverage", &flag_test_coverage, 1},
    {"branch-probabilities", &flag_branch_probabilities, 1},
*************** compile_file (name)
*** 2494,2499 ****
--- 2495,2523 ----
  
    if (flag_function_sections && write_symbols != NO_DEBUG)
      warning ("-ffunction-sections may affect debugging on some targets.");
+ 
+ #if defined (EH_TEXT_SECTION_ASM_OP) || defined (ASM_OUTPUT_SECTION_NAME)
+ #if defined (DBX_DEBUGGING_INFO) && defined (DBX_BLOCKS_FUNCTION_RELATIVE)
+   if (write_symbols == DBX_DEBUG)
+     {
+       if (extra_section_for_exceptions == 1)
+         warning ("-fexception-section disabled; it makes debugging impossible.");
+       extra_section_for_exceptions = 0;
+     }
+ #endif
+   if (profile_flag || profile_block_flag)
+     {
+       if (extra_section_for_exceptions == 1)
+ 	warning ("-fexception-section disabled; it makes profiling impossible.");
+       extra_section_for_exceptions = 0;
+     }
+   if (extra_section_for_exceptions == 2)
+     extra_section_for_exceptions = 1;
+ #else
+   if (extra_section_for_exceptions == 1)
+     warning ("-fexception-section not supported for this target.");
+   extra_section_for_exceptions = 0;
+ #endif
  
    if (output_bytecode)
      {
*** egcs-971225/gcc/rtl.h.bak	Tue Dec 30 11:27:33 1997
--- egcs-971225/gcc/rtl.h	Sun Jan  4 14:28:20 1998
*************** extern char *reg_note_name[];
*** 416,421 ****
--- 416,425 ----
     one is output after the end of an inline function, in order to prevent
     the line containing the inline call from being counted twice in gcov. */
  #define NOTE_REPEATED_LINE_NUMBER -16
+ /* These note where exception handlers begin and end.  For some targets,
+    exception handling code is put into a separate section.  */
+ #define NOTE_INSN_EH_HANDLER_BEG -17
+ #define NOTE_INSN_EH_HANDLER_END -18
  
  
  #if 0 /* These are not used, and I don't know what they were for. --rms.  */
*** egcs-971225/gcc/rtl.c.bak	Tue Dec 30 11:27:33 1997
--- egcs-971225/gcc/rtl.c	Sun Jan  4 14:31:22 1998
*************** char *note_insn_name[] = { 0            
*** 177,183 ****
  			   "NOTE_INSN_PROLOGUE_END", "NOTE_INSN_EPILOGUE_BEG",
  			   "NOTE_INSN_DELETED_LABEL", "NOTE_INSN_FUNCTION_BEG",
  			   "NOTE_INSN_EH_REGION_BEG", "NOTE_INSN_EH_REGION_END",
! 			   "NOTE_REPEATED_LINE_NUMBER" };
  
  char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0",
  			  "REG_EQUAL", "REG_RETVAL", "REG_LIBCALL",
--- 177,185 ----
  			   "NOTE_INSN_PROLOGUE_END", "NOTE_INSN_EPILOGUE_BEG",
  			   "NOTE_INSN_DELETED_LABEL", "NOTE_INSN_FUNCTION_BEG",
  			   "NOTE_INSN_EH_REGION_BEG", "NOTE_INSN_EH_REGION_END",
! 			   "NOTE_REPEATED_LINE_NUMBER",
! 			   "NOTE_INSN_EH_HANDLER_BEG",
! 			   "NOTE_INSN_EH_HANDLER_END" };
  
  char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0",
  			  "REG_EQUAL", "REG_RETVAL", "REG_LIBCALL",
*** egcs-971225/gcc/except.c.bak	Thu Jan  1 14:32:08 1998
--- egcs-971225/gcc/except.c	Wed Jan  7 02:42:56 1998
*************** int exceptions_via_longjmp = 2;
*** 422,427 ****
--- 422,431 ----
  
  int asynchronous_exceptions = 0;
  
+ /* One to emit exception handler code in a separate section.  */
+ 
+ int extra_section_for_exceptions = 2;
+ 
  /* One to protect cleanup actions with a handler that calls
     __terminate, zero otherwise.  */
  
*************** expand_eh_region_end (handler)
*** 1123,1133 ****
--- 1127,1141 ----
        label = gen_label_rtx ();
        emit_jump (label);
  
+       emit_note (NULL_PTR, NOTE_INSN_EH_HANDLER_BEG);
+ 
        /* Emit a label marking the end of this exception region that
  	 is used for rethrowing into the outer context.  */
        emit_label (entry->outer_context);
        expand_internal_throw ();
  
+       emit_note (NULL_PTR, NOTE_INSN_EH_HANDLER_END);
+ 
        emit_label (label);
      }
  
*************** protect_with_terminate (e)
*** 1508,1565 ****
     dispatching exceptions, the current number of entries, and its
     maximum size before we have to extend it. 
  
!    The number in eh_table is the code label number of the exception
!    handler for the region. This is added by add_eh_table_entry and
!    used by output_exception_table_entry.  */
! 
! static int *eh_table;
! static int eh_table_size;
! static int eh_table_max_size;
! 
! /* Note the need for an exception table entry for region N.  If we
!    don't need to output an explicit exception table, avoid all of the
!    extra work.
! 
!    Called from final_scan_insn when a NOTE_INSN_EH_REGION_BEG is seen.
!    N is the NOTE_BLOCK_NUMBER of the note, which comes from the code
!    label number of the exception handler for the region.  */
  
  void
! add_eh_table_entry (n)
!      int n;
  {
  #ifndef OMIT_EH_TABLE
!   if (eh_table_size >= eh_table_max_size)
      {
!       if (eh_table)
  	{
! 	  eh_table_max_size += eh_table_max_size>>1;
  
! 	  if (eh_table_max_size < 0)
  	    abort ();
  
! 	  eh_table = (int *) xrealloc (eh_table,
! 				       eh_table_max_size * sizeof (int));
  	}
        else
  	{
! 	  eh_table_max_size = 252;
! 	  eh_table = (int *) xmalloc (eh_table_max_size * sizeof (int));
  	}
      }
!   eh_table[eh_table_size++] = n;
  #endif
  }
  
! /* Return a non-zero value if we need to output an exception table.
  
     On some platforms, we don't have to output a table explicitly.
     This routine doesn't mean we don't have one.  */
  
  int
! exception_table_p ()
  {
!   if (eh_table)
      return 1;
  
    return 0;
--- 1516,1598 ----
     dispatching exceptions, the current number of entries, and its
     maximum size before we have to extend it. 
  
!    There is one table for the text section and one for the eh_text
!    section.
! 
!    The number in eh_table[section].entries is the code label number of
!    the exception handler for the region. This is added by
!    add_eh_table_entry and used by output_exception_table_entry.  */
! 
! struct eh_table_entry
!   {
!     int n;
!     int i;
!   };
! 
! static struct eh_table_struct
!   {
!     struct eh_table_entry *entries;
!     int size;
!     int max_size;
!   }
! eh_table[2];
! 
! /* Note the need for an exception table entry which protects interval I
!    through handler N.  If we don't need to output an explicit exception
!    table, avoid all of the extra work.
! 
!    Called from final_scan_insn when a NOTE_INSN_EH_REGION_BEG or a
!    NOTE_INSN_EH_HANDLER_BEG is seen.  N is the code label number of the
!    exception handler for the region.  I is the code label number of the
!    special start and end labels (output directly from final_scan_insn)
!    of the regions.  */
  
  void
! add_eh_table_entry (n, i, section)
!      int n, i, section;
  {
  #ifndef OMIT_EH_TABLE
!   struct eh_table_struct *table = &eh_table[section];
! 
!   if (table->size >= table->max_size)
      {
!       if (table->entries)
  	{
! 	  table->max_size += table->max_size>>1;
  
! 	  if (table->max_size < 0)
  	    abort ();
  
! 	  table->entries =
! 	    (struct eh_table_entry *)
! 	      xrealloc (table->entries,
! 			table->max_size * sizeof (struct eh_table_entry));
  	}
        else
  	{
! 	  table->max_size = 252;
! 	  table->entries =
! 	    (struct eh_table_entry *)
! 	      xmalloc (table->max_size * sizeof (struct eh_table_entry));
  	}
      }
!   table->entries[table->size].i = i;
!   table->entries[table->size].n = n;
!   table->size++;
  #endif
  }
  
! /* Return a non-zero value if we need to output an exception table for
!    a specified section.
  
     On some platforms, we don't have to output a table explicitly.
     This routine doesn't mean we don't have one.  */
  
  int
! exception_table_p (section)
!      int section;
  {
!   if (eh_table[section].entries)
      return 1;
  
    return 0;
*************** exception_table_p ()
*** 1572,1593 ****
     region.  */
  
  static void
! output_exception_table_entry (file, n)
       FILE *file;
!      int n;
  {
    char buf[256];
    rtx sym;
  
!   ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
    sym = gen_rtx (SYMBOL_REF, Pmode, buf);
    assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
  
!   ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
    sym = gen_rtx (SYMBOL_REF, Pmode, buf);
    assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
  
!   ASM_GENERATE_INTERNAL_LABEL (buf, "L", n);
    sym = gen_rtx (SYMBOL_REF, Pmode, buf);
    assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
  
--- 1605,1626 ----
     region.  */
  
  static void
! output_exception_table_entry (file, entry)
       FILE *file;
!      const struct eh_table_entry *entry;
  {
    char buf[256];
    rtx sym;
  
!   ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", entry->i);
    sym = gen_rtx (SYMBOL_REF, Pmode, buf);
    assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
  
!   ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", entry->i);
    sym = gen_rtx (SYMBOL_REF, Pmode, buf);
    assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
  
!   ASM_GENERATE_INTERNAL_LABEL (buf, "L", entry->n);
    sym = gen_rtx (SYMBOL_REF, Pmode, buf);
    assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
  
*************** output_exception_table_entry (file, n)
*** 1599,1626 ****
  void
  output_exception_table ()
  {
!   int i;
    extern FILE *asm_out_file;
  
!   if (! doing_eh (0) || ! eh_table)
      return;
  
    exception_section ();
  
!   /* Beginning marker for table.  */
!   assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
!   assemble_label ("__EXCEPTION_TABLE__");
! 
!   for (i = 0; i < eh_table_size; ++i)
!     output_exception_table_entry (asm_out_file, eh_table[i]);
! 
!   free (eh_table);
! 
!   /* Ending marker for table.  */
!   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
!   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
!   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
!   putc ('\n', asm_out_file);		/* blank line */
  }
  
  /* Emit code to get EH context.
--- 1632,1671 ----
  void
  output_exception_table ()
  {
!   int section, i;
    extern FILE *asm_out_file;
  
!   if (! doing_eh (0))
!     return;
! 
!   if (! eh_table[0].entries && ! eh_table[1].entries)
      return;
  
    exception_section ();
  
!   for (section = 0; section < 2; section++)
!     {
!       struct eh_table_struct *table = &eh_table[section];
! 
!       if (table->size > 0)
! 	{
! 	  /* Beginning marker for table.  */
! 	  assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
! 	  assemble_label (section == 0 ? "__EXCEPTION_TABLE__"
! 				       : "__EH_EXCEPTION_TABLE__");
! 
! 	  for (i = 0; i < table->size; i++)
! 	    output_exception_table_entry (asm_out_file, &table->entries[i]);
! 
! 	  /* Ending marker for table.  */
! 	  assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
! 	  assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
! 	  assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
! 	  putc ('\n', asm_out_file);		/* blank line */
! 	}
! 
!       free (table->entries);
!     }
  }
  
  /* Emit code to get EH context.
*** egcs-971225/gcc/function.c.bak	Thu Jan  1 14:04:35 1998
--- egcs-971225/gcc/function.c	Fri Jan  9 00:19:01 1998
*************** expand_function_end (filename, line, end
*** 5901,5913 ****
       created for the parameters.  */
    {
      rtx last = get_last_insn ();
-     rtx label;
  
      expand_leftover_cleanups ();
  
      /* If the above emitted any code, may sure we jump around it.  */
      if (last != get_last_insn ())
        {
  	label = gen_label_rtx ();
  	last = emit_jump_insn_after (gen_jump (label), last);
  	last = emit_barrier_after (last);
--- 5901,5919 ----
       created for the parameters.  */
    {
      rtx last = get_last_insn ();
  
      expand_leftover_cleanups ();
  
      /* If the above emitted any code, may sure we jump around it.  */
      if (last != get_last_insn ())
        {
+ 	rtx label;
+ 
+ 	/* If extra_section_for_exceptions is on, the cleanup code will be
+ 	   moved to the eh_text section, and if we aren't already in the
+ 	   eh_text section, the jump will be eliminated in final.c.  */
+ 	emit_note_after (NOTE_INSN_EH_HANDLER_BEG, last);
+ 	emit_note (NULL_PTR, NOTE_INSN_EH_HANDLER_END);
  	label = gen_label_rtx ();
  	last = emit_jump_insn_after (gen_jump (label), last);
  	last = emit_barrier_after (last);
*** egcs-971225/gcc/jump.c.bak	Thu Jan  1 15:20:20 1998
--- egcs-971225/gcc/jump.c	Sun Jan  4 19:39:49 1998
*************** jump_optimize (f, cross_jump, noop_moves
*** 720,725 ****
--- 720,726 ----
  	    {
  	      if (GET_CODE (temp1) == BARRIER)
  		{
+ 		  temp1 = PREV_INSN (JUMP_LABEL (insn));
  		  emit_insn_after (PATTERN (temp), temp1);
  		  temp1 = NEXT_INSN (temp1);
  		}
*** egcs-971225/gcc/final.c.bak	Thu Jan  1 17:35:20 1998
--- egcs-971225/gcc/final.c	Sat Jan 10 03:38:33 1998
*************** static int *pending_blocks;
*** 233,238 ****
--- 233,258 ----
  
  static int block_depth;
  
+ /* Length so far allocated in PENDING_EH_REGIONS.  */
+ 
+ static int max_eh_region_depth;
+ 
+ /* Stack of handler block numbers for open exception handling regions.  */
+ 
+ static int *pending_eh_regions;
+ 
+ /* Number of elements currently in use in PENDING_EH_REGIONS.  */
+ 
+ static int eh_region_depth;
+ 
+ /* Number of nested NOTE_INSN_EH_HANDLER_{BEG,END} notes seen.  */
+ 
+ static int eh_handler_depth;
+ 
+ /* If eh_handler_depth > 0, a label used to protect an eh_text region.  */
+ 
+ static rtx eh_handler_region_label;
+ 
  /* Nonzero if have enabled APP processing of our assembler output.  */
  
  static int app_on;
*************** init_final (filename)
*** 310,316 ****
    next_block_index = 2;
    app_on = 0;
    max_block_depth = 20;
!   pending_blocks = (int *) xmalloc (20 * sizeof *pending_blocks);
    final_sequence = 0;
  
  #ifdef ASSEMBLER_DIALECT
--- 330,338 ----
    next_block_index = 2;
    app_on = 0;
    max_block_depth = 20;
!   pending_blocks = (int *) xmalloc (max_block_depth * sizeof (int));
!   max_eh_region_depth = 10;
!   pending_eh_regions = (int *) xmalloc (max_eh_region_depth * sizeof (int));
    final_sequence = 0;
  
  #ifdef ASSEMBLER_DIALECT
*************** final_start_function (first, file, optim
*** 951,956 ****
--- 973,981 ----
       int optimize;
  {
    block_depth = 0;
+   eh_region_depth = 0;
+   eh_handler_depth = 0;
+   eh_handler_region_label = NULL_RTX;
  
    this_is_asm_operands = 0;
  
*************** add_bb_string (string, perm_p)
*** 1266,1271 ****
--- 1291,1462 ----
  }
  
  
+ /* We must make sure that we don't output the difference of two labels in
+    different sections: the text section and the eh_text section. Some pairs
+    of NOTE_INSN_EH_HANDLER_{BEG,END} insns must be deleted.  */
+ static void
+ final_section_merge (rtx first)
+ {
+   int max_uid;
+   rtx *outer_table;
+   rtx insn;
+   rtx outer;
+ 
+   if (! extra_section_for_exceptions)
+     return;
+ 
+   max_uid = get_max_uid ();
+   outer_table = (rtx *) alloca (max_uid * sizeof (rtx));
+   bzero ((char *) outer_table, max_uid * sizeof (rtx));
+ 
+   /* Make a single pass through the code, registering the outer enclosing
+      NOTE_INSN_EH_HANDLER_BEG insn in OUTER_TABLE. Also let each
+      EH_HANDLER_BEG note point to its corresponding EH_HANDLER_END note.  */
+   outer = NULL_RTX;
+   for (insn = first; insn; insn = NEXT_INSN (insn))
+     {
+       outer_table[INSN_UID (insn)] = outer;
+       if (INSN_DELETED_P (insn))
+ 	continue;
+       if (GET_CODE (insn) == NOTE)
+ 	{
+ 	  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_HANDLER_BEG)
+ 	    outer = insn;
+ 	  else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_HANDLER_END)
+ 	    {
+ 	      NOTE_SOURCE_FILE (outer) = (char *) insn;
+ 	      outer = outer_table[INSN_UID (outer)];
+ 	    }
+ 	}
+     }
+   if (outer != NULL_RTX)
+     abort ();
+ 
+   /* Now go through the code once again, looking for suspicious label
+      differences.  */
+   for (insn = first; insn; insn = NEXT_INSN (insn))
+     {
+       if (INSN_DELETED_P (insn))
+ 	continue;
+       if (GET_CODE (insn) == JUMP_INSN
+ 	  && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
+ 	{
+ 	  rtx body = PATTERN (insn);
+ 	  int vlen = XVECLEN (body, 1);
+ 	  int idx;
+ 	  for (idx = 0; idx < vlen; idx++)
+ 	    {
+ 	      rtx outer1, outer2;
+ 	      int depth1, depth2;
+ 	      outer1 = XEXP (XEXP (body, 0), 0);
+ 	      outer2 = XEXP (XVECEXP (body, 1, idx), 0);
+ 	      outer1 = outer_table[INSN_UID (outer1)];
+ 	      outer2 = outer_table[INSN_UID (outer2)];
+ 	      for (outer = outer1, depth1 = 0;
+ 		   outer != NULL_RTX;
+ 		   outer = outer_table[INSN_UID (outer)], depth1++);
+ 	      for (outer = outer2, depth2 = 0;
+ 		   outer != NULL_RTX;
+ 		   outer = outer_table[INSN_UID (outer)], depth2++);
+ 	      while (!(depth1 == depth2 && outer1 == outer2))
+ 		{
+ 		  int kill1 = (depth1 >= depth2);
+ 		  int kill2 = (depth1 <= depth2);
+ 		  if (kill1)
+ 		    {
+ 		      /* Kill EH_HANDLER_{BEG,END} corresponding to outer1.  */
+ 		      NOTE_LINE_NUMBER ((rtx) NOTE_SOURCE_FILE (outer1))
+ 			= NOTE_INSN_DELETED;
+ 		      NOTE_LINE_NUMBER (outer1) = NOTE_INSN_DELETED;
+ 		      outer1 = outer_table[INSN_UID (outer1)];
+ 		      depth1--;
+ 		    }
+ 		  if (kill2)
+ 		    {
+ 		      /* Kill EH_HANDLER_{BEG,END} corresponding to outer2.  */
+ 		      NOTE_LINE_NUMBER ((rtx) NOTE_SOURCE_FILE (outer2))
+ 			= NOTE_INSN_DELETED;
+ 		      NOTE_LINE_NUMBER (outer2) = NOTE_INSN_DELETED;
+ 		      outer2 = outer_table[INSN_UID (outer2)];
+ 		      depth2--;
+ 		    }
+ 		}
+ 	    }
+ 	}
+     }
+ }
+ 
+ /* Remove simple jumps which jump "over" some code in another section.
+    The usual jump optimizations don't catch this because they don't know
+    about different code sections. In fact, the usual jump optimizations
+    cannot do this because the partitioning into sections is different
+    between an out-of-line copy and an inline copy of the same function.  */
+ static void
+ final_jump_optimize (rtx first)
+ {
+   rtx insn, insn1, insn2, last_jump;
+   int eh_handler_depth;
+ 
+   if (optimize && extra_section_for_exceptions)
+     {
+       eh_handler_depth = 0;
+       last_jump = NULL_RTX;
+       for (insn = first; insn; insn = NEXT_INSN (insn))
+ 	{
+ 	  if (INSN_DELETED_P (insn))
+ 	    continue;
+ 	  switch (GET_CODE (insn))
+ 	    {
+ 	    case NOTE:
+ 	      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_HANDLER_BEG)
+ 		{
+ 		  if (eh_handler_depth++ == 0)
+ 		    {
+ 		      if ((insn1 = PREV_INSN (insn))
+ 			  && GET_CODE (insn1) == BARRIER
+ 			  && (insn2 = PREV_INSN (insn1))
+ 			  && simplejump_p (insn2))
+ 			last_jump = insn2;
+ 		    }
+ 		  break;
+ 		}
+ 	      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_HANDLER_END)
+ 		{
+ 		  if (--eh_handler_depth == 0)
+ 		    {
+ 		      if (last_jump)
+ 			{
+ 			  for (insn1 = NEXT_INSN (insn);
+ 			       insn1
+ 			       && GET_CODE (insn1) == NOTE
+ 			       && (NOTE_LINE_NUMBER (insn1)
+ 				   != NOTE_INSN_EH_HANDLER_BEG);
+ 			       insn1 = NEXT_INSN (insn1))
+ 			    ;
+ 			  if (GET_CODE (insn1) == CODE_LABEL
+ 			      && JUMP_LABEL (last_jump) == insn1)
+ 			    /* Delete the jump "over" the section and the
+ 			       barrier in between.  */
+ 			    {
+ 			      INSN_DELETED_P (last_jump) = 1;
+ 			      INSN_DELETED_P (NEXT_INSN (last_jump)) = 1;
+ 			      last_jump = NULL_RTX;
+ 			    }
+ 			}
+ 		    }
+ 		  break;
+ 		}
+ 	      break;
+ 	    default:
+ 	      if (eh_handler_depth == 0)
+ 		last_jump = NULL_RTX;
+ 	      break;
+ 	    }
+ 	}
+     }
+ }
+ 
+ 
  /* Output assembler code for some insns: all or part of a function.
     For description of args, see `final_start_function', above.
  
*************** final (first, file, optimize, prescan)
*** 1292,1297 ****
--- 1483,1491 ----
  
    check_exception_handler_labels ();
  
+   final_section_merge (first);
+   final_jump_optimize (first);
+ 
    /* Make a map indicating which line numbers appear in this function.
       When producing SDB debugging info, delete troublesome line number
       notes from inlined functions in other files as well as duplicate
*************** final_scan_insn (insn, file, optimize, p
*** 1399,1422 ****
        if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
  	break;
  
!       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
! 	  && ! exceptions_via_longjmp)
  	{
! 	  ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_BLOCK_NUMBER (insn));
! 	  add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
  #ifdef ASM_OUTPUT_EH_REGION_BEG
! 	  ASM_OUTPUT_EH_REGION_BEG (file, NOTE_BLOCK_NUMBER (insn));
  #endif
  	  break;
  	}
  
!       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
! 	  && ! exceptions_via_longjmp)
  	{
! 	  ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_BLOCK_NUMBER (insn));
  #ifdef ASM_OUTPUT_EH_REGION_END
! 	  ASM_OUTPUT_EH_REGION_END (file, NOTE_BLOCK_NUMBER (insn));
  #endif
  	  break;
  	}
  
--- 1593,1691 ----
        if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
  	break;
  
!       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
  	{
! 	  int blockno = NOTE_BLOCK_NUMBER (insn);
! 
! 	  if (eh_region_depth == max_eh_region_depth)
! 	    {
! 	      /* PENDING_EH_REGIONS is full; make it longer.  */
! 	      max_eh_region_depth *= 2;
! 	      pending_eh_regions =
! 		(int *) xrealloc (pending_eh_regions,
! 				  max_eh_region_depth * sizeof (int));
! 	    }
! 	  pending_eh_regions[eh_region_depth++] = blockno;
! 
! 	  if (! exceptions_via_longjmp)
! 	    {
! 	      ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", blockno);
! 	      add_eh_table_entry (blockno, blockno,
! 				  extra_section_for_exceptions
! 				  && eh_handler_depth > 0);
  #ifdef ASM_OUTPUT_EH_REGION_BEG
! 	      ASM_OUTPUT_EH_REGION_BEG (file, blockno);
  #endif
+ 	    }
+ 
  	  break;
  	}
  
!       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
  	{
! 	  int blockno = NOTE_BLOCK_NUMBER (insn);
! 
! 	  eh_region_depth--;
! 
! 	  if (! exceptions_via_longjmp)
! 	    {
! 	      ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", blockno);
  #ifdef ASM_OUTPUT_EH_REGION_END
! 	      ASM_OUTPUT_EH_REGION_END (file, blockno);
! #endif
! 	    }
! 
! 	  break;
! 	}
! 
!       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_HANDLER_BEG)
! 	{
! 	  /* NOTE_INSN_EH_HANDLER_BEG followed by NOTE_INSN_EH_HANDLER_END
! 	     cancel each other and can be ignored.  */
! 	  rtx next_insn = NEXT_INSN (insn);
! 	  if (GET_CODE (next_insn) == NOTE
! 	      && NOTE_LINE_NUMBER (next_insn) == NOTE_INSN_EH_HANDLER_END)
! 	    return NEXT_INSN (next_insn);
! 
! 	  if (eh_handler_depth++ == 0 && extra_section_for_exceptions)
! 	    {
! 	      function_eh_section (current_function_decl);
! 	      if (! exceptions_via_longjmp && eh_region_depth > 0)
! 		{
! 		  int i, n;
! 		  eh_handler_region_label = gen_label_rtx ();
! 		  i = CODE_LABEL_NUMBER (eh_handler_region_label);
! 		  n = pending_eh_regions[eh_region_depth - 1];
! 		  ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", i);
! 		  add_eh_table_entry (n, i, 1);
! 		}
! #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
! 	      if (dwarf2out_do_frame ())
! 		dwarf2out_goto_section (1, eh_handler_region_label);
! #endif
! 	    }
! 	  break;
! 	}
! 
!       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_HANDLER_END)
! 	{
! 	  if (--eh_handler_depth == 0 && extra_section_for_exceptions)
! 	    {
! #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
! 	      if (dwarf2out_do_frame ())
! 		dwarf2out_goto_section (0, eh_handler_region_label);
  #endif
+ 	      if (! exceptions_via_longjmp && eh_region_depth > 0)
+ 		{
+ 		  int i, n;
+ 		  i = CODE_LABEL_NUMBER (eh_handler_region_label);
+ 		  n = pending_eh_regions[eh_region_depth - 1];
+ 		  ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", i);
+ 		  rtx_free (eh_handler_region_label);
+ 		  eh_handler_region_label = NULL_RTX;
+ 		}
+ 	      function_section (current_function_decl);
+ 	    }
  	  break;
  	}
  
*** egcs-971225/gcc/tree.h.bak	Sat Dec 20 01:16:00 1997
--- egcs-971225/gcc/tree.h	Wed Jan  7 00:43:10 1998
*************** extern void dwarf2out_return_save	PROTO(
*** 1805,1810 ****
--- 1805,1814 ----
  
  extern void dwarf2out_return_reg	PROTO((char *, unsigned));
  
+ /* Entry point for switching to another section.  */
+ 
+ extern void dwarf2out_goto_section	PROTO((int, struct rtx_def *));
+ 
  /* Output a marker (i.e. a label) for the beginning of a function, before
     the prologue.  */
  
*** egcs-971225/gcc/dwarf2out.c.bak	Thu Jan  1 15:13:23 1998
--- egcs-971225/gcc/dwarf2out.c	Fri Jan  9 02:55:44 1998
*************** typedef union dw_cfi_oprnd_struct
*** 79,84 ****
--- 79,85 ----
    unsigned long dw_cfi_reg_num;
    long int dw_cfi_offset;
    char *dw_cfi_addr;
+   int dw_cfi_section;
  }
  dw_cfi_oprnd;
  
*************** dw_cfi_node;
*** 99,107 ****
  
  typedef struct dw_fde_struct
  {
!   char *dw_fde_begin;
    char *dw_fde_current_label;
!   char *dw_fde_end;
    dw_cfi_ref dw_fde_cfi;
  }
  dw_fde_node;
--- 100,108 ----
  
  typedef struct dw_fde_struct
  {
!   char *dw_fde_begin[2];
    char *dw_fde_current_label;
!   char *dw_fde_end[2];
    dw_cfi_ref dw_fde_cfi;
  }
  dw_fde_node;
*************** dwarf_cfi_name (cfi_opc)
*** 688,693 ****
--- 689,755 ----
      }
  }
  
+ /* If this is set to 1, CIEs and FDEs will be output even if no function
+    in the compilation uses exceptions.  */
+ static int force_call_frame_info = 0;
+ 
+ /* The current section to which insns are being emitted. 0 means "text",
+    1 means "eh_text".  */
+ static int current_section;
+ 
+ /* Switch to another section.
+    When LABEL is non-NULL, it denotes an LEHB/LEHE label which is just being
+    output.  */
+ void
+ dwarf2out_goto_section (section, label)
+      int section;
+      rtx label;
+ {
+   register dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
+   rtx templabel;
+   int labelno = -1;
+   char labelstring[MAX_ARTIFICIAL_LABEL_BYTES];
+ 
+   if (section == 0)
+     {
+       /* Switching from section 1 to section 0.  */
+       if (label)
+ 	labelno = CODE_LABEL_NUMBER (label);
+       else
+ 	{
+ 	  templabel = gen_label_rtx ();
+ 	  labelno = CODE_LABEL_NUMBER (templabel);
+ 	  rtx_free (templabel);
+ 	}
+       ASM_GENERATE_INTERNAL_LABEL (labelstring, "LEHE", labelno);
+       if (! label)
+ 	ASM_OUTPUT_LABEL (asm_out_file, labelstring);
+       if (fde->dw_fde_end[1])
+ 	free (fde->dw_fde_end[1]);
+       fde->dw_fde_end[1] = xstrdup (labelstring);
+     }
+   else
+     {
+       /* Switching from section 0 to section 1.  */
+       if (! fde->dw_fde_begin[1])
+ 	{
+ 	  if (label)
+ 	    labelno = CODE_LABEL_NUMBER (label);
+ 	  else
+ 	    {
+ 	      templabel = gen_label_rtx ();
+ 	      labelno = CODE_LABEL_NUMBER (templabel);
+ 	      rtx_free (templabel);
+ 	    }
+ 	  ASM_GENERATE_INTERNAL_LABEL (labelstring, "LEHB", labelno);
+ 	  if (! label)
+ 	    ASM_OUTPUT_LABEL (asm_out_file, labelstring);
+ 	  fde->dw_fde_begin[1] = xstrdup (labelstring);
+ 	}
+     }
+   current_section = section;
+ }
+ 
  /* Return a pointer to a newly allocated Call Frame Instruction.  */
  
  static inline dw_cfi_ref
*************** add_fde_cfi (label, cfi)
*** 758,763 ****
--- 820,826 ----
  	  xcfi = new_cfi ();
  	  xcfi->dw_cfi_opc = DW_CFA_advance_loc4;
  	  xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
+ 	  xcfi->dw_cfi_oprnd2.dw_cfi_section = current_section;
  	  add_cfi (&fde->dw_fde_cfi, xcfi);
  	}
  
*************** static void
*** 1579,1584 ****
--- 1642,1648 ----
  output_call_frame_info (for_eh)
       int for_eh;
  {
+   int section;
    register unsigned long i;
    register dw_fde_ref fde;
    register dw_cfi_ref cfi;
*************** output_call_frame_info (for_eh)
*** 1587,1595 ****
    char ld[20];
  #endif
  
-   /* Do we want to include a pointer to the exception table?  */
-   int eh_ptr = for_eh && exception_table_p ();
- 
    fputc ('\n', asm_out_file);
  
    /* We're going to be generating comments, so turn on app.  */
--- 1651,1656 ----
*************** output_call_frame_info (for_eh)
*** 1608,1731 ****
        ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
        ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
  #endif
-       assemble_label ("__FRAME_BEGIN__");
      }
    else
      ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION);
  
!   /* Output the CIE. */
!   ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
!   ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
! #ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
!   ASM_GENERATE_INTERNAL_LABEL (ld, CIE_LENGTH_LABEL, for_eh);
!   if (for_eh)
!     ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
!   else
!     ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld);
! #else
!   if (for_eh)
!     ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1);
!   else
!     ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
! #endif
!   if (flag_debug_asm)
!     fprintf (asm_out_file, "\t%s Length of Common Information Entry",
! 	     ASM_COMMENT_START);
! 
!   fputc ('\n', asm_out_file);
!   ASM_OUTPUT_LABEL (asm_out_file, l1);
! 
!   if (for_eh)
!     /* Now that the CIE pointer is PC-relative for EH,
!        use 0 to identify the CIE.  */
!     ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
!   else
!     ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
! 
!   if (flag_debug_asm)
!     fprintf (asm_out_file, "\t%s CIE Identifier Tag", ASM_COMMENT_START);
! 
!   fputc ('\n', asm_out_file);
!   if (! for_eh && DWARF_OFFSET_SIZE == 8)
!     {
!       ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
!       fputc ('\n', asm_out_file);
!     }
! 
!   ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CIE_VERSION);
!   if (flag_debug_asm)
!     fprintf (asm_out_file, "\t%s CIE Version", ASM_COMMENT_START);
! 
!   fputc ('\n', asm_out_file);
!   if (eh_ptr)
!     {
!       /* The CIE contains a pointer to the exception region info for the
!          frame.  Make the augmentation string three bytes (including the
!          trailing null) so the pointer is 4-byte aligned.  The Solaris ld
!          can't handle unaligned relocs.  */
!       if (flag_debug_asm)
! 	{
! 	  ASM_OUTPUT_DWARF_STRING (asm_out_file, "eh");
! 	  fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START);
! 	}
!       else
! 	{
! 	  ASM_OUTPUT_ASCII (asm_out_file, "eh", 3);
! 	}
!       fputc ('\n', asm_out_file);
! 
!       ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__");
!       if (flag_debug_asm)
! 	fprintf (asm_out_file, "\t%s pointer to exception region info",
! 		 ASM_COMMENT_START);
!     }
!   else
      {
!       ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
!       if (flag_debug_asm)
! 	fprintf (asm_out_file, "\t%s CIE Augmentation (none)",
! 		 ASM_COMMENT_START);
!     }
! 
!   fputc ('\n', asm_out_file);
!   output_uleb128 (1);
!   if (flag_debug_asm)
!     fprintf (asm_out_file, " (CIE Code Alignment Factor)");
! 
!   fputc ('\n', asm_out_file);
!   output_sleb128 (DWARF_CIE_DATA_ALIGNMENT);
!   if (flag_debug_asm)
!     fprintf (asm_out_file, " (CIE Data Alignment Factor)");
! 
!   fputc ('\n', asm_out_file);
!   ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN);
!   if (flag_debug_asm)
!     fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START);
! 
!   fputc ('\n', asm_out_file);
! 
!   for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
!     output_cfi (cfi, NULL);
  
!   /* Pad the CIE out to an address sized boundary.  */
!   ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
!   ASM_OUTPUT_LABEL (asm_out_file, l2);
! #ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
!   ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
!   if (flag_debug_asm)
!     fprintf (asm_out_file, "\t%s CIE Length Symbol", ASM_COMMENT_START);
!   fputc ('\n', asm_out_file);
! #endif
! 
!   /* Loop through all of the FDE's.  */
!   for (i = 0; i < fde_table_in_use; ++i)
!     {
!       fde = &fde_table[i];
  
!       ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i*2);
!       ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i*2);
  #ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
!       ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, for_eh + i*2);
        if (for_eh)
  	ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
        else
--- 1669,1697 ----
        ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
        ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
  #endif
      }
    else
      ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION);
  
!   /* A CIE and a series of FDEs for each section. */
!   for (section = 0; section < 1 + extra_section_for_exceptions; section++)
      {
!       /* Number to append to labels, to keep them distinct. */
!       int nr = 2 * section + for_eh;
  
!       if (for_eh
! 	  && ! exception_table_p (section)
! 	  && ! (section == 0 && force_call_frame_info))
! 	continue;
  
!       /* Output the CIE. */
!       if (for_eh)
! 	assemble_label (section == 0 ? "__FRAME_BEGIN__"
! 				     : "__EH_FRAME_BEGIN__");
!       ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, nr);
!       ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, nr);
  #ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
!       ASM_GENERATE_INTERNAL_LABEL (ld, CIE_LENGTH_LABEL, nr);
        if (for_eh)
  	ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
        else
*************** output_call_frame_info (for_eh)
*** 1737,1790 ****
  	ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
  #endif
        if (flag_debug_asm)
! 	fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START);
        fputc ('\n', asm_out_file);
        ASM_OUTPUT_LABEL (asm_out_file, l1);
  
        if (for_eh)
! 	ASM_OUTPUT_DWARF_DELTA (asm_out_file, l1, "__FRAME_BEGIN__");
        else
! 	ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (FRAME_SECTION));
        if (flag_debug_asm)
! 	fprintf (asm_out_file, "\t%s FDE CIE offset", ASM_COMMENT_START);
  
        fputc ('\n', asm_out_file);
!       ASM_OUTPUT_DWARF_ADDR (asm_out_file, fde->dw_fde_begin);
        if (flag_debug_asm)
! 	fprintf (asm_out_file, "\t%s FDE initial location", ASM_COMMENT_START);
  
        fputc ('\n', asm_out_file);
!       ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file,
! 				   fde->dw_fde_end, fde->dw_fde_begin);
        if (flag_debug_asm)
! 	fprintf (asm_out_file, "\t%s FDE address range", ASM_COMMENT_START);
  
        fputc ('\n', asm_out_file);
  
!       /* Loop through the Call Frame Instructions associated with
! 	 this FDE.  */
!       fde->dw_fde_current_label = fde->dw_fde_begin;
!       for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
! 	output_cfi (cfi, fde);
  
!       /* Pad the FDE out to an address sized boundary.  */
        ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
        ASM_OUTPUT_LABEL (asm_out_file, l2);
  #ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
        ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
        if (flag_debug_asm)
! 	fprintf (asm_out_file, "\t%s FDE Length Symbol", ASM_COMMENT_START);
        fputc ('\n', asm_out_file);
  #endif
!     }
  #ifndef EH_FRAME_SECTION
!   if (for_eh)
!     {
!       /* Emit terminating zero for table.  */
!       ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
!       fputc ('\n', asm_out_file);
!     }
  #endif
  #ifdef MIPS_DEBUGGING_INFO
    /* Work around Irix 6 assembler bug whereby labels at the end of a section
       get a value of 0.  Putting .align 0 after the label fixes it.  */
--- 1703,1888 ----
  	ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
  #endif
        if (flag_debug_asm)
! 	fprintf (asm_out_file, "\t%s Length of Common Information Entry",
! 		 ASM_COMMENT_START);
! 
        fputc ('\n', asm_out_file);
        ASM_OUTPUT_LABEL (asm_out_file, l1);
  
        if (for_eh)
! 	/* Now that the CIE pointer is PC-relative for EH,
! 	   use 0 to identify the CIE.  */
! 	ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
!       else
! 	ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
! 
!       if (flag_debug_asm)
! 	fprintf (asm_out_file, "\t%s CIE Identifier Tag", ASM_COMMENT_START);
! 
!       fputc ('\n', asm_out_file);
!       if (! for_eh && DWARF_OFFSET_SIZE == 8)
! 	{
! 	  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
! 	  fputc ('\n', asm_out_file);
! 	}
! 
!       ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CIE_VERSION);
!       if (flag_debug_asm)
! 	fprintf (asm_out_file, "\t%s CIE Version", ASM_COMMENT_START);
! 
!       fputc ('\n', asm_out_file);
!       if (for_eh && exception_table_p (section))
! 	{
! 	  /* The CIE contains a pointer to the exception region info for the
! 	     frame.  Make the augmentation string three bytes (including the
! 	     trailing null) so the pointer is 4-byte aligned.  The Solaris ld
! 	     can't handle unaligned relocs.  */
! 	  if (flag_debug_asm)
! 	    {
! 	      ASM_OUTPUT_DWARF_STRING (asm_out_file, "eh");
! 	      fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START);
! 	    }
! 	  else
! 	    {
! 	      ASM_OUTPUT_ASCII (asm_out_file, "eh", 3);
! 	    }
! 	  fputc ('\n', asm_out_file);
! 
! 	  ASM_OUTPUT_DWARF_ADDR (asm_out_file, section == 0
! 					       ? "__EXCEPTION_TABLE__"
! 					       : "__EH_EXCEPTION_TABLE__");
! 	  if (flag_debug_asm)
! 	    fprintf (asm_out_file, "\t%s pointer to exception region info",
! 		     ASM_COMMENT_START);
! 	}
        else
! 	{
! 	  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
! 	  if (flag_debug_asm)
! 	    fprintf (asm_out_file, "\t%s CIE Augmentation (none)",
! 		     ASM_COMMENT_START);
! 	}
! 
!       fputc ('\n', asm_out_file);
!       output_uleb128 (1);
        if (flag_debug_asm)
! 	fprintf (asm_out_file, " (CIE Code Alignment Factor)");
  
        fputc ('\n', asm_out_file);
!       output_sleb128 (DWARF_CIE_DATA_ALIGNMENT);
        if (flag_debug_asm)
! 	fprintf (asm_out_file, " (CIE Data Alignment Factor)");
  
        fputc ('\n', asm_out_file);
!       ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN);
        if (flag_debug_asm)
! 	fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START);
  
        fputc ('\n', asm_out_file);
  
!       for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
! 	output_cfi (cfi, NULL);
  
!       /* Pad the CIE out to an address sized boundary.  */
        ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
        ASM_OUTPUT_LABEL (asm_out_file, l2);
  #ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
        ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
        if (flag_debug_asm)
! 	fprintf (asm_out_file, "\t%s CIE Length Symbol", ASM_COMMENT_START);
        fputc ('\n', asm_out_file);
  #endif
! 
!       /* Loop through all of the FDE's.  */
!       for (i = 0; i < fde_table_in_use; ++i)
! 	{
! 	  fde = &fde_table[i];
! 
! 	  if (for_eh && ! fde->dw_fde_begin[section])
! 	    continue;
! 
! 	  ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, nr + i*4);
! 	  ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, nr + i*4);
! #ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
! 	  ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, nr + i*4);
! 	  if (for_eh)
! 	    ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
! 	  else
! 	    ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld);
! #else
! 	  if (for_eh)
! 	    ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1);
! 	  else
! 	    ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
! #endif
! 	  if (flag_debug_asm)
! 	    fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START);
! 	  fputc ('\n', asm_out_file);
! 	  ASM_OUTPUT_LABEL (asm_out_file, l1);
! 
! 	  if (for_eh)
! 	    ASM_OUTPUT_DWARF_DELTA (asm_out_file, l1, section == 0
! 						      ? "__FRAME_BEGIN__"
! 						      : "__EH_FRAME_BEGIN__");
! 	  else
! 	    ASM_OUTPUT_DWARF_OFFSET (asm_out_file,
! 				     stripattributes (FRAME_SECTION));
! 	  if (flag_debug_asm)
! 	    fprintf (asm_out_file, "\t%s FDE CIE offset", ASM_COMMENT_START);
! 
! 	  fputc ('\n', asm_out_file);
! 	  ASM_OUTPUT_DWARF_ADDR (asm_out_file, fde->dw_fde_begin[section]);
! 	  if (flag_debug_asm)
! 	    fprintf (asm_out_file, "\t%s FDE initial location",
! 		     ASM_COMMENT_START);
! 
! 	  fputc ('\n', asm_out_file);
! 	  ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file,
! 				       fde->dw_fde_end[section],
! 				       fde->dw_fde_begin[section]);
! 	  if (flag_debug_asm)
! 	    fprintf (asm_out_file, "\t%s FDE address range", ASM_COMMENT_START);
! 
! 	  fputc ('\n', asm_out_file);
! 
! 	  /* Loop through the Call Frame Instructions associated with
! 	     this FDE.  */
! 	  fde->dw_fde_current_label = fde->dw_fde_begin[section];
! 	  for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
! 	    {
! 	      switch (cfi->dw_cfi_opc)
! 		{
! 		case DW_CFA_advance_loc:
! 		case DW_CFA_advance_loc1:
! 		case DW_CFA_advance_loc2:
! 		case DW_CFA_advance_loc4:
! 		case DW_CFA_MIPS_advance_loc8:
! 		  if (cfi->dw_cfi_oprnd2.dw_cfi_section != section)
! 		    continue;
! 		}
! 	      output_cfi (cfi, fde);
! 	    }
! 
! 	  /* Pad the FDE out to an address sized boundary.  */
! 	  ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
! 	  ASM_OUTPUT_LABEL (asm_out_file, l2);
! #ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
! 	  ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
! 	  if (flag_debug_asm)
! 	    fprintf (asm_out_file, "\t%s FDE Length Symbol", ASM_COMMENT_START);
! 	  fputc ('\n', asm_out_file);
! #endif
! 	}
  #ifndef EH_FRAME_SECTION
!       if (for_eh)
! 	{
! 	  /* Emit terminating zero for table.  */
! 	  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
! 	  fputc ('\n', asm_out_file);
! 	}
  #endif
+     }
+ 
  #ifdef MIPS_DEBUGGING_INFO
    /* Work around Irix 6 assembler bug whereby labels at the end of a section
       get a value of 0.  Putting .align 0 after the label fixes it.  */
*************** dwarf2out_begin_prologue ()
*** 1807,1812 ****
--- 1905,1916 ----
  
    ++current_funcdef_number;
  
+   /* This is needed so that __throw(), the only function which calls
+      __builtin_unwind_init() and __builtin_eh_stub(), gets proper call
+      frame info.  */
+   if (! strcmp (current_function_name, "__throw"))
+     force_call_frame_info = 1;
+ 
    function_section (current_function_decl);
    ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
  			       current_funcdef_number);
*************** dwarf2out_begin_prologue ()
*** 1826,1836 ****
  
    /* Add the new FDE at the end of the fde_table.  */
    fde = &fde_table[fde_table_in_use++];
!   fde->dw_fde_begin = xstrdup (label);
    fde->dw_fde_current_label = NULL;
!   fde->dw_fde_end = NULL;
    fde->dw_fde_cfi = NULL;
  
    args_size = 0;
  }
  
--- 1930,1943 ----
  
    /* Add the new FDE at the end of the fde_table.  */
    fde = &fde_table[fde_table_in_use++];
!   fde->dw_fde_begin[0] = xstrdup (label);
!   fde->dw_fde_begin[1] = NULL;
    fde->dw_fde_current_label = NULL;
!   fde->dw_fde_end[0] = NULL;
!   fde->dw_fde_end[1] = NULL;
    fde->dw_fde_cfi = NULL;
  
+   current_section = 0;
    args_size = 0;
  }
  
*************** dwarf2out_end_epilogue ()
*** 1845,1855 ****
    char label[MAX_ARTIFICIAL_LABEL_BYTES];
  
    /* Output a label to mark the endpoint of the code generated for this
!      function.        */
    ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, current_funcdef_number);
    ASM_OUTPUT_LABEL (asm_out_file, label);
    fde = &fde_table[fde_table_in_use - 1];
!   fde->dw_fde_end = xstrdup (label);
  }
  
  void
--- 1952,1962 ----
    char label[MAX_ARTIFICIAL_LABEL_BYTES];
  
    /* Output a label to mark the endpoint of the code generated for this
!      function.  */
    ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, current_funcdef_number);
    ASM_OUTPUT_LABEL (asm_out_file, label);
    fde = &fde_table[fde_table_in_use - 1];
!   fde->dw_fde_end[0] = xstrdup (label);
  }
  
  void
*** egcs-971225/gcc/output.h.bak	Sun Nov  2 09:40:38 1997
--- egcs-971225/gcc/output.h	Wed Jan  7 02:22:35 1998
*************** extern void named_section		PROTO((tree, 
*** 147,152 ****
--- 147,156 ----
  /* Tell assembler to switch to the section for function DECL.  */
  extern void function_section		PROTO((tree));
  
+ /* Tell assembler to switch to the section for exception handling code of
+    function DECL.  */
+ extern void function_eh_section		PROTO((tree));
+ 
  /* Tell assembler to switch to the section for the exception table.  */
  extern void exception_section		PROTO((void));
  
*** egcs-971225/gcc/varasm.c.bak	Thu Jan  1 15:07:31 1998
--- egcs-971225/gcc/varasm.c	Wed Jan  7 03:10:53 1998
*************** static enum in_section { no_section, in_
*** 177,182 ****
--- 177,185 ----
  #ifdef BSS_SECTION_ASM_OP
    , in_bss
  #endif
+ #ifdef EH_TEXT_SECTION_ASM_OP
+   , in_eh_text
+ #endif
  #ifdef EH_FRAME_SECTION_ASM_OP
    , in_eh_frame
  #endif
*************** asm_output_aligned_bss (file, decl, name
*** 411,416 ****
--- 414,436 ----
  
  #endif /* BSS_SECTION_ASM_OP */
  
+ void
+ eh_text_section (decl)
+      tree decl;
+ {
+   if (decl == NULL_TREE || TREE_CODE (decl) != FUNCTION_DECL)
+     abort ();
+ #ifdef EH_TEXT_SECTION_ASM_OP
+   if (in_section != in_eh_text)
+     {
+       fprintf (asm_out_file, "%s\n", EH_TEXT_SECTION_ASM_OP);
+       in_section = in_eh_text;
+     }
+ #else
+   named_section (decl, ".eh_text", 0);
+ #endif
+ }
+ 
  #ifdef EH_FRAME_SECTION_ASM_OP
  void
  eh_frame_section ()
*************** function_section (decl)
*** 438,443 ****
--- 458,497 ----
      named_section (decl, (char *) 0, 0);
    else
      text_section ();
+ }
+ 
+ /* Switch to the section for exception handling code of function DECL.  */
+ 
+ void
+ function_eh_section (decl)
+      tree decl;
+ {
+   if (decl != NULL_TREE
+       && DECL_SECTION_NAME (decl) != NULL_TREE)
+     {
+       /* Small heuristic for finding the eh_text section name, given the
+ 	 normal section name. This is here because we don't want to store
+ 	 two section names in every decl.  */
+       char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+       char *name_eh;
+       if (! strncmp (name, ".gnu.linkonce.t.", 16))
+ 	{
+ 	  name_eh = alloca (strlen (name) + 1);
+ 	  strcpy (name_eh, name);
+ 	  name_eh[14] = 'u';
+ 	}
+       else
+ 	{
+ 	  name_eh = alloca (3 + strlen (name) + 1);
+ 	  if (name[0] == '.')
+ 	    sprintf (name_eh, ".eh_%s", &name[1]);
+ 	  else
+ 	    sprintf (name_eh, "eh_%s", name);
+ 	}
+       named_section (decl, name_eh, 0);
+     }
+   else
+     eh_text_section (decl);
  }
  
  /* Switch to section for variable DECL.
*** egcs-971225/gcc/frame.c.bak	Fri Jan  9 01:41:32 1998
--- egcs-971225/gcc/frame.c	Sat Jan 10 03:51:27 1998
*************** next_fde (fde *p)
*** 192,212 ****
  }
  
  /* One iteration of an insertion sort, for adding new FDEs to the array.
!    Usually the new FDE will go in at the end, so we can expect close to
!    O(n) performance.  If this turns out to be overly optimistic, we can have
!    the linker sort the FDEs so we don't have to do it at run time.  */
  
  static void
! fde_insert (fde **array, size_t i, fde *this_fde)
  {
!   array[i] = this_fde;
  
!   for (; i > 0 && fde_compare (array[i], array[i-1]) < 0; --i)
      {
-       this_fde = array[i];
        array[i] = array[i-1];
!       array[i-1] = this_fde;
      }
  }
  
  static size_t
--- 192,253 ----
  }
  
  /* One iteration of an insertion sort, for adding new FDEs to the array.
!    This is a special kind of insertion sort, optimized for data sets that
!    look like  101 102 103 201 202 105 203 204 106 107 205 206 207.
!    Usually the new FDE will go in at the end or at the last insertio point,
!    so we can expect O(n) performance, instead of the worst-case O(n^2).
!    If this turns out to be overly optimistic, we can have the linker sort
!    the FDEs so we don't have to do it at run time, or we can use an AVL
!    tree for O(n log(n)) performance.  */
! 
! typedef struct fde_accumulator
! {
!   fde **array1;
!   size_t count1;
!   fde **array2;
!   size_t count2;
! } fde_accumulator;
  
  static void
! fde_insert (fde_accumulator *accu, fde *this_fde)
  {
!   fde **array;
!   size_t i;
  
!   if (accu->count2 == 0 || fde_compare (this_fde, accu->array2[0]) < 0)
!     {
!       array = accu->array1;
!       i = accu->count1;
!     }
!   else
!     {
!       array = accu->array2;
!       i = accu->count2;
!     }
! 
!   while (i > 0 && fde_compare (this_fde, array[i-1]) < 0)
      {
        array[i] = array[i-1];
!       i--;
      }
+   if (array == accu->array1)
+     {
+       if (i < accu->count1 && accu->count2 == 0)
+ 	{
+ 	  fde **ptr1 = accu->array1 + i + 1;
+ 	  fde **ptr2 = accu->array2;
+ 	  size_t count = accu->count1 - i;
+ 	  accu->count2 = count;
+ 	  do *ptr2++ = *ptr1++; while (--count > 0);
+ 	  accu->count1 = i;
+ 	}
+       accu->count1++;
+     }
+   else
+     {
+       accu->count2++;
+     }
+   array[i] = this_fde;
  }
  
  static size_t
*************** count_fdes (fde *this_fde)
*** 227,236 ****
  }
  
  static void
! add_fdes (fde *this_fde, fde **array, size_t *i_ptr,
! 	  void **beg_ptr, void **end_ptr)
  {
-   size_t i = *i_ptr;
    void *pc_begin = *beg_ptr;
    void *pc_end = *end_ptr;
  
--- 268,275 ----
  }
  
  static void
! add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr)
  {
    void *pc_begin = *beg_ptr;
    void *pc_end = *end_ptr;
  
*************** add_fdes (fde *this_fde, fde **array, si
*** 240,246 ****
        if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
  	continue;
  
!       fde_insert (array, i++, this_fde);
  
        if (this_fde->pc_begin < pc_begin)
  	pc_begin = this_fde->pc_begin;
--- 279,285 ----
        if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
  	continue;
  
!       fde_insert (accu, this_fde);
  
        if (this_fde->pc_begin < pc_begin)
  	pc_begin = this_fde->pc_begin;
*************** add_fdes (fde *this_fde, fde **array, si
*** 248,254 ****
  	pc_end = this_fde->pc_begin + this_fde->pc_range;
      }
  
-   *i_ptr = i;
    *beg_ptr = pc_begin;
    *end_ptr = pc_end;
  }
--- 287,292 ----
*************** add_fdes (fde *this_fde, fde **array, si
*** 260,268 ****
  static void
  frame_init (struct object* ob)
  {
-   fde *this_fde;
    size_t count;
!   fde **array;
    void *pc_begin, *pc_end;
  
    if (ob->fde_array)
--- 298,305 ----
  static void
  frame_init (struct object* ob)
  {
    size_t count;
!   fde_accumulator accu;
    void *pc_begin, *pc_end;
  
    if (ob->fde_array)
*************** frame_init (struct object* ob)
*** 275,296 ****
      count = count_fdes (ob->fde_begin);
  
    ob->count = count;
!   array = (fde **) malloc (sizeof (fde *) * count);
  
    pc_begin = (void*)(uaddr)-1;
    pc_end = 0;
-   count = 0;
  
    if (ob->fde_array)
      {
        fde **p = ob->fde_array;
        for (; *p; ++p)
! 	add_fdes (*p, array, &count, &pc_begin, &pc_end);
      }
    else
!     add_fdes (ob->fde_begin, array, &count, &pc_begin, &pc_end);
  
!   ob->fde_array = array;
    ob->pc_begin = pc_begin;
    ob->pc_end = pc_end;
  }
--- 312,346 ----
      count = count_fdes (ob->fde_begin);
  
    ob->count = count;
!   accu.array1 = (fde **) malloc (sizeof (fde *) * count);
!   accu.array2 = (fde **) alloca (sizeof (fde *) * count);
!   accu.count1 = 0;
!   accu.count2 = 0;
  
    pc_begin = (void*)(uaddr)-1;
    pc_end = 0;
  
    if (ob->fde_array)
      {
        fde **p = ob->fde_array;
        for (; *p; ++p)
! 	add_fdes (*p, &accu, &pc_begin, &pc_end);
      }
    else
!     add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end);
! 
!   if (accu.count1 + accu.count2 != count)
!     abort ();
! 
!   if (accu.count2 > 0)
!     {
!       fde **ptr1 = accu.array1 + accu.count1;
!       fde **ptr2 = accu.array2;
!       size_t c = accu.count2;
!       do *ptr1++ = *ptr2++; while (--c > 0);
!     }
  
!   ob->fde_array = accu.array1;
    ob->pc_begin = pc_begin;
    ob->pc_end = pc_end;
  }
*** egcs-971225/gcc/cp/except.c.bak	Thu Jan  1 16:36:26 1998
--- egcs-971225/gcc/cp/except.c	Sun Jan  4 21:52:40 1998
*************** expand_exception_blocks ()
*** 842,847 ****
--- 842,849 ----
        rtx funcend = gen_label_rtx ();
        emit_jump (funcend);
  
+       emit_note (NULL_PTR, NOTE_INSN_EH_HANDLER_BEG);
+ 
        /* We cannot protect n regions this way if we must flow into the
  	 EH region through the top of the region, as we have to with
  	 the setjmp/longjmp approach.  */
*************** expand_exception_blocks ()
*** 855,860 ****
--- 857,864 ----
  	expand_eh_region_end (build_function_call (Terminate, NULL_TREE));
  
        expand_leftover_cleanups ();
+ 
+       emit_note (NULL_PTR, NOTE_INSN_EH_HANDLER_END);
  
        emit_label (funcend);
      }
*** egcs-971225/gcc/testsuite/g++.old-deja/g++.eh/sections1.C.bak	Sat Jan 10 03:53:45 1998
--- egcs-971225/gcc/testsuite/g++.old-deja/g++.eh/sections1.C	Sat Jan 10 03:56:11 1998
***************
*** 0 ****
--- 1,33 ----
+ // Build don't link:
+ // Special g++ Options: -fPIC -O
+ 
+ // Test label differences (in PIC case table) across sections.
+ 
+ typedef int foov (int);
+ extern int foo1 (int);
+ extern int foo2 (int);
+ extern int foo3 (int);
+ extern int foo4 (int);
+ extern int foo5 (int);
+ extern int foo6 (int);
+ extern volatile foov foo7;
+ 
+ int foo (int x)
+ {
+   try {
+     switch (x) {
+       case 1: return foo1(x);
+       case 2: return foo2(x);
+       case 3: return foo3(x);
+       case 4: return foo4(x);
+       case 5: return foo5(x);
+       case 6: goto xx;
+       case 7: return foo6(x);
+     }
+     foo7(x);
+   }
+   catch (...) {
+     xx: ;
+   }
+ }
+ 




More information about the Gcc mailing list