OSDN Git Service

* config/linux.h (ASM_COMMENT_START): Remove from here,
[pf3gnuchains/gcc-fork.git] / gcc / except.c
index a493375..4d69240 100644 (file)
@@ -1,5 +1,5 @@
 /* Implements exception handling.
-   Copyright (C) 1989, 92-96, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc.
    Contributed by Mike Stump <mrs@cygnus.com>.
 
 This file is part of GNU CC.
@@ -23,7 +23,7 @@ Boston, MA 02111-1307, USA.  */
 /* An exception is an event that can be signaled from within a
    function. This event can then be "caught" or "trapped" by the
    callers of this function. This potentially allows program flow to
-   be transferred to any arbitrary code assocated with a function call
+   be transferred to any arbitrary code associated with a function call
    several levels up the stack.
 
    The intended use for this mechanism is for signaling "exceptional
@@ -71,7 +71,7 @@ Boston, MA 02111-1307, USA.  */
    perform tasks such as destruction of objects allocated on the
    stack.
 
-   In the current implementaion, cleanups are handled by allocating an
+   In the current implementation, cleanups are handled by allocating an
    exception region for the area that the cleanup is designated for,
    and the handler for the region performs the cleanup and then
    rethrows the exception to the outer exception region. From the
@@ -97,9 +97,9 @@ Boston, MA 02111-1307, USA.  */
    On targets that support crtstuff.c, the unwind information
    is stored in a section named .eh_frame and the information for the
    entire shared object or program is registered with a call to
-   __register_frame.  On other targets, the information for each
+   __register_frame_info.  On other targets, the information for each
    translation unit is registered from the file generated by collect2.
-   __register_frame is defined in frame.c, and is responsible for
+   __register_frame_info is defined in frame.c, and is responsible for
    recording all of the unwind regions into one list (which is kept in a
    static variable named unwind_table_list).
 
@@ -107,7 +107,7 @@ Boston, MA 02111-1307, USA.  */
    throw. On machines that have unwind info support, __throw is generated
    by code in libgcc2.c, otherwise __throw is generated on a
    per-object-file basis for each source file compiled with
-   -fexceptions by the the C++ frontend.  Before __throw is invoked,
+   -fexceptions by the C++ frontend.  Before __throw is invoked,
    the current context of the throw needs to be placed in the global
    variable __eh_pc.
 
@@ -279,7 +279,7 @@ Boston, MA 02111-1307, USA.  */
    when the unwinder isn't needed.  __unwind_function is used as an
    action of last resort.  If no other method can be used for
    unwinding, __unwind_function is used.  If it cannot unwind, it
-   should call __teminate.
+   should call __terminate.
 
    By default, if the target-specific backend doesn't supply a definition
    for __unwind_function and doesn't support DWARF2_UNWIND_INFO, inlined
@@ -377,7 +377,7 @@ Boston, MA 02111-1307, USA.  */
    for all the machine specific details.  There is no variable context
    of a throw, just the one implied by the dynamic handler stack
    pointed to by the dynamic handler chain.  There is no exception
-   table, and no calls to __register_excetpions.  __sjthrow is used
+   table, and no calls to __register_exceptions.  __sjthrow is used
    instead of __throw, and it works by using the dynamic handler
    chain, and longjmp.  -fasynchronous-exceptions has no effect, as
    the elimination of trivial exception regions is not yet performed.
@@ -390,7 +390,7 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "defaults.h"
-#include <stdio.h>
+#include "system.h"
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
@@ -404,6 +404,7 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-config.h"
 #include "recog.h"
 #include "output.h"
+#include "toplev.h"
 
 /* One to use setjmp/longjmp method of generating code for exception
    handling.  */
@@ -417,33 +418,19 @@ int asynchronous_exceptions = 0;
 /* One to protect cleanup actions with a handler that calls
    __terminate, zero otherwise.  */
 
-int protect_cleanup_actions_with_terminate = 0;
+int protect_cleanup_actions_with_terminate;
 
 /* A list of labels used for exception handlers.  Created by
    find_exception_handler_labels for the optimization passes.  */
 
 rtx exception_handler_labels;
 
-/* Nonzero means that __throw was invoked. 
+/* The EH context.  Nonzero if the function has already
+   fetched a pointer to the EH context  for exception handling.  */
 
-   This is used by the C++ frontend to know if code needs to be emitted
-   for __throw or not.  */
+rtx current_function_ehc;
 
-int throw_used;
-
-/* The dynamic handler chain.  Nonzero if the function has already
-   fetched a pointer to the dynamic handler chain for exception
-   handling.  */
-
-rtx current_function_dhc;
-
-/* The dynamic cleanup chain.  Nonzero if the function has already
-   fetched a pointer to the dynamic cleanup chain for exception
-   handling.  */
-
-rtx current_function_dcc;
-
-/* A stack used for keeping track of the currectly active exception
+/* A stack used for keeping track of the currently active exception
    handling region.  As each exception region is started, an entry
    describing the region is pushed onto this stack.  The current
    region can be found by looking at the top of the stack, and as we
@@ -496,10 +483,19 @@ struct label_node *outer_context_label_stack = NULL;
 
 struct label_node *false_label_stack = NULL;
 
-/* The rtx and the tree for the saved PC value.  */
-
-rtx eh_saved_pc_rtx;
-tree eh_saved_pc;
+static void push_eh_entry      PROTO((struct eh_stack *));
+static struct eh_entry * pop_eh_entry          PROTO((struct eh_stack *));
+static void enqueue_eh_entry   PROTO((struct eh_queue *, struct eh_entry *));
+static struct eh_entry * dequeue_eh_entry      PROTO((struct eh_queue *));
+static rtx call_get_eh_context PROTO((void));
+static void start_dynamic_cleanup              PROTO((tree, tree));
+static void start_dynamic_handler              PROTO((void));
+static void expand_rethrow     PROTO((rtx));
+static void output_exception_table_entry       PROTO((FILE *, int));
+static int can_throw           PROTO((rtx));
+static rtx scan_region         PROTO((rtx, int, int *));
+static void eh_regs            PROTO((rtx *, rtx *, int));
+static void set_insn_eh_region PROTO((rtx *, int));
 
 rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
 \f
@@ -557,20 +553,6 @@ top_label_entry (stack)
   return (*stack)->u.tlabel;
 }
 
-/* Make a copy of ENTRY using xmalloc to allocate the space.  */
-
-static struct eh_entry *
-copy_eh_entry (entry)
-     struct eh_entry *entry;
-{
-  struct eh_entry *newentry;
-
-  newentry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
-  bcopy ((char *) entry, (char *) newentry, sizeof (struct eh_entry));
-
-  return newentry;
-}
-
 /* Push a new eh_node entry onto STACK.  */
 
 static void
@@ -650,7 +632,7 @@ dequeue_eh_entry (queue)
   return tempentry;
 }
 \f
-/* Routine to see if exception exception handling is turned on.
+/* Routine to see if exception handling is turned on.
    DO_WARN is non-zero if we want to inform the user that exception
    handling is turned off. 
 
@@ -717,48 +699,18 @@ add_partial_entry (handler)
   pop_obstacks ();
 }
 
-/* Get a reference to the dynamic handler chain.  It points to the
-   pointer to the next element in the dynamic handler chain.  It ends
-   when there are no more elements in the dynamic handler chain, when
-   the value is &top_elt from libgcc2.c.  Immediately after the
-   pointer, is an area suitable for setjmp/longjmp when
-   DONT_USE_BUILTIN_SETJMP is defined, and an area suitable for
-   __builtin_setjmp/__builtin_longjmp when DONT_USE_BUILTIN_SETJMP
-   isn't defined.
-
-   This routine is here to facilitate the porting of this code to
-   systems with threads.  One can either replace the routine we emit a
-   call for here in libgcc2.c, or one can modify this routine to work
-   with their thread system.  */
+/* Emit code to get EH context to current function.  */
 
-rtx
-get_dynamic_handler_chain ()
+static rtx
+call_get_eh_context ()
 {
-#if 0
-  /* Do this once we figure out how to get this to the front of the
-     function, and we really only want one per real function, not one
-     per inlined function.  */
-  if (current_function_dhc == 0)
-    {
-      rtx dhc, insns;
-      start_sequence ();
-
-      /* ... */
-      insns = get_insns ();
-      end_sequence ();
-      emit_insns_before (insns, get_first_nonparm_insn ());
-    }
-  /* We don't want a copy of the dhc, but rather, the single dhc.  */
-  return gen_rtx (MEM, Pmode, current_function_dhc);
-#endif
-
   static tree fn;
   tree expr;
 
   if (fn == NULL_TREE)
     {
       tree fntype;
-      fn = get_identifier ("__get_dynamic_handler_chain");
+      fn = get_identifier ("__get_eh_context");
       push_obstacks_nochange ();
       end_temporary_allocation ();
       fntype = build_pointer_type (build_pointer_type
@@ -778,9 +730,58 @@ get_dynamic_handler_chain ()
   expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
                expr, NULL_TREE, NULL_TREE);
   TREE_SIDE_EFFECTS (expr) = 1;
-  expr = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (expr)), expr);
 
-  return expand_expr (expr, NULL_RTX, VOIDmode, 0);
+  return copy_to_reg (expand_expr (expr, NULL_RTX, VOIDmode, 0));
+}
+
+/* Get a reference to the EH context.
+   We will only generate a register for the current function EH context here,
+   and emit a USE insn to mark that this is a EH context register.
+
+   Later, emit_eh_context will emit needed call to __get_eh_context
+   in libgcc2, and copy the value to the register we have generated. */
+
+rtx
+get_eh_context ()
+{
+  if (current_function_ehc == 0)
+    {
+      rtx insn;
+
+      current_function_ehc = gen_reg_rtx (Pmode);
+      
+      insn = gen_rtx_USE (GET_MODE (current_function_ehc),
+                         current_function_ehc);
+      insn = emit_insn_before (insn, get_first_nonparm_insn ());
+
+      REG_NOTES (insn)
+       = gen_rtx_EXPR_LIST (REG_EH_CONTEXT, current_function_ehc,
+                            REG_NOTES (insn));
+    }
+  return current_function_ehc;
+}
+     
+/* Get a reference to the dynamic handler chain.  It points to the
+   pointer to the next element in the dynamic handler chain.  It ends
+   when there are no more elements in the dynamic handler chain, when
+   the value is &top_elt from libgcc2.c.  Immediately after the
+   pointer, is an area suitable for setjmp/longjmp when
+   DONT_USE_BUILTIN_SETJMP is defined, and an area suitable for
+   __builtin_setjmp/__builtin_longjmp when DONT_USE_BUILTIN_SETJMP
+   isn't defined. */
+
+rtx
+get_dynamic_handler_chain ()
+{
+  rtx ehc, dhc, result;
+
+  ehc = get_eh_context ();
+  dhc = ehc;
+
+  result = copy_to_reg (dhc);
+
+  /* We don't want a copy of the dcc, but rather, the single dcc.  */
+  return gen_rtx_MEM (Pmode, result);
 }
 
 /* Get a reference to the dynamic cleanup chain.  It points to the
@@ -792,15 +793,15 @@ get_dynamic_handler_chain ()
 rtx
 get_dynamic_cleanup_chain ()
 {
-  rtx dhc, dcc;
+  rtx dhc, dcc, result;
 
   dhc = get_dynamic_handler_chain ();
   dcc = plus_constant (dhc, GET_MODE_SIZE (Pmode));
 
-  current_function_dcc = copy_to_reg (dcc);
+  result = copy_to_reg (dcc);
 
   /* We don't want a copy of the dcc, but rather, the single dcc.  */
-  return gen_rtx (MEM, Pmode, current_function_dcc);
+  return gen_rtx_MEM (Pmode, result);
 }
 
 /* Generate code to evaluate X and jump to LABEL if the value is nonzero.
@@ -842,7 +843,7 @@ start_dynamic_cleanup (func, arg)
      tree func;
      tree arg;
 {
-  rtx dhc, dcc;
+  rtx dcc;
   rtx new_func, new_arg;
   rtx x, buf;
   int size;
@@ -867,10 +868,10 @@ start_dynamic_cleanup (func, arg)
 
   /* Store func and arg into the cleanup list element.  */
 
-  new_func = gen_rtx (MEM, Pmode, plus_constant (XEXP (buf, 0),
-                                                GET_MODE_SIZE (Pmode)));
-  new_arg = gen_rtx (MEM, Pmode, plus_constant (XEXP (buf, 0),
-                                               GET_MODE_SIZE (Pmode)*2));
+  new_func = gen_rtx_MEM (Pmode, plus_constant (XEXP (buf, 0),
+                                               GET_MODE_SIZE (Pmode)));
+  new_arg = gen_rtx_MEM (Pmode, plus_constant (XEXP (buf, 0),
+                                              GET_MODE_SIZE (Pmode)*2));
   x = expand_expr (func, new_func, Pmode, 0);
   if (x != new_func)
     emit_move_insn (new_func, x);
@@ -923,8 +924,8 @@ start_dynamic_handler ()
   /* Store dhc into the first word of the newly allocated buffer.  */
 
   dhc = get_dynamic_handler_chain ();
-  dcc = gen_rtx (MEM, Pmode, plus_constant (XEXP (arg, 0),
-                                           GET_MODE_SIZE (Pmode)));
+  dcc = gen_rtx_MEM (Pmode, plus_constant (XEXP (arg, 0),
+                                          GET_MODE_SIZE (Pmode)));
   emit_move_insn (arg, dhc);
 
   /* Zero out the start of the cleanup chain.  */
@@ -936,15 +937,18 @@ start_dynamic_handler ()
 #ifdef DONT_USE_BUILTIN_SETJMP
   x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1, SImode, 1,
                               buf, Pmode);
+  /* If we come back here for a catch, transfer control to the handler.  */
+  jumpif_rtx (x, ehstack.top->entry->exception_handler_label);
 #else
-  x = expand_builtin_setjmp (buf, NULL_RTX);
+  {
+    /* A label to continue execution for the no exception case.  */
+    rtx noex = gen_label_rtx();
+    x = expand_builtin_setjmp (buf, NULL_RTX, noex,
+                              ehstack.top->entry->exception_handler_label);
+    emit_label (noex);
+  }
 #endif
 
-  /* If we come back here for a catch, transfer control to the
-     handler.  */
-
-  jumpif_rtx (x, ehstack.top->entry->exception_handler_label);
-
   /* We are committed to this, so update the handler chain.  */
 
   emit_move_insn (dhc, XEXP (arg, 0));
@@ -961,15 +965,13 @@ start_dynamic_handler ()
    This routine notices one particular common case in C++ code
    generation, and optimizes it so as to not need the exception
    region.  It works by creating a dynamic cleanup action, instead of
-   of a using an exception region.  */
+   a using an exception region.  */
 
 int
 expand_eh_region_start_tree (decl, cleanup)
      tree decl;
      tree cleanup;
 {
-  rtx note;
-
   /* This is the old code.  */
   if (! doing_eh (0))
     return 0;
@@ -1097,7 +1099,9 @@ expand_eh_region_end (handler)
   note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
   NOTE_BLOCK_NUMBER (note)
     = CODE_LABEL_NUMBER (entry->exception_handler_label);
-  if (exceptions_via_longjmp == 0)
+  if (exceptions_via_longjmp == 0
+      /* We share outer_context between regions; only emit it once.  */
+      && INSN_UID (entry->outer_context) == 0)
     {
       rtx label;
 
@@ -1107,14 +1111,8 @@ expand_eh_region_end (handler)
       /* 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 ();
 
-      /* Put in something that takes up space, as otherwise the end
-        address for this EH region could have the exact same address as
-        its outer region. This would cause us to miss the fact that
-        resuming exception handling with this PC value would be inside
-        the outer region.  */
-      emit_insn (gen_nop ());
-      emit_barrier ();
       emit_label (label);
     }
 
@@ -1159,9 +1157,7 @@ void
 expand_fixup_region_end (cleanup)
      tree cleanup;
 {
-  tree t;
   struct eh_node *node;
-  int yes;
 
   if (! doing_eh (0) || exceptions_via_longjmp)
     return;
@@ -1174,20 +1170,10 @@ expand_fixup_region_end (cleanup)
   if (node == 0)
     abort ();
 
-  yes = suspend_momentary ();
+  ehstack.top->entry->outer_context = node->entry->outer_context;
 
-  t = build (RTL_EXPR, void_type_node, NULL_RTX, const0_rtx);
-  TREE_SIDE_EFFECTS (t) = 1;
-  do_pending_stack_adjust ();
-  start_sequence_for_rtl_expr (t);
-  expand_internal_throw (node->entry->outer_context);
-  do_pending_stack_adjust ();
-  RTL_EXPR_SEQUENCE (t) = get_insns ();
-  end_sequence ();
-
-  resume_momentary (yes);
-
-  expand_eh_region_end (t);
+  /* Just rethrow.  size_zero_node is just a NOP.  */
+  expand_eh_region_end (size_zero_node);
 }
 
 /* If we are using the setjmp/longjmp EH codegen method, we emit a
@@ -1214,38 +1200,19 @@ emit_throw ()
 #ifdef JUMP_TO_THROW
       emit_indirect_jump (throw_libfunc);
 #else
-#ifndef DWARF2_UNWIND_INFO
-      /* Prevent assemble_external from doing anything with this symbol.  */
-      SYMBOL_REF_USED (throw_libfunc) = 1;
-#endif
       emit_library_call (throw_libfunc, 0, VOIDmode, 0);
 #endif
-      throw_used = 1;
     }
   emit_barrier ();
 }
 
-/* An internal throw with an indirect CONTEXT we want to throw from.
-   CONTEXT evaluates to the context of the throw.  */
-
-static void
-expand_internal_throw_indirect (context)
-     rtx context;
-{
-  assemble_external (eh_saved_pc);
-  emit_move_insn (eh_saved_pc_rtx, context);
-  emit_throw ();
-}
-
-/* An internal throw with a direct CONTEXT we want to throw from.
-   CONTEXT must be a label; its address will be used as the context of
-   the throw.  */
+/* Throw the current exception.  If appropriate, this is done by jumping
+   to the next handler.  */
 
 void
-expand_internal_throw (context)
-     rtx context;
+expand_internal_throw ()
 {
-  expand_internal_throw_indirect (gen_rtx (LABEL_REF, Pmode, context));
+  emit_throw ();
 }
 
 /* Called from expand_exception_blocks and expand_end_catch_block to
@@ -1284,19 +1251,9 @@ expand_leftover_cleanups ()
 
       prev = get_last_insn ();
       if (prev == NULL || GET_CODE (prev) != BARRIER)
-       {
-         if (exceptions_via_longjmp)
-           emit_throw ();
-         else
-           {
-             /* The below can be optimized away, and we could just
-                fall into the next EH handler, if we are certain they
-                are nested.  */
-             /* Emit code to throw to the outer context if we fall off
-                the end of the handler.  */
-             expand_internal_throw (entry->outer_context);
-           }
-       }
+       /* Emit code to throw to the outer context if we fall off
+          the end of the handler.  */
+       expand_rethrow (entry->outer_context);
 
       do_pending_stack_adjust ();
       free (entry);
@@ -1325,12 +1282,12 @@ expand_start_all_catch ()
 {
   struct eh_entry *entry;
   tree label;
+  rtx outer_context;
 
   if (! doing_eh (1))
     return;
 
-  push_label_entry (&outer_context_label_stack,
-                   ehstack.top->entry->outer_context, NULL_TREE);
+  outer_context = ehstack.top->entry->outer_context;
 
   /* End the try block.  */
   expand_eh_region_end (integer_zero_node);
@@ -1339,19 +1296,9 @@ expand_start_all_catch ()
   label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
 
   /* The label for the exception handling block that we will save.
-     This is Lresume in the documention.  */
+     This is Lresume in the documentation.  */
   expand_label (label);
   
-  if (exceptions_via_longjmp == 0)
-    {
-      /* Put in something that takes up space, as otherwise the end
-        address for the EH region could have the exact same address as
-        the outer region, causing us to miss the fact that resuming
-        exception handling with this PC value would be inside the outer
-        region.  */
-      emit_insn (gen_nop ());
-    }
-
   /* Push the label that points to where normal flow is resumed onto
      the top of the label stack.  */
   push_label_entry (&caught_return_label_stack, NULL_RTX, label);
@@ -1402,25 +1349,24 @@ expand_start_all_catch ()
 
       prev = get_last_insn ();
       if (prev == NULL || GET_CODE (prev) != BARRIER)
-       {
-         if (exceptions_via_longjmp)
-           emit_throw ();
-         else
-           {
-             /* Code to throw out to outer context when we fall off end
-                of the handler. We can't do this here for catch blocks,
-                so it's done in expand_end_all_catch instead.
-
-                The below can be optimized away (and we could just fall
-                into the next EH handler) if we are certain they are
-                nested.  */
+       /* Code to throw out to outer context when we fall off end
+          of the handler. We can't do this here for catch blocks,
+          so it's done in expand_end_all_catch instead.  */
+       expand_rethrow (entry->outer_context);
 
-             expand_internal_throw (entry->outer_context);
-           }
-       }
       do_pending_stack_adjust ();
       free (entry);
     }
+
+  /* If we are not doing setjmp/longjmp EH, because we are reordered
+     out of line, we arrange to rethrow in the outer context.  We need to
+     do this because we are not physically within the region, if any, that
+     logically contains this catch block.  */
+  if (! exceptions_via_longjmp)
+    {
+      expand_eh_region_start ();
+      ehstack.top->entry->outer_context = outer_context;
+    }
 }
 
 /* Finish up the catch block.  At this point all the insns for the
@@ -1432,28 +1378,30 @@ expand_start_all_catch ()
 void
 expand_end_all_catch ()
 {
-  rtx new_catch_clause;
+  rtx new_catch_clause, outer_context = NULL_RTX;
 
   if (! doing_eh (1))
     return;
 
-  if (exceptions_via_longjmp)
-    emit_throw ();
-  else
+  if (! exceptions_via_longjmp)
     {
-      /* 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.
+      outer_context = ehstack.top->entry->outer_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.  */
-
-      expand_internal_throw (outer_context_label_stack->u.rlabel);
+      /* Finish the rethrow region.  size_zero_node is just a NOP.  */
+      expand_eh_region_end (size_zero_node);
     }
 
+  /* 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.  */
+  expand_rethrow (outer_context);
+
   /* Now we have the complete catch sequence.  */
   new_catch_clause = get_insns ();
   end_sequence ();
@@ -1472,6 +1420,18 @@ expand_end_all_catch ()
   /* Here we fall through into the continuation code.  */
 }
 
+/* Rethrow from the outer context LABEL.  */
+
+static void
+expand_rethrow (label)
+     rtx label;
+{
+  if (exceptions_via_longjmp)
+    emit_throw ();
+  else
+    emit_jump (label);
+}
+
 /* End all the pending exception regions on protect_list. The handlers
    will be emitted when expand_leftover_cleanups is invoked.  */
 
@@ -1589,19 +1549,7 @@ exception_table_p ()
   return 0;
 }
 
-/* 1 if we need a static constructor to register EH table info.  */
-
-int
-register_exception_table_p ()
-{
-#if defined (DWARF2_UNWIND_INFO)
-  return 0;
-#endif
-
-  return exception_table_p ();
-}
-
-/* Output the entry of the exception table corresponding to to the
+/* Output the entry of the exception table corresponding to the
    exception region numbered N to file FILE. 
 
    N is the code label number corresponding to the handler of the
@@ -1616,15 +1564,15 @@ output_exception_table_entry (file, n)
   rtx sym;
 
   ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
-  sym = gen_rtx (SYMBOL_REF, Pmode, buf);
+  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);
+  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);
+  sym = gen_rtx_SYMBOL_REF (Pmode, buf);
   assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
 
   putc ('\n', file);           /* blank line */
@@ -1658,202 +1606,49 @@ output_exception_table ()
   assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
   putc ('\n', asm_out_file);           /* blank line */
 }
-
-/* Generate code to initialize the exception table at program startup
-   time.  */
-
-void
-register_exception_table ()
-{
-  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
-                    VOIDmode, 1,
-                    gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
-                    Pmode);
-}
 \f
-/* Emit the RTL for the start of the per-function unwinder for the
-   current function. See emit_unwinder for further information.
+/* Emit code to get EH context.
+   
+   We have to scan thru the code to find possible EH context registers.
+   Inlined functions may use it too, and thus we'll have to be able
+   to change them too.
 
-   DOESNT_NEED_UNWINDER is a target-specific macro that determines if
-   the current function actually needs a per-function unwinder or not.
-   By default, all functions need one.  */
+   This is done only if using exceptions_via_longjmp. */
 
 void
-start_eh_unwinder ()
+emit_eh_context ()
 {
-#ifdef DOESNT_NEED_UNWINDER
-  if (DOESNT_NEED_UNWINDER)
-    return;
-#endif
-
-  /* If we are using the setjmp/longjmp implementation, we don't need a
-     per function unwinder.  */
-
-  if (exceptions_via_longjmp)
-    return;
-
-#ifdef DWARF2_UNWIND_INFO
-  return;
-#endif
-
-  expand_eh_region_start ();
-}
-
-/* Emit insns for the end of the per-function unwinder for the
-   current function.  */
-
-void
-end_eh_unwinder ()
-{
-  tree expr;
-  rtx return_val_rtx, ret_val, label, end, insns;
+  rtx insn;
+  rtx ehc = 0;
 
   if (! doing_eh (0))
     return;
 
-#ifdef DOESNT_NEED_UNWINDER
-  if (DOESNT_NEED_UNWINDER)
-    return;
-#endif
-
-  /* If we are using the setjmp/longjmp implementation, we don't need a
-     per function unwinder.  */
-
-  if (exceptions_via_longjmp)
-    return;
-
-#ifdef DWARF2_UNWIND_INFO
-  return;
-#else /* DWARF2_UNWIND_INFO */
-
-  assemble_external (eh_saved_pc);
-
-  expr = make_node (RTL_EXPR);
-  TREE_TYPE (expr) = void_type_node;
-  RTL_EXPR_RTL (expr) = const0_rtx;
-  TREE_SIDE_EFFECTS (expr) = 1;
-  start_sequence_for_rtl_expr (expr);
-
-  /* ret_val will contain the address of the code where the call
-     to the current function occurred.  */
-  ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
-                                       0, hard_frame_pointer_rtx);
-  return_val_rtx = copy_to_reg (ret_val);
-
-  /* Get the address we need to use to determine what exception
-     handler should be invoked, and store it in __eh_pc.  */
-  return_val_rtx = eh_outer_context (return_val_rtx);
-  return_val_rtx = expand_binop (Pmode, sub_optab, return_val_rtx, GEN_INT (1),
-                                NULL_RTX, 0, OPTAB_LIB_WIDEN);
-  emit_move_insn (eh_saved_pc_rtx, return_val_rtx);
-  
-  /* Either set things up so we do a return directly to __throw, or
-     we return here instead.  */
-#ifdef JUMP_TO_THROW
-  emit_move_insn (ret_val, throw_libfunc);
-#else
-  label = gen_label_rtx ();
-  emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label));
-#endif
-
-#ifdef RETURN_ADDR_OFFSET
-  return_val_rtx = plus_constant (ret_val, -RETURN_ADDR_OFFSET);
-  if (return_val_rtx != ret_val)
-    emit_move_insn (ret_val, return_val_rtx);
-#endif
-  
-  end = gen_label_rtx ();
-  emit_jump (end);  
-
-  RTL_EXPR_SEQUENCE (expr) = get_insns ();
-  end_sequence ();
-
-  expand_eh_region_end (expr);
-
-  emit_jump (end);
-
-#ifndef JUMP_TO_THROW
-  emit_label (label);
-  emit_throw ();
-#endif
-  
-  expand_leftover_cleanups ();
-
-  emit_label (end);
-
-#ifdef HAVE_return
-  if (HAVE_return)
-    {
-      emit_jump_insn (gen_return ());
-      emit_barrier ();
-    }
-#endif
-#endif /* DWARF2_UNWIND_INFO */
-}
-
-/* If necessary, emit insns for the per function unwinder for the
-   current function.  Called after all the code that needs unwind
-   protection is output.  
-
-   The unwinder takes care of catching any exceptions that have not
-   been previously caught within the function, unwinding the stack to
-   the next frame, and rethrowing using the address of the current
-   function's caller as the context of the throw.
-
-   On some platforms __throw can do this by itself (or with the help
-   of __unwind_function) so the per-function unwinder is
-   unnecessary.
-  
-   We cannot place the unwinder into the function until after we know
-   we are done inlining, as we don't want to have more than one
-   unwinder per non-inlined function.  */
-
-void
-emit_unwinder ()
-{
-  rtx insns, insn;
-
-  start_sequence ();
-  start_eh_unwinder ();
-  insns = get_insns ();
-  end_sequence ();
-
-  /* We place the start of the exception region associated with the
-     per function unwinder at the top of the function.  */
-  if (insns)
-    emit_insns_after (insns, get_insns ());
-
-  start_sequence ();
-  end_eh_unwinder ();
-  insns = get_insns ();
-  end_sequence ();
-
-  /* And we place the end of the exception region before the USE and
-     CLOBBER insns that may come at the end of the function.  */
-  if (insns == 0)
-    return;
-
-  insn = get_last_insn ();
-  while (GET_CODE (insn) == NOTE
-        || (GET_CODE (insn) == INSN
-            && (GET_CODE (PATTERN (insn)) == USE
-                || GET_CODE (PATTERN (insn)) == CLOBBER)))
-    insn = PREV_INSN (insn);
-
-  if (GET_CODE (insn) == CODE_LABEL
-      && GET_CODE (PREV_INSN (insn)) == BARRIER)
-    {
-      insn = PREV_INSN (insn);
-    }
-  else
-    {
-      rtx label = gen_label_rtx ();
-      emit_label_after (label, insn);
-      insn = emit_jump_insn_after (gen_jump (label), insn);
-      insn = emit_barrier_after (insn);
-    }
-    
-  emit_insns_after (insns, insn);
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (GET_CODE (insn) == INSN
+       && GET_CODE (PATTERN (insn)) == USE)
+      {
+       rtx reg = find_reg_note (insn, REG_EH_CONTEXT, 0);
+       if (reg)
+         {
+           rtx insns;
+           
+           start_sequence ();
+
+           /* If this is the first use insn, emit the call here.  This
+              will always be at the top of our function, because if
+              expand_inline_function notices a REG_EH_CONTEXT note, it
+              adds a use insn to this function as well.  */
+           if (ehc == 0)
+             ehc = call_get_eh_context ();
+
+           emit_move_insn (XEXP (reg, 0), ehc);
+           insns = get_insns ();
+           end_sequence ();
+
+           emit_insns_before (insns, insn);
+         }
+      }
 }
 
 /* Scan the current insns and build a list of handler labels. The
@@ -1912,8 +1707,8 @@ find_exception_handler_labels ()
 
              if (label)
                exception_handler_labels
-                 = gen_rtx (EXPR_LIST, VOIDmode,
-                            label, exception_handler_labels);
+                 = gen_rtx_EXPR_LIST (VOIDmode,
+                                      label, exception_handler_labels);
              else
                warning ("didn't find handler for EH region %d",
                         NOTE_BLOCK_NUMBER (insn));
@@ -1984,7 +1779,7 @@ check_exception_handler_labels ()
                  == NOTE_BLOCK_NUMBER (insn))
                break;
            }
-         if (handler == NULL_RTX)
+         if (handler == NULL_RTX && !flag_syntax_only)
            warning ("region exists, no handler %d",
                     NOTE_BLOCK_NUMBER (insn));
        }
@@ -2002,15 +1797,6 @@ check_exception_handler_labels ()
 void
 init_eh ()
 {
-  /* Generate rtl to reference the variable in which the PC of the
-     current context is saved.  */
-  tree type = build_pointer_type (make_node (VOID_TYPE));
-
-  eh_saved_pc = build_decl (VAR_DECL, get_identifier ("__eh_pc"), type);
-  DECL_EXTERNAL (eh_saved_pc) = 1;
-  TREE_PUBLIC (eh_saved_pc) = 1;
-  make_decl_rtl (eh_saved_pc, NULL_PTR, 1);
-  eh_saved_pc_rtx = DECL_RTL (eh_saved_pc);
 }
 
 /* Initialize the per-function EH information.  */
@@ -2024,8 +1810,7 @@ init_eh_for_function ()
   false_label_stack = 0;
   caught_return_label_stack = 0;
   protect_list = NULL_TREE;
-  current_function_dhc = NULL_RTX;
-  current_function_dcc = NULL_RTX;
+  current_function_ehc = NULL_RTX;
 }
 
 /* Save some of the per-function EH info into the save area denoted by
@@ -2046,10 +1831,9 @@ save_eh_status (p)
   p->false_label_stack = false_label_stack;
   p->caught_return_label_stack = caught_return_label_stack;
   p->protect_list = protect_list;
-  p->dhc = current_function_dhc;
-  p->dcc = current_function_dcc;
+  p->ehc = current_function_ehc;
 
-  init_eh ();
+  init_eh_for_function ();
 }
 
 /* Restore the per-function EH info saved into the area denoted by P.  
@@ -2069,8 +1853,7 @@ restore_eh_status (p)
   catch_clauses        = p->catch_clauses;
   ehqueue = p->ehqueue;
   ehstack = p->ehstack;
-  current_function_dhc = p->dhc;
-  current_function_dcc = p->dcc;
+  current_function_ehc = p->ehc;
 }
 \f
 /* This section is for the exception handling specific optimization
@@ -2215,7 +1998,7 @@ scan_region (insn, n, delete_outer)
 void
 exception_optimize ()
 {
-  rtx insn, regions = NULL_RTX;
+  rtx insn;
   int n;
 
   /* Remove empty regions.  */
@@ -2338,7 +2121,7 @@ eh_regs (r1, r2, outgoing)
       for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
        if (call_used_regs[i] && ! fixed_regs[i] && i != REGNO (reg1))
          {
-           reg2 = gen_rtx (REG, Pmode, i);
+           reg2 = gen_rtx_REG (Pmode, i);
            break;
          }
 
@@ -2359,7 +2142,7 @@ expand_builtin_eh_stub ()
 {
   rtx stub_start = gen_label_rtx ();
   rtx after_stub = gen_label_rtx ();
-  rtx handler, offset, temp;
+  rtx handler, offset;
 
   emit_jump (after_stub);
   emit_label (stub_start);
@@ -2370,7 +2153,7 @@ expand_builtin_eh_stub ()
   emit_indirect_jump (handler);
 
   emit_label (after_stub);
-  return gen_rtx (LABEL_REF, Pmode, stub_start);
+  return gen_rtx_LABEL_REF (Pmode, stub_start);
 }
 
 /* Set up the registers for passing the handler address and stack offset
@@ -2388,6 +2171,113 @@ expand_builtin_set_eh_regs (handler, offset)
   store_expr (handler, reg1, 0);
 
   /* These will be used by the stub.  */
-  emit_insn (gen_rtx (USE, VOIDmode, reg1));
-  emit_insn (gen_rtx (USE, VOIDmode, reg2));
+  emit_insn (gen_rtx_USE (VOIDmode, reg1));
+  emit_insn (gen_rtx_USE (VOIDmode, reg2));
 }
+
+\f
+
+/* This contains the code required to verify whether arbitrary instructions
+   are in the same exception region. */
+
+static int *insn_eh_region = (int *)0;
+static int maximum_uid;
+
+static void
+set_insn_eh_region (first, region_num)
+     rtx *first;
+     int region_num;
+{
+  rtx insn;
+  int rnum;
+
+  for (insn = *first; insn; insn = NEXT_INSN (insn))
+    {
+      if ((GET_CODE (insn) == NOTE) && 
+                        (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG))
+        {
+          rnum = NOTE_BLOCK_NUMBER (insn);
+          insn_eh_region[INSN_UID (insn)] =  rnum;
+          insn = NEXT_INSN (insn);
+          set_insn_eh_region (&insn, rnum);
+          /* Upon return, insn points to the EH_REGION_END of nested region */
+          continue;
+        }
+      insn_eh_region[INSN_UID (insn)] = region_num;
+      if ((GET_CODE (insn) == NOTE) && 
+            (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
+        break;
+    }
+  *first = insn;
+}
+
+/* Free the insn table, an make sure it cannot be used again. */
+
+void free_insn_eh_region () 
+{
+  if (!doing_eh (0))
+    return;
+
+  if (insn_eh_region)
+    {
+      free (insn_eh_region);
+      insn_eh_region = (int *)0;
+    }
+}
+
+/* Initialize the table. max_uid must be calculated and handed into 
+   this routine. If it is unavailable, passing a value of 0 will 
+   cause this routine to calculate it as well. */
+
+void init_insn_eh_region (first, max_uid)
+     rtx first;
+     int max_uid;
+{
+  rtx insn;
+
+  if (!doing_eh (0))
+    return;
+
+  if (insn_eh_region)
+    free_insn_eh_region();
+
+  if (max_uid == 0) 
+    for (insn = first; insn; insn = NEXT_INSN (insn))
+      if (INSN_UID (insn) > max_uid)       /* find largest UID */
+        max_uid = INSN_UID (insn);
+
+  maximum_uid = max_uid;
+  insn_eh_region = (int *) malloc ((max_uid + 1) * sizeof (int));
+  insn = first;
+  set_insn_eh_region (&insn, 0);
+}
+
+
+/* Check whether 2 instructions are within the same region. */
+
+int in_same_eh_region(insn1, insn2) 
+     rtx insn1,insn2;
+{
+  int ret, uid1, uid2;
+
+  /* If no exceptions, instructions are always in same region. */
+  if (!doing_eh (0))
+    return 1;
+
+  /* If the table isn't allocated, assume the worst. */
+  if (!insn_eh_region)  
+    return 0;
+
+  uid1 = INSN_UID (insn1);
+  uid2 = INSN_UID (insn2);
+
+  /* if instructions have been allocated beyond the end, either
+     the table is out of date, or this is a late addition, or
+     something... Assume the worst. */
+  if (uid1 > maximum_uid || uid2 > maximum_uid)
+    return 0;
+
+  ret = (insn_eh_region[uid1] == insn_eh_region[uid2]);
+  return ret;
+}
+