OSDN Git Service

2004-05-21 Andrew Pinski <pinskia@physics.uc.edu>
[pf3gnuchains/gcc-fork.git] / gcc / except.c
index a999834..9f1bfe9 100644 (file)
@@ -1,6 +1,6 @@
 /* Implements exception handling.
    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Contributed by Mike Stump <mrs@cygnus.com>.
 
 This file is part of GCC.
@@ -73,32 +73,25 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm_p.h"
 #include "target.h"
 #include "langhooks.h"
+#include "cgraph.h"
+#include "diagnostic.h"
 
 /* Provide defaults for stuff that may not be defined when using
    sjlj exceptions.  */
-#ifndef EH_RETURN_STACKADJ_RTX
-#define EH_RETURN_STACKADJ_RTX 0
-#endif
-#ifndef EH_RETURN_HANDLER_RTX
-#define EH_RETURN_HANDLER_RTX 0
-#endif
 #ifndef EH_RETURN_DATA_REGNO
 #define EH_RETURN_DATA_REGNO(N) INVALID_REGNUM
 #endif
 
 
-/* Nonzero means enable synchronous exceptions for non-call instructions.  */
-int flag_non_call_exceptions;
-
 /* Protect cleanup actions with must-not-throw regions, with a call
    to the given failure handler.  */
-tree (*lang_protect_cleanup_actions) PARAMS ((void));
+tree (*lang_protect_cleanup_actions) (void);
 
 /* Return true if type A catches type B.  */
-int (*lang_eh_type_covers) PARAMS ((tree a, tree b));
+int (*lang_eh_type_covers) (tree a, tree b);
 
 /* Map a type to a runtime object to match type.  */
-tree (*lang_eh_runtime_type) PARAMS ((tree));
+tree (*lang_eh_runtime_type) (tree);
 
 /* A hash table of label to region number.  */
 
@@ -108,7 +101,7 @@ struct ehl_map_entry GTY(())
   struct eh_region *region;
 };
 
-static int call_site_base;
+static GTY(()) int call_site_base;
 static GTY ((param_is (union tree_node)))
   htab_t type_to_runtime_map;
 
@@ -139,7 +132,7 @@ struct eh_region GTY(())
 
   /* Each region does exactly one thing.  */
   enum eh_region_type
-  {
+  { 
     ERT_UNKNOWN = 0,
     ERT_CLEANUP,
     ERT_TRY,
@@ -185,20 +178,20 @@ struct eh_region GTY(())
     /* Retain the cleanup expression even after expansion so that
        we can match up fixup regions.  */
     struct eh_region_u_cleanup {
-      tree exp;
       struct eh_region *prev_try;
     } GTY ((tag ("ERT_CLEANUP"))) cleanup;
 
     /* The real region (by expression and by pointer) that fixup code
        should live in.  */
     struct eh_region_u_fixup {
-      tree cleanup_exp;
       struct eh_region *real_region;
+      bool resolved;
     } GTY ((tag ("ERT_FIXUP"))) fixup;
   } GTY ((desc ("%0.type"))) u;
 
   /* Entry point for this region's handler before landing pads are built.  */
   rtx label;
+  tree tree_label;
 
   /* Entry point for this region's handler from the runtime eh library.  */
   rtx landing_pad;
@@ -209,6 +202,9 @@ struct eh_region GTY(())
   /* The RESX insn for handing off control to the next outermost handler,
      if appropriate.  */
   rtx resume;
+
+  /* True if something in this region may throw.  */
+  unsigned may_contain_throw : 1;
 };
 
 struct call_site_record GTY(())
@@ -238,13 +234,13 @@ struct eh_status GTY(())
   int built_landing_pads;
   int last_region_number;
 
-  varray_type ttype_data;
+  VEC(tree,gc) *ttype_data;
   varray_type ehspec_data;
   varray_type action_record_data;
 
   htab_t GTY ((param_is (struct ehl_map_entry))) exception_handler_label_map;
 
-  struct call_site_record * GTY ((length ("%h.call_site_data_used"))) 
+  struct call_site_record * GTY ((length ("%h.call_site_data_used")))
     call_site_data;
   int call_site_data_used;
   int call_site_data_size;
@@ -255,66 +251,44 @@ struct eh_status GTY(())
 
   rtx sjlj_fc;
   rtx sjlj_exit_after;
+
+  htab_t GTY((param_is (struct throw_stmt_node))) throw_stmt_table;
 };
 
 \f
-static int t2r_eq                              PARAMS ((const PTR,
-                                                        const PTR));
-static hashval_t t2r_hash                      PARAMS ((const PTR));
-static void add_type_for_runtime               PARAMS ((tree));
-static tree lookup_type_for_runtime            PARAMS ((tree));
-
-static struct eh_region *expand_eh_region_end  PARAMS ((void));
-
-static rtx get_exception_filter                        PARAMS ((struct function *));
-
-static void collect_eh_region_array            PARAMS ((void));
-static void resolve_fixup_regions              PARAMS ((void));
-static void remove_fixup_regions               PARAMS ((void));
-static void remove_unreachable_regions         PARAMS ((rtx));
-static void convert_from_eh_region_ranges_1    PARAMS ((rtx *, int *, int));
-
-static struct eh_region *duplicate_eh_region_1 PARAMS ((struct eh_region *,
-                                                    struct inline_remap *));
-static void duplicate_eh_region_2              PARAMS ((struct eh_region *,
-                                                        struct eh_region **));
-static int ttypes_filter_eq                    PARAMS ((const PTR,
-                                                        const PTR));
-static hashval_t ttypes_filter_hash            PARAMS ((const PTR));
-static int ehspec_filter_eq                    PARAMS ((const PTR,
-                                                        const PTR));
-static hashval_t ehspec_filter_hash            PARAMS ((const PTR));
-static int add_ttypes_entry                    PARAMS ((htab_t, tree));
-static int add_ehspec_entry                    PARAMS ((htab_t, htab_t,
-                                                        tree));
-static void assign_filter_values               PARAMS ((void));
-static void build_post_landing_pads            PARAMS ((void));
-static void connect_post_landing_pads          PARAMS ((void));
-static void dw2_build_landing_pads             PARAMS ((void));
+static int t2r_eq (const void *, const void *);
+static hashval_t t2r_hash (const void *);
+static void add_type_for_runtime (tree);
+static tree lookup_type_for_runtime (tree);
+
+static void remove_unreachable_regions (rtx);
+
+static int ttypes_filter_eq (const void *, const void *);
+static hashval_t ttypes_filter_hash (const void *);
+static int ehspec_filter_eq (const void *, const void *);
+static hashval_t ehspec_filter_hash (const void *);
+static int add_ttypes_entry (htab_t, tree);
+static int add_ehspec_entry (htab_t, htab_t, tree);
+static void assign_filter_values (void);
+static void build_post_landing_pads (void);
+static void connect_post_landing_pads (void);
+static void dw2_build_landing_pads (void);
 
 struct sjlj_lp_info;
-static bool sjlj_find_directly_reachable_regions
-     PARAMS ((struct sjlj_lp_info *));
-static void sjlj_assign_call_site_values
-     PARAMS ((rtx, struct sjlj_lp_info *));
-static void sjlj_mark_call_sites
-     PARAMS ((struct sjlj_lp_info *));
-static void sjlj_emit_function_enter           PARAMS ((rtx));
-static void sjlj_emit_function_exit            PARAMS ((void));
-static void sjlj_emit_dispatch_table
-     PARAMS ((rtx, struct sjlj_lp_info *));
-static void sjlj_build_landing_pads            PARAMS ((void));
-
-static hashval_t ehl_hash                      PARAMS ((const PTR));
-static int ehl_eq                              PARAMS ((const PTR,
-                                                        const PTR));
-static void add_ehl_entry                      PARAMS ((rtx,
-                                                        struct eh_region *));
-static void remove_exception_handler_label     PARAMS ((rtx));
-static void remove_eh_handler                  PARAMS ((struct eh_region *));
-static int for_each_eh_label_1                 PARAMS ((PTR *, PTR));
-
-struct reachable_info;
+static bool sjlj_find_directly_reachable_regions (struct sjlj_lp_info *);
+static void sjlj_assign_call_site_values (rtx, struct sjlj_lp_info *);
+static void sjlj_mark_call_sites (struct sjlj_lp_info *);
+static void sjlj_emit_function_enter (rtx);
+static void sjlj_emit_function_exit (void);
+static void sjlj_emit_dispatch_table (rtx, struct sjlj_lp_info *);
+static void sjlj_build_landing_pads (void);
+
+static hashval_t ehl_hash (const void *);
+static int ehl_eq (const void *, const void *);
+static void add_ehl_entry (rtx, struct eh_region *);
+static void remove_exception_handler_label (rtx);
+static void remove_eh_handler (struct eh_region *);
+static int for_each_eh_label_1 (void **, void *);
 
 /* The return value of reachable_next_level.  */
 enum reachable_code
@@ -329,30 +303,24 @@ enum reachable_code
   RNL_BLOCKED
 };
 
-static int check_handled                       PARAMS ((tree, tree));
-static void add_reachable_handler
-     PARAMS ((struct reachable_info *, struct eh_region *,
-             struct eh_region *));
-static enum reachable_code reachable_next_level
-     PARAMS ((struct eh_region *, tree, struct reachable_info *));
-
-static int action_record_eq                    PARAMS ((const PTR,
-                                                        const PTR));
-static hashval_t action_record_hash            PARAMS ((const PTR));
-static int add_action_record                   PARAMS ((htab_t, int, int));
-static int collect_one_action_chain            PARAMS ((htab_t,
-                                                        struct eh_region *));
-static int add_call_site                       PARAMS ((rtx, int));
-
-static void push_uleb128                       PARAMS ((varray_type *,
-                                                        unsigned int));
-static void push_sleb128                       PARAMS ((varray_type *, int));
+struct reachable_info;
+static enum reachable_code reachable_next_level (struct eh_region *, tree,
+                                                struct reachable_info *);
+
+static int action_record_eq (const void *, const void *);
+static hashval_t action_record_hash (const void *);
+static int add_action_record (htab_t, int, int);
+static int collect_one_action_chain (htab_t, struct eh_region *);
+static int add_call_site (rtx, int);
+
+static void push_uleb128 (varray_type *, unsigned int);
+static void push_sleb128 (varray_type *, int);
 #ifndef HAVE_AS_LEB128
-static int dw2_size_of_call_site_table         PARAMS ((void));
-static int sjlj_size_of_call_site_table                PARAMS ((void));
+static int dw2_size_of_call_site_table (void);
+static int sjlj_size_of_call_site_table (void);
 #endif
-static void dw2_output_call_site_table         PARAMS ((void));
-static void sjlj_output_call_site_table                PARAMS ((void));
+static void dw2_output_call_site_table (void);
+static void sjlj_output_call_site_table (void);
 
 \f
 /* Routine to see if exception handling is turned on.
@@ -363,8 +331,7 @@ static void sjlj_output_call_site_table             PARAMS ((void));
    compiler tries to use any exception-specific functions.  */
 
 int
-doing_eh (do_warn)
-     int do_warn;
+doing_eh (int do_warn)
 {
   if (! flag_exceptions)
     {
@@ -381,7 +348,7 @@ doing_eh (do_warn)
 
 \f
 void
-init_eh ()
+init_eh (void)
 {
   if (! flag_exceptions)
     return;
@@ -394,7 +361,7 @@ init_eh ()
     {
       tree f_jbuf, f_per, f_lsda, f_prev, f_cs, f_data, tmp;
 
-      sjlj_fc_type_node = (*lang_hooks.types.make_type) (RECORD_TYPE);
+      sjlj_fc_type_node = lang_hooks.types.make_type (RECORD_TYPE);
 
       f_prev = build_decl (FIELD_DECL, get_identifier ("__prev"),
                           build_pointer_type (sjlj_fc_type_node));
@@ -404,8 +371,8 @@ init_eh ()
                         integer_type_node);
       DECL_FIELD_CONTEXT (f_cs) = sjlj_fc_type_node;
 
-      tmp = build_index_type (build_int_2 (4 - 1, 0));
-      tmp = build_array_type ((*lang_hooks.types.type_for_mode) (word_mode, 1),
+      tmp = build_index_type (build_int_cst (NULL_TREE, 4 - 1));
+      tmp = build_array_type (lang_hooks.types.type_for_mode (word_mode, 1),
                              tmp);
       f_data = build_decl (FIELD_DECL, get_identifier ("__data"), tmp);
       DECL_FIELD_CONTEXT (f_data) = sjlj_fc_type_node;
@@ -420,19 +387,17 @@ init_eh ()
 
 #ifdef DONT_USE_BUILTIN_SETJMP
 #ifdef JMP_BUF_SIZE
-      tmp = build_int_2 (JMP_BUF_SIZE - 1, 0);
+      tmp = build_int_cst (NULL_TREE, JMP_BUF_SIZE - 1);
 #else
       /* Should be large enough for most systems, if it is not,
         JMP_BUF_SIZE should be defined with the proper value.  It will
         also tend to be larger than necessary for most systems, a more
         optimal port will define JMP_BUF_SIZE.  */
-      tmp = build_int_2 (FIRST_PSEUDO_REGISTER + 2 - 1, 0);
+      tmp = build_int_cst (NULL_TREE, FIRST_PSEUDO_REGISTER + 2 - 1);
 #endif
 #else
-      /* This is 2 for builtin_setjmp, plus whatever the target requires
-        via STACK_SAVEAREA_MODE (SAVE_NONLOCAL).  */
-      tmp = build_int_2 ((GET_MODE_SIZE (STACK_SAVEAREA_MODE (SAVE_NONLOCAL))
-                         / GET_MODE_SIZE (Pmode)) + 2 - 1, 0);
+      /* builtin_setjmp takes a pointer to 5 words.  */
+      tmp = build_int_cst (NULL_TREE, 5 * BITS_PER_WORD / POINTER_SIZE - 1);
 #endif
       tmp = build_index_type (tmp);
       tmp = build_array_type (ptr_type_node, tmp);
@@ -475,175 +440,69 @@ init_eh ()
 }
 
 void
-init_eh_for_function ()
+init_eh_for_function (void)
 {
-  cfun->eh = (struct eh_status *) 
-    ggc_alloc_cleared (sizeof (struct eh_status));
+  cfun->eh = ggc_alloc_cleared (sizeof (struct eh_status));
 }
 \f
-/* Start an exception handling region.  All instructions emitted
-   after this point are considered to be part of the region until
-   expand_eh_region_end is invoked.  */
+/* Routines to generate the exception tree somewhat directly.  
+   These are used from tree-eh.c when processing exception related
+   nodes during tree optimization.  */
 
-void
-expand_eh_region_start ()
+static struct eh_region *
+gen_eh_region (enum eh_region_type type, struct eh_region *outer)
 {
-  struct eh_region *new_region;
-  struct eh_region *cur_region;
-  rtx note;
+  struct eh_region *new;
 
-  if (! doing_eh (0))
-    return;
+#ifdef ENABLE_CHECKING
+  gcc_assert (doing_eh (0));
+#endif
 
   /* Insert a new blank region as a leaf in the tree.  */
-  new_region = (struct eh_region *) ggc_alloc_cleared (sizeof (*new_region));
-  cur_region = cfun->eh->cur_region;
-  new_region->outer = cur_region;
-  if (cur_region)
+  new = ggc_alloc_cleared (sizeof (*new));
+  new->type = type;
+  new->outer = outer;
+  if (outer)
     {
-      new_region->next_peer = cur_region->inner;
-      cur_region->inner = new_region;
+      new->next_peer = outer->inner;
+      outer->inner = new;
     }
   else
     {
-      new_region->next_peer = cfun->eh->region_tree;
-      cfun->eh->region_tree = new_region;
+      new->next_peer = cfun->eh->region_tree;
+      cfun->eh->region_tree = new;
     }
-  cfun->eh->cur_region = new_region;
-
-  /* Create a note marking the start of this region.  */
-  new_region->region_number = ++cfun->eh->last_region_number;
-  note = emit_note (NULL, NOTE_INSN_EH_REGION_BEG);
-  NOTE_EH_HANDLER (note) = new_region->region_number;
-}
-
-/* Common code to end a region.  Returns the region just ended.  */
-
-static struct eh_region *
-expand_eh_region_end ()
-{
-  struct eh_region *cur_region = cfun->eh->cur_region;
-  rtx note;
-
-  /* Create a note marking the end of this region.  */
-  note = emit_note (NULL, NOTE_INSN_EH_REGION_END);
-  NOTE_EH_HANDLER (note) = cur_region->region_number;
 
-  /* Pop.  */
-  cfun->eh->cur_region = cur_region->outer;
+  new->region_number = ++cfun->eh->last_region_number;
 
-  return cur_region;
+  return new;
 }
 
-/* End an exception handling region for a cleanup.  HANDLER is an
-   expression to expand for the cleanup.  */
-
-void
-expand_eh_region_end_cleanup (handler)
-     tree handler;
+struct eh_region *
+gen_eh_region_cleanup (struct eh_region *outer, struct eh_region *prev_try)
 {
-  struct eh_region *region;
-  tree protect_cleanup_actions;
-  rtx around_label;
-  rtx data_save[2];
-
-  if (! doing_eh (0))
-    return;
-
-  region = expand_eh_region_end ();
-  region->type = ERT_CLEANUP;
-  region->label = gen_label_rtx ();
-  region->u.cleanup.exp = handler;
-  region->u.cleanup.prev_try = cfun->eh->try_region;
-
-  around_label = gen_label_rtx ();
-  emit_jump (around_label);
-
-  emit_label (region->label);
-
-  /* Give the language a chance to specify an action to be taken if an
-     exception is thrown that would propagate out of the HANDLER.  */
-  protect_cleanup_actions
-    = (lang_protect_cleanup_actions
-       ? (*lang_protect_cleanup_actions) ()
-       : NULL_TREE);
-
-  if (protect_cleanup_actions)
-    expand_eh_region_start ();
-
-  /* In case this cleanup involves an inline destructor with a try block in
-     it, we need to save the EH return data registers around it.  */
-  data_save[0] = gen_reg_rtx (ptr_mode);
-  emit_move_insn (data_save[0], get_exception_pointer (cfun));
-  data_save[1] = gen_reg_rtx (word_mode);
-  emit_move_insn (data_save[1], get_exception_filter (cfun));
-
-  expand_expr (handler, const0_rtx, VOIDmode, 0);
-
-  emit_move_insn (cfun->eh->exc_ptr, data_save[0]);
-  emit_move_insn (cfun->eh->filter, data_save[1]);
-
-  if (protect_cleanup_actions)
-    expand_eh_region_end_must_not_throw (protect_cleanup_actions);
-
-  /* We need any stack adjustment complete before the around_label.  */
-  do_pending_stack_adjust ();
-
-  /* We delay the generation of the _Unwind_Resume until we generate
-     landing pads.  We emit a marker here so as to get good control
-     flow data in the meantime.  */
-  region->resume
-    = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
-  emit_barrier ();
-
-  emit_label (around_label);
+  struct eh_region *cleanup = gen_eh_region (ERT_CLEANUP, outer);
+  cleanup->u.cleanup.prev_try = prev_try;
+  return cleanup;
 }
 
-/* End an exception handling region for a try block, and prepares
-   for subsequent calls to expand_start_catch.  */
-
-void
-expand_start_all_catch ()
+struct eh_region *
+gen_eh_region_try (struct eh_region *outer)
 {
-  struct eh_region *region;
-
-  if (! doing_eh (1))
-    return;
-
-  region = expand_eh_region_end ();
-  region->type = ERT_TRY;
-  region->u.try.prev_try = cfun->eh->try_region;
-  region->u.try.continue_label = gen_label_rtx ();
-
-  cfun->eh->try_region = region;
-
-  emit_jump (region->u.try.continue_label);
+  return gen_eh_region (ERT_TRY, outer);
 }
 
-/* Begin a catch clause.  TYPE is the type caught, a list of such types, or
-   null if this is a catch-all clause. Providing a type list enables to
-   associate the catch region with potentially several exception types, which
-   is useful e.g. for Ada.  */
-
-void
-expand_start_catch (type_or_list)
-     tree type_or_list;
+struct eh_region *
+gen_eh_region_catch (struct eh_region *t, tree type_or_list)
 {
-  struct eh_region *t, *c, *l;
-  tree type_list;
-
-  if (! doing_eh (0))
-    return;
+  struct eh_region *c, *l;
+  tree type_list, type_node;
 
+  /* Ensure to always end up with a type list to normalize further
+     processing, then register each type against the runtime types map.  */
   type_list = type_or_list;
-
   if (type_or_list)
     {
-      /* Ensure to always end up with a type list to normalize further
-         processing, then register each type against the runtime types
-         map.  */
-      tree type_node;
-
       if (TREE_CODE (type_or_list) != TREE_LIST)
        type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE);
 
@@ -652,14 +511,8 @@ expand_start_catch (type_or_list)
        add_type_for_runtime (TREE_VALUE (type_node));
     }
 
-  expand_eh_region_start ();
-
-  t = cfun->eh->try_region;
-  c = cfun->eh->cur_region;
-  c->type = ERT_CATCH;
+  c = gen_eh_region (ERT_CATCH, t->outer);
   c->u.catch.type_list = type_list;
-  c->label = gen_label_rtx ();
-
   l = t->u.try.last_catch;
   c->u.catch.prev_catch = l;
   if (l)
@@ -668,167 +521,86 @@ expand_start_catch (type_or_list)
     t->u.try.catch = c;
   t->u.try.last_catch = c;
 
-  emit_label (c->label);
+  return c;
 }
 
-/* End a catch clause.  Control will resume after the try/catch block.  */
-
-void
-expand_end_catch ()
+struct eh_region *
+gen_eh_region_allowed (struct eh_region *outer, tree allowed)
 {
-  struct eh_region *try_region;
-
-  if (! doing_eh (0))
-    return;
+  struct eh_region *region = gen_eh_region (ERT_ALLOWED_EXCEPTIONS, outer);
+  region->u.allowed.type_list = allowed;
 
-  expand_eh_region_end ();
-  try_region = cfun->eh->try_region;
+  for (; allowed ; allowed = TREE_CHAIN (allowed))
+    add_type_for_runtime (TREE_VALUE (allowed));
 
-  emit_jump (try_region->u.try.continue_label);
+  return region;
 }
 
-/* End a sequence of catch handlers for a try block.  */
-
-void
-expand_end_all_catch ()
+struct eh_region *
+gen_eh_region_must_not_throw (struct eh_region *outer)
 {
-  struct eh_region *try_region;
-
-  if (! doing_eh (0))
-    return;
-
-  try_region = cfun->eh->try_region;
-  cfun->eh->try_region = try_region->u.try.prev_try;
+  return gen_eh_region (ERT_MUST_NOT_THROW, outer);
+}
 
-  emit_label (try_region->u.try.continue_label);
+int
+get_eh_region_number (struct eh_region *region)
+{
+  return region->region_number;
 }
 
-/* End an exception region for an exception type filter.  ALLOWED is a
-   TREE_LIST of types to be matched by the runtime.  FAILURE is an
-   expression to invoke if a mismatch occurs.
+bool
+get_eh_region_may_contain_throw (struct eh_region *region)
+{
+  return region->may_contain_throw;
+}
 
-   ??? We could use these semantics for calls to rethrow, too; if we can
-   see the surrounding catch clause, we know that the exception we're
-   rethrowing satisfies the "filter" of the catch type.  */
+tree
+get_eh_region_tree_label (struct eh_region *region)
+{
+  return region->tree_label;
+}
 
 void
-expand_eh_region_end_allowed (allowed, failure)
-     tree allowed, failure;
+set_eh_region_tree_label (struct eh_region *region, tree lab)
 {
-  struct eh_region *region;
-  rtx around_label;
-
-  if (! doing_eh (0))
-    return;
-
-  region = expand_eh_region_end ();
-  region->type = ERT_ALLOWED_EXCEPTIONS;
-  region->u.allowed.type_list = allowed;
-  region->label = gen_label_rtx ();
-
-  for (; allowed ; allowed = TREE_CHAIN (allowed))
-    add_type_for_runtime (TREE_VALUE (allowed));
-
-  /* We must emit the call to FAILURE here, so that if this function
-     throws a different exception, that it will be processed by the
-     correct region.  */
-
-  around_label = gen_label_rtx ();
-  emit_jump (around_label);
-
-  emit_label (region->label);
-  expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL);
-  /* We must adjust the stack before we reach the AROUND_LABEL because
-     the call to FAILURE does not occur on all paths to the
-     AROUND_LABEL.  */
-  do_pending_stack_adjust ();
-
-  emit_label (around_label);
+  region->tree_label = lab;
 }
-
-/* End an exception region for a must-not-throw filter.  FAILURE is an
-   expression invoke if an uncaught exception propagates this far.
-
-   This is conceptually identical to expand_eh_region_end_allowed with
-   an empty allowed list (if you passed "std::terminate" instead of
-   "__cxa_call_unexpected"), but they are represented differently in
-   the C++ LSDA.  */
-
+\f
 void
-expand_eh_region_end_must_not_throw (failure)
-     tree failure;
+expand_resx_expr (tree exp)
 {
-  struct eh_region *region;
-  rtx around_label;
+  int region_nr = TREE_INT_CST_LOW (TREE_OPERAND (exp, 0));
+  struct eh_region *reg = cfun->eh->region_array[region_nr];
 
-  if (! doing_eh (0))
-    return;
-
-  region = expand_eh_region_end ();
-  region->type = ERT_MUST_NOT_THROW;
-  region->label = gen_label_rtx ();
-
-  /* We must emit the call to FAILURE here, so that if this function
-     throws a different exception, that it will be processed by the
-     correct region.  */
-
-  around_label = gen_label_rtx ();
-  emit_jump (around_label);
-
-  emit_label (region->label);
-  expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
-  emit_label (around_label);
+  reg->resume = emit_jump_insn (gen_rtx_RESX (VOIDmode, region_nr));
+  emit_barrier ();
 }
 
-/* End an exception region for a throw.  No handling goes on here,
-   but it's the easiest way for the front-end to indicate what type
-   is being thrown.  */
+/* Note that the current EH region (if any) may contain a throw, or a
+   call to a function which itself may contain a throw.  */
 
 void
-expand_eh_region_end_throw (type)
-     tree type;
+note_eh_region_may_contain_throw (struct eh_region *region)
 {
-  struct eh_region *region;
-
-  if (! doing_eh (0))
-    return;
-
-  region = expand_eh_region_end ();
-  region->type = ERT_THROW;
-  region->u.throw.type = type;
+  while (region && !region->may_contain_throw)
+    {
+      region->may_contain_throw = 1;
+      region = region->outer;
+    }
 }
 
-/* End a fixup region.  Within this region the cleanups for the immediately
-   enclosing region are _not_ run.  This is used for goto cleanup to avoid
-   destroying an object twice.
-
-   This would be an extraordinarily simple prospect, were it not for the
-   fact that we don't actually know what the immediately enclosing region
-   is.  This surprising fact is because expand_cleanups is currently
-   generating a sequence that it will insert somewhere else.  We collect
-   the proper notion of "enclosing" in convert_from_eh_region_ranges.  */
-
 void
-expand_eh_region_end_fixup (handler)
-     tree handler;
+note_current_region_may_contain_throw (void)
 {
-  struct eh_region *fixup;
-
-  if (! doing_eh (0))
-    return;
-
-  fixup = expand_eh_region_end ();
-  fixup->type = ERT_FIXUP;
-  fixup->u.fixup.cleanup_exp = handler;
+  note_eh_region_may_contain_throw (cfun->eh->cur_region);
 }
 
+
 /* Return an rtl expression for a pointer to the exception object
    within a handler.  */
 
 rtx
-get_exception_pointer (fun)
-     struct function *fun;
+get_exception_pointer (struct function *fun)
 {
   rtx exc_ptr = fun->eh->exc_ptr;
   if (fun == cfun && ! exc_ptr)
@@ -842,14 +614,13 @@ get_exception_pointer (fun)
 /* Return an rtl expression for the exception dispatch filter
    within a handler.  */
 
-static rtx
-get_exception_filter (fun)
-     struct function *fun;
+rtx
+get_exception_filter (struct function *fun)
 {
   rtx filter = fun->eh->filter;
   if (fun == cfun && ! filter)
     {
-      filter = gen_reg_rtx (word_mode);
+      filter = gen_reg_rtx (targetm.eh_return_filter_mode ());
       fun->eh->filter = filter;
     }
   return filter;
@@ -857,12 +628,10 @@ get_exception_filter (fun)
 \f
 /* This section is for the exception handling specific optimization pass.  */
 
-/* Random access the exception region tree.  It's just as simple to
-   collect the regions this way as in expand_eh_region_start, but
-   without having to realloc memory.  */
+/* Random access the exception region tree.  */
 
-static void
-collect_eh_region_array ()
+void
+collect_eh_region_array (void)
 {
   struct eh_region **array, *i;
 
@@ -897,109 +666,10 @@ collect_eh_region_array ()
     }
 }
 
-static void
-resolve_fixup_regions ()
-{
-  int i, j, n = cfun->eh->last_region_number;
-
-  for (i = 1; i <= n; ++i)
-    {
-      struct eh_region *fixup = cfun->eh->region_array[i];
-      struct eh_region *cleanup = 0;
-
-      if (! fixup || fixup->type != ERT_FIXUP)
-       continue;
-
-      for (j = 1; j <= n; ++j)
-       {
-         cleanup = cfun->eh->region_array[j];
-         if (cleanup && cleanup->type == ERT_CLEANUP
-             && cleanup->u.cleanup.exp == fixup->u.fixup.cleanup_exp)
-           break;
-       }
-      if (j > n)
-       abort ();
-
-      fixup->u.fixup.real_region = cleanup->outer;
-    }
-}
-
-/* Now that we've discovered what region actually encloses a fixup,
-   we can shuffle pointers and remove them from the tree.  */
-
-static void
-remove_fixup_regions ()
-{
-  int i;
-  rtx insn, note;
-  struct eh_region *fixup;
-
-  /* Walk the insn chain and adjust the REG_EH_REGION numbers
-     for instructions referencing fixup regions.  This is only
-     strictly necessary for fixup regions with no parent, but
-     doesn't hurt to do it for all regions.  */
-  for (insn = get_insns(); insn ; insn = NEXT_INSN (insn))
-    if (INSN_P (insn)
-       && (note = find_reg_note (insn, REG_EH_REGION, NULL))
-       && INTVAL (XEXP (note, 0)) > 0
-       && (fixup = cfun->eh->region_array[INTVAL (XEXP (note, 0))])
-       && fixup->type == ERT_FIXUP)
-      {
-       if (fixup->u.fixup.real_region)
-         XEXP (note, 0) = GEN_INT (fixup->u.fixup.real_region->region_number);
-       else
-         remove_note (insn, note);
-      }
-
-  /* Remove the fixup regions from the tree.  */
-  for (i = cfun->eh->last_region_number; i > 0; --i)
-    {
-      fixup = cfun->eh->region_array[i];
-      if (! fixup)
-       continue;
-
-      /* Allow GC to maybe free some memory.  */
-      if (fixup->type == ERT_CLEANUP)
-       fixup->u.cleanup.exp = NULL_TREE;
-
-      if (fixup->type != ERT_FIXUP)
-       continue;
-
-      if (fixup->inner)
-       {
-         struct eh_region *parent, *p, **pp;
-
-         parent = fixup->u.fixup.real_region;
-
-         /* Fix up the children's parent pointers; find the end of
-            the list.  */
-         for (p = fixup->inner; ; p = p->next_peer)
-           {
-             p->outer = parent;
-             if (! p->next_peer)
-               break;
-           }
-
-         /* In the tree of cleanups, only outer-inner ordering matters.
-            So link the children back in anywhere at the correct level.  */
-         if (parent)
-           pp = &parent->inner;
-         else
-           pp = &cfun->eh->region_tree;
-         p->next_peer = *pp;
-         *pp = fixup->inner;
-         fixup->inner = NULL;
-       }
-
-      remove_eh_handler (fixup);
-    }
-}
-
 /* Remove all regions whose labels are not reachable from insns.  */
 
 static void
-remove_unreachable_regions (insns)
-     rtx insns;
+remove_unreachable_regions (rtx insns)
 {
   int i, *uid_region_num;
   bool *reachable;
@@ -1017,22 +687,14 @@ remove_unreachable_regions (insns)
 
       if (r->resume)
        {
-         if (uid_region_num[INSN_UID (r->resume)])
-           abort ();
+         gcc_assert (!uid_region_num[INSN_UID (r->resume)]);
          uid_region_num[INSN_UID (r->resume)] = i;
        }
       if (r->label)
        {
-         if (uid_region_num[INSN_UID (r->label)])
-           abort ();
+         gcc_assert (!uid_region_num[INSN_UID (r->label)]);
          uid_region_num[INSN_UID (r->label)] = i;
        }
-      if (r->type == ERT_TRY && r->u.try.continue_label)
-       {
-         if (uid_region_num[INSN_UID (r->u.try.continue_label)])
-           abort ();
-         uid_region_num[INSN_UID (r->u.try.continue_label)] = i;
-       }
     }
 
   for (insn = insns; insn; insn = NEXT_INSN (insn))
@@ -1043,155 +705,80 @@ remove_unreachable_regions (insns)
       r = cfun->eh->region_array[i];
       if (r && r->region_number == i && !reachable[i])
        {
-         /* Don't remove ERT_THROW regions if their outer region
-            is reachable.  */
-         if (r->type == ERT_THROW
-             && r->outer
-             && reachable[r->outer->region_number])
-           continue;
-
-         remove_eh_handler (r);
-       }
-    }
-
-  free (reachable);
-  free (uid_region_num);
-}
-
-/* Turn NOTE_INSN_EH_REGION notes into REG_EH_REGION notes for each
-   can_throw instruction in the region.  */
-
-static void
-convert_from_eh_region_ranges_1 (pinsns, orig_sp, cur)
-     rtx *pinsns;
-     int *orig_sp;
-     int cur;
-{
-  int *sp = orig_sp;
-  rtx insn, next;
-
-  for (insn = *pinsns; insn ; insn = next)
-    {
-      next = NEXT_INSN (insn);
-      if (GET_CODE (insn) == NOTE)
-       {
-         int kind = NOTE_LINE_NUMBER (insn);
-         if (kind == NOTE_INSN_EH_REGION_BEG
-             || kind == NOTE_INSN_EH_REGION_END)
+         bool kill_it = true;
+         switch (r->type)
            {
-             if (kind == NOTE_INSN_EH_REGION_BEG)
-               {
-                 struct eh_region *r;
+           case ERT_THROW:
+             /* Don't remove ERT_THROW regions if their outer region
+                is reachable.  */
+             if (r->outer && reachable[r->outer->region_number])
+               kill_it = false;
+             break;
 
-                 *sp++ = cur;
-                 cur = NOTE_EH_HANDLER (insn);
+           case ERT_MUST_NOT_THROW:
+             /* MUST_NOT_THROW regions are implementable solely in the
+                runtime, but their existence continues to affect calls
+                within that region.  Never delete them here.  */
+             kill_it = false;
+             break;
 
-                 r = cfun->eh->region_array[cur];
-                 if (r->type == ERT_FIXUP)
-                   {
-                     r = r->u.fixup.real_region;
-                     cur = r ? r->region_number : 0;
-                   }
-                 else if (r->type == ERT_CATCH)
+           case ERT_TRY:
+             {
+               /* TRY regions are reachable if any of its CATCH regions
+                  are reachable.  */
+               struct eh_region *c;
+               for (c = r->u.try.catch; c ; c = c->u.catch.next_catch)
+                 if (reachable[c->region_number])
                    {
-                     r = r->outer;
-                     cur = r ? r->region_number : 0;
+                     kill_it = false;
+                     break;
                    }
-               }
-             else
-               cur = *--sp;
-
-             /* Removing the first insn of a CALL_PLACEHOLDER sequence
-                requires extra care to adjust sequence start.  */
-             if (insn == *pinsns)
-               *pinsns = next;
-             remove_insn (insn);
-             continue;
-           }
-       }
-      else if (INSN_P (insn))
-       {
-         rtx note;
-         switch (cur)
-           {
-           default:
-             /* An existing region note may be present to suppress
-                exception handling.  Anything with a note value of -1
-                cannot throw an exception of any kind.  A note value
-                of 0 means that "normal" exceptions are suppressed,
-                but not necessarily "forced unwind" exceptions.  */
-             note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-             if (note)
-               {
-                 if (flag_forced_unwind_exceptions
-                     && INTVAL (XEXP (note, 0)) >= 0)
-                   XEXP (note, 0) = GEN_INT (cur);
-                 break;
-               }
-
-             /* Calls can always potentially throw exceptions; if we wanted
-                exceptions for non-call insns, then any may_trap_p
-                instruction can throw.  */
-             if (GET_CODE (insn) != CALL_INSN
-                 && (!flag_non_call_exceptions
-                     || GET_CODE (PATTERN (insn)) == CLOBBER
-                     || GET_CODE (PATTERN (insn)) == USE
-                     || !may_trap_p (PATTERN (insn))))
                break;
+             }
 
-             REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION,
-                                                 GEN_INT (cur),
-                                                 REG_NOTES (insn));
-
-           case 0:
+           default:
              break;
            }
-
-         if (GET_CODE (insn) == CALL_INSN
-             && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
-           {
-             convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 0),
-                                              sp, cur);
-             convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 1),
-                                              sp, cur);
-             convert_from_eh_region_ranges_1 (&XEXP (PATTERN (insn), 2),
-                                              sp, cur);
-           }
+             
+         if (kill_it)
+           remove_eh_handler (r);
        }
     }
 
-  if (sp != orig_sp)
-    abort ();
+  free (reachable);
+  free (uid_region_num);
 }
 
+/* Set up EH labels for RTL.  */
+
 void
-convert_from_eh_region_ranges ()
+convert_from_eh_region_ranges (void)
 {
-  int *stack;
-  rtx insns;
-
-  collect_eh_region_array ();
-  resolve_fixup_regions ();
+  rtx insns = get_insns ();
+  int i, n = cfun->eh->last_region_number;
 
-  stack = xmalloc (sizeof (int) * (cfun->eh->last_region_number + 1));
-  insns = get_insns ();
-  convert_from_eh_region_ranges_1 (&insns, stack, 0);
-  free (stack);
+  /* Most of the work is already done at the tree level.  All we need to
+     do is collect the rtl labels that correspond to the tree labels that
+     collect the rtl labels that correspond to the tree labels
+     we allocated earlier.  */
+  for (i = 1; i <= n; ++i)
+    {
+      struct eh_region *region = cfun->eh->region_array[i];
+      if (region && region->tree_label)
+       region->label = DECL_RTL_IF_SET (region->tree_label);
+    }
 
-  remove_fixup_regions ();
   remove_unreachable_regions (insns);
 }
 
 static void
-add_ehl_entry (label, region)
-     rtx label;
-     struct eh_region *region;
+add_ehl_entry (rtx label, struct eh_region *region)
 {
   struct ehl_map_entry **slot, *entry;
 
   LABEL_PRESERVE_P (label) = 1;
 
-  entry = (struct ehl_map_entry *) ggc_alloc (sizeof (*entry));
+  entry = ggc_alloc (sizeof (*entry));
   entry->label = label;
   entry->region = region;
 
@@ -1202,14 +789,13 @@ add_ehl_entry (label, region)
      label.  After landing pad creation, the exception handlers may
      share landing pads.  This is ok, since maybe_remove_eh_handler
      only requires the 1-1 mapping before landing pad creation.  */
-  if (*slot && !cfun->eh->built_landing_pads)
-    abort ();
+  gcc_assert (!*slot || cfun->eh->built_landing_pads);
 
   *slot = entry;
 }
 
 void
-find_exception_handler_labels ()
+find_exception_handler_labels (void)
 {
   int i;
 
@@ -1250,7 +836,7 @@ find_exception_handler_labels ()
 }
 
 bool
-current_function_has_exception_handlers ()
+current_function_has_exception_handlers (void)
 {
   int i;
 
@@ -1268,70 +854,33 @@ current_function_has_exception_handlers ()
 }
 \f
 static struct eh_region *
-duplicate_eh_region_1 (o, map)
-     struct eh_region *o;
-     struct inline_remap *map;
+duplicate_eh_region_1 (struct eh_region *o)
 {
-  struct eh_region *n
-    = (struct eh_region *) ggc_alloc_cleared (sizeof (struct eh_region));
+  struct eh_region *n = ggc_alloc_cleared (sizeof (struct eh_region));
 
+  *n = *o;
+  
   n->region_number = o->region_number + cfun->eh->last_region_number;
-  n->type = o->type;
-
-  switch (n->type)
-    {
-    case ERT_CLEANUP:
-    case ERT_MUST_NOT_THROW:
-      break;
-
-    case ERT_TRY:
-      if (o->u.try.continue_label)
-       n->u.try.continue_label
-         = get_label_from_map (map,
-                               CODE_LABEL_NUMBER (o->u.try.continue_label));
-      break;
-
-    case ERT_CATCH:
-      n->u.catch.type_list = o->u.catch.type_list;
-      break;
-
-    case ERT_ALLOWED_EXCEPTIONS:
-      n->u.allowed.type_list = o->u.allowed.type_list;
-      break;
-
-    case ERT_THROW:
-      n->u.throw.type = o->u.throw.type;
-
-    default:
-      abort ();
-    }
-
-  if (o->label)
-    n->label = get_label_from_map (map, CODE_LABEL_NUMBER (o->label));
-  if (o->resume)
-    {
-      n->resume = map->insn_map[INSN_UID (o->resume)];
-      if (n->resume == NULL)
-       abort ();
-    }
-
+  gcc_assert (!o->aka);
+  
   return n;
 }
 
 static void
-duplicate_eh_region_2 (o, n_array)
-     struct eh_region *o;
-     struct eh_region **n_array;
+duplicate_eh_region_2 (struct eh_region *o, struct eh_region **n_array,
+                      struct eh_region *prev_try)
 {
   struct eh_region *n = n_array[o->region_number];
-
+  
   switch (n->type)
     {
     case ERT_TRY:
-      n->u.try.catch = n_array[o->u.try.catch->region_number];
-      n->u.try.last_catch = n_array[o->u.try.last_catch->region_number];
+      if (o->u.try.catch)
+        n->u.try.catch = n_array[o->u.try.catch->region_number];
+      if (o->u.try.last_catch)
+        n->u.try.last_catch = n_array[o->u.try.last_catch->region_number];
       break;
-
+      
     case ERT_CATCH:
       if (o->u.catch.next_catch)
        n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number];
@@ -1339,10 +888,17 @@ duplicate_eh_region_2 (o, n_array)
        n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number];
       break;
 
+    case ERT_CLEANUP:
+      if (o->u.cleanup.prev_try)
+       n->u.cleanup.prev_try = n_array[o->u.cleanup.prev_try->region_number];
+      else
+        n->u.cleanup.prev_try = prev_try;
+      break;
+      
     default:
       break;
     }
-
+  
   if (o->outer)
     n->outer = n_array[o->outer->region_number];
   if (o->inner)
@@ -1351,40 +907,59 @@ duplicate_eh_region_2 (o, n_array)
     n->next_peer = n_array[o->next_peer->region_number];
 }
 
+/* Duplicate the EH regions of IFUN into current function, root the tree in
+   OUTER_REGION and remap labels using MAP callback.  */
 int
-duplicate_eh_regions (ifun, map)
-     struct function *ifun;
-     struct inline_remap *map;
+duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
+                     void *data, int outer_region)
 {
   int ifun_last_region_number = ifun->eh->last_region_number;
-  struct eh_region **n_array, *root, *cur;
+  struct eh_region **n_array, *root, *cur, *prev_try;
   int i;
-
-  if (ifun_last_region_number == 0)
+  
+  if (ifun_last_region_number == 0 || !ifun->eh->region_tree)
     return 0;
-
+  
   n_array = xcalloc (ifun_last_region_number + 1, sizeof (*n_array));
+  
+  /* Search for the containing ERT_TRY region to fix up
+     the prev_try short-cuts for ERT_CLEANUP regions.  */
+  prev_try = NULL;
+  if (outer_region > 0)
+    for (prev_try = cfun->eh->region_array[outer_region];
+         prev_try && prev_try->type != ERT_TRY;
+        prev_try = prev_try->outer)
+      ;
 
   for (i = 1; i <= ifun_last_region_number; ++i)
     {
       cur = ifun->eh->region_array[i];
       if (!cur || cur->region_number != i)
        continue;
-      n_array[i] = duplicate_eh_region_1 (cur, map);
+      n_array[i] = duplicate_eh_region_1 (cur);
+      if (cur->tree_label)
+       {
+         tree newlabel = map (cur->tree_label, data);
+         n_array[i]->tree_label = newlabel;
+       }
+      else
+       n_array[i]->tree_label = NULL;
     }
   for (i = 1; i <= ifun_last_region_number; ++i)
     {
       cur = ifun->eh->region_array[i];
       if (!cur || cur->region_number != i)
        continue;
-      duplicate_eh_region_2 (cur, n_array);
+      duplicate_eh_region_2 (cur, n_array, prev_try);
     }
-
+  
   root = n_array[ifun->eh->region_tree->region_number];
-  cur = cfun->eh->cur_region;
-  if (cur)
+  gcc_assert (root->outer == NULL);
+  if (outer_region > 0)
     {
+      struct eh_region *cur = cfun->eh->region_array[outer_region];
       struct eh_region *p = cur->inner;
+
       if (p)
        {
          while (p->next_peer)
@@ -1392,8 +967,7 @@ duplicate_eh_regions (ifun, map)
          p->next_peer = root;
        }
       else
-       cur->inner = root;
-
+        cur->inner = root;
       for (i = 1; i <= ifun_last_region_number; ++i)
        if (n_array[i] && n_array[i]->outer == NULL)
          n_array[i]->outer = cur;
@@ -1408,21 +982,21 @@ duplicate_eh_regions (ifun, map)
          p->next_peer = root;
        }
       else
-       cfun->eh->region_tree = root;
+        cfun->eh->region_tree = root;
     }
-
+  
   free (n_array);
-
+  
   i = cfun->eh->last_region_number;
   cfun->eh->last_region_number = i + ifun_last_region_number;
+  
+  collect_eh_region_array ();
+  
   return i;
 }
-
 \f
 static int
-t2r_eq (pentry, pdata)
-     const PTR pentry;
-     const PTR pdata;
+t2r_eq (const void *pentry, const void *pdata)
 {
   tree entry = (tree) pentry;
   tree data = (tree) pdata;
@@ -1431,21 +1005,19 @@ t2r_eq (pentry, pdata)
 }
 
 static hashval_t
-t2r_hash (pentry)
-     const PTR pentry;
+t2r_hash (const void *pentry)
 {
   tree entry = (tree) pentry;
-  return TYPE_HASH (TREE_PURPOSE (entry));
+  return TREE_HASH (TREE_PURPOSE (entry));
 }
 
 static void
-add_type_for_runtime (type)
-     tree type;
+add_type_for_runtime (tree type)
 {
   tree *slot;
 
   slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
-                                           TYPE_HASH (type), INSERT);
+                                           TREE_HASH (type), INSERT);
   if (*slot == NULL)
     {
       tree runtime = (*lang_eh_runtime_type) (type);
@@ -1454,13 +1026,12 @@ add_type_for_runtime (type)
 }
 
 static tree
-lookup_type_for_runtime (type)
-     tree type;
+lookup_type_for_runtime (tree type)
 {
   tree *slot;
 
   slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
-                                           TYPE_HASH (type), NO_INSERT);
+                                           TREE_HASH (type), NO_INSERT);
 
   /* We should have always inserted the data earlier.  */
   return TREE_VALUE (*slot);
@@ -1479,9 +1050,7 @@ struct ttypes_filter GTY(())
    (a tree) for a @TTypes type node we are thinking about adding.  */
 
 static int
-ttypes_filter_eq (pentry, pdata)
-     const PTR pentry;
-     const PTR pdata;
+ttypes_filter_eq (const void *pentry, const void *pdata)
 {
   const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
   tree data = (tree) pdata;
@@ -1490,11 +1059,10 @@ ttypes_filter_eq (pentry, pdata)
 }
 
 static hashval_t
-ttypes_filter_hash (pentry)
-     const PTR pentry;
+ttypes_filter_hash (const void *pentry)
 {
   const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
-  return TYPE_HASH (entry->t);
+  return TREE_HASH (entry->t);
 }
 
 /* Compare ENTRY with DATA (both struct ttypes_filter) for a @TTypes
@@ -1503,9 +1071,7 @@ ttypes_filter_hash (pentry)
    should put these in some canonical order.  */
 
 static int
-ehspec_filter_eq (pentry, pdata)
-     const PTR pentry;
-     const PTR pdata;
+ehspec_filter_eq (const void *pentry, const void *pdata)
 {
   const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
   const struct ttypes_filter *data = (const struct ttypes_filter *) pdata;
@@ -1516,41 +1082,38 @@ ehspec_filter_eq (pentry, pdata)
 /* Hash function for exception specification lists.  */
 
 static hashval_t
-ehspec_filter_hash (pentry)
-     const PTR pentry;
+ehspec_filter_hash (const void *pentry)
 {
   const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
   hashval_t h = 0;
   tree list;
 
   for (list = entry->t; list ; list = TREE_CHAIN (list))
-    h = (h << 5) + (h >> 27) + TYPE_HASH (TREE_VALUE (list));
+    h = (h << 5) + (h >> 27) + TREE_HASH (TREE_VALUE (list));
   return h;
 }
 
-/* Add TYPE to cfun->eh->ttype_data, using TYPES_HASH to speed
-   up the search.  Return the filter value to be used.  */
+/* Add TYPE (which may be NULL) to cfun->eh->ttype_data, using TYPES_HASH
+   to speed up the search.  Return the filter value to be used.  */
 
 static int
-add_ttypes_entry (ttypes_hash, type)
-     htab_t ttypes_hash;
-     tree type;
+add_ttypes_entry (htab_t ttypes_hash, tree type)
 {
   struct ttypes_filter **slot, *n;
 
   slot = (struct ttypes_filter **)
-    htab_find_slot_with_hash (ttypes_hash, type, TYPE_HASH (type), INSERT);
+    htab_find_slot_with_hash (ttypes_hash, type, TREE_HASH (type), INSERT);
 
   if ((n = *slot) == NULL)
     {
       /* Filter value is a 1 based table index.  */
 
-      n = (struct ttypes_filter *) xmalloc (sizeof (*n));
+      n = xmalloc (sizeof (*n));
       n->t = type;
-      n->filter = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) + 1;
+      n->filter = VEC_length (tree, cfun->eh->ttype_data) + 1;
       *slot = n;
 
-      VARRAY_PUSH_TREE (cfun->eh->ttype_data, type);
+      VEC_safe_push (tree, gc, cfun->eh->ttype_data, type);
     }
 
   return n->filter;
@@ -1560,10 +1123,7 @@ add_ttypes_entry (ttypes_hash, type)
    to speed up the search.  Return the filter value to be used.  */
 
 static int
-add_ehspec_entry (ehspec_hash, ttypes_hash, list)
-     htab_t ehspec_hash;
-     htab_t ttypes_hash;
-     tree list;
+add_ehspec_entry (htab_t ehspec_hash, htab_t ttypes_hash, tree list)
 {
   struct ttypes_filter **slot, *n;
   struct ttypes_filter dummy;
@@ -1576,7 +1136,7 @@ add_ehspec_entry (ehspec_hash, ttypes_hash, list)
     {
       /* Filter value is a -1 based byte index into a uleb128 buffer.  */
 
-      n = (struct ttypes_filter *) xmalloc (sizeof (*n));
+      n = xmalloc (sizeof (*n));
       n->t = list;
       n->filter = -(VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) + 1);
       *slot = n;
@@ -1598,12 +1158,12 @@ add_ehspec_entry (ehspec_hash, ttypes_hash, list)
    the same filter value, which saves table space.  */
 
 static void
-assign_filter_values ()
+assign_filter_values (void)
 {
   int i;
   htab_t ttypes, ehspec;
 
-  VARRAY_TREE_INIT (cfun->eh->ttype_data, 16, "ttype_data");
+  cfun->eh->ttype_data = VEC_alloc (tree, gc, 16);
   VARRAY_UCHAR_INIT (cfun->eh->ehspec_data, 64, "ehspec_data");
 
   ttypes = htab_create (31, ttypes_filter_hash, ttypes_filter_eq, free);
@@ -1633,7 +1193,7 @@ assign_filter_values ()
              for (;tp_node; tp_node = TREE_CHAIN (tp_node))
                {
                  int flt = add_ttypes_entry (ttypes, TREE_VALUE (tp_node));
-                 tree flt_node = build_int_2 (flt, 0);
+                 tree flt_node = build_int_cst (NULL_TREE, flt);
 
                  r->u.catch.filter_list
                    = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
@@ -1644,7 +1204,7 @@ assign_filter_values ()
              /* Get a filter value for the NULL list also since it will need
                 an action record anyway.  */
              int flt = add_ttypes_entry (ttypes, NULL);
-             tree flt_node = build_int_2 (flt, 0);
+             tree flt_node = build_int_cst (NULL_TREE, flt);
 
              r->u.catch.filter_list
                = tree_cons (NULL_TREE, flt_node, r->u.catch.filter_list);
@@ -1666,8 +1226,39 @@ assign_filter_values ()
   htab_delete (ehspec);
 }
 
+/* Emit SEQ into basic block just before INSN (that is assumed to be
+   first instruction of some existing BB and return the newly
+   produced block.  */
+static basic_block
+emit_to_new_bb_before (rtx seq, rtx insn)
+{
+  rtx last;
+  basic_block bb;
+  edge e;
+  edge_iterator ei;
+
+  /* If there happens to be a fallthru edge (possibly created by cleanup_cfg
+     call), we don't want it to go into newly created landing pad or other EH 
+     construct.  */
+  for (ei = ei_start (BLOCK_FOR_INSN (insn)->preds); (e = ei_safe_edge (ei)); )
+    if (e->flags & EDGE_FALLTHRU)
+      force_nonfallthru (e);
+    else
+      ei_next (&ei);
+  last = emit_insn_before (seq, insn);
+  if (BARRIER_P (last))
+    last = PREV_INSN (last);
+  bb = create_basic_block (seq, last, BLOCK_FOR_INSN (insn)->prev_bb);
+  update_bb_for_insn (bb);
+  bb->flags |= BB_SUPERBLOCK;
+  return bb;
+}
+
+/* Generate the code to actually handle exceptions, which will follow the
+   landing pads.  */
+
 static void
-build_post_landing_pads ()
+build_post_landing_pads (void)
 {
   int i;
 
@@ -1703,14 +1294,7 @@ build_post_landing_pads ()
            for (c = region->u.try.catch; c ; c = c->u.catch.next_catch)
              {
                if (c->u.catch.type_list == NULL)
-                 {
-                   if (flag_forced_unwind_exceptions)
-                     emit_cmp_and_jump_insns
-                       (cfun->eh->filter, const0_rtx, GT, NULL_RTX,
-                        word_mode, 0, c->label);
-                   else
-                     emit_jump (c->label);
-                 }
+                 emit_jump (c->label);
                else
                  {
                    /* Need for one cmp/jump per type caught. Each type
@@ -1724,7 +1308,8 @@ build_post_landing_pads ()
                        emit_cmp_and_jump_insns
                          (cfun->eh->filter,
                           GEN_INT (tree_low_cst (TREE_VALUE (flt_node), 0)),
-                          EQ, NULL_RTX, word_mode, 0, c->label);
+                          EQ, NULL_RTX, 
+                          targetm.eh_return_filter_mode (), 0, c->label);
 
                        tp_node = TREE_CHAIN (tp_node);
                        flt_node = TREE_CHAIN (flt_node);
@@ -1743,7 +1328,8 @@ build_post_landing_pads ()
          seq = get_insns ();
          end_sequence ();
 
-         emit_insn_before (seq, region->u.try.catch->label);
+         emit_to_new_bb_before (seq, region->u.try.catch->label);
+
          break;
 
        case ERT_ALLOWED_EXCEPTIONS:
@@ -1755,7 +1341,8 @@ build_post_landing_pads ()
 
          emit_cmp_and_jump_insns (cfun->eh->filter,
                                   GEN_INT (region->u.allowed.filter),
-                                  EQ, NULL_RTX, word_mode, 0, region->label);
+                                  EQ, NULL_RTX, 
+                                  targetm.eh_return_filter_mode (), 0, region->label);
 
          /* We delay the generation of the _Unwind_Resume until we generate
             landing pads.  We emit a marker here so as to get good control
@@ -1767,37 +1354,12 @@ build_post_landing_pads ()
          seq = get_insns ();
          end_sequence ();
 
-         emit_insn_before (seq, region->label);
+         emit_to_new_bb_before (seq, region->label);
          break;
 
        case ERT_CLEANUP:
-         region->post_landing_pad = region->label;
-         break;
-
        case ERT_MUST_NOT_THROW:
-         /* See maybe_remove_eh_handler about removing region->label.  */
-         if (flag_forced_unwind_exceptions && region->label)
-           {
-             region->post_landing_pad = gen_label_rtx ();
-
-             start_sequence ();
-
-             emit_label (region->post_landing_pad);
-             emit_cmp_and_jump_insns (cfun->eh->filter, const0_rtx, GT,
-                                      NULL_RTX, word_mode, 0, region->label);
-
-             region->resume
-               = emit_jump_insn (gen_rtx_RESX (VOIDmode,
-                                               region->region_number));
-             emit_barrier ();
-
-             seq = get_insns ();
-             end_sequence ();
-
-             emit_insn_before (seq, region->label);
-           }
-         else
-           region->post_landing_pad = region->label;
+         region->post_landing_pad = region->label;
          break;
 
        case ERT_CATCH:
@@ -1806,7 +1368,7 @@ build_post_landing_pads ()
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
 }
@@ -1815,7 +1377,7 @@ build_post_landing_pads ()
    _Unwind_Resume otherwise.  */
 
 static void
-connect_post_landing_pads ()
+connect_post_landing_pads (void)
 {
   int i;
 
@@ -1824,6 +1386,7 @@ connect_post_landing_pads ()
       struct eh_region *region = cfun->eh->region_array[i];
       struct eh_region *outer;
       rtx seq;
+      rtx barrier;
 
       /* Mind we don't process a region more than once.  */
       if (!region || region->region_number != i)
@@ -1842,21 +1405,55 @@ connect_post_landing_pads ()
       start_sequence ();
 
       if (outer)
-       emit_jump (outer->post_landing_pad);
+       {
+         edge e;
+         basic_block src, dest;
+
+         emit_jump (outer->post_landing_pad);
+         src = BLOCK_FOR_INSN (region->resume);
+         dest = BLOCK_FOR_INSN (outer->post_landing_pad);
+         while (EDGE_COUNT (src->succs) > 0)
+           remove_edge (EDGE_SUCC (src, 0));
+         e = make_edge (src, dest, 0);
+         e->probability = REG_BR_PROB_BASE;
+         e->count = src->count;
+       }
       else
-       emit_library_call (unwind_resume_libfunc, LCT_THROW,
-                          VOIDmode, 1, cfun->eh->exc_ptr, ptr_mode);
+       {
+         emit_library_call (unwind_resume_libfunc, LCT_THROW,
+                            VOIDmode, 1, cfun->eh->exc_ptr, ptr_mode);
+
+         /* What we just emitted was a throwing libcall, so it got a
+            barrier automatically added after it.  If the last insn in
+            the libcall sequence isn't the barrier, it's because the
+            target emits multiple insns for a call, and there are insns
+            after the actual call insn (which are redundant and would be
+            optimized away).  The barrier is inserted exactly after the
+            call insn, so let's go get that and delete the insns after
+            it, because below we need the barrier to be the last insn in
+            the sequence.  */
+         delete_insns_since (NEXT_INSN (last_call_insn ()));
+       }
 
       seq = get_insns ();
       end_sequence ();
-      emit_insn_before (seq, region->resume);
+      barrier = emit_insn_before (seq, region->resume);
+      /* Avoid duplicate barrier.  */
+      gcc_assert (BARRIER_P (barrier));
+      delete_insn (barrier);
       delete_insn (region->resume);
+
+      /* ??? From tree-ssa we can wind up with catch regions whose
+        label is not instantiated, but whose resx is present.  Now
+        that we've dealt with the resx, kill the region.  */
+      if (region->label == NULL && region->type == ERT_CLEANUP)
+       remove_eh_handler (region);
     }
 }
 
 \f
 static void
-dw2_build_landing_pads ()
+dw2_build_landing_pads (void)
 {
   int i;
   unsigned int j;
@@ -1865,7 +1462,9 @@ dw2_build_landing_pads ()
     {
       struct eh_region *region = cfun->eh->region_array[i];
       rtx seq;
+      basic_block bb;
       bool clobbers_hard_regs = false;
+      edge e;
 
       /* Mind we don't process a region more than once.  */
       if (!region || region->region_number != i)
@@ -1920,12 +1519,16 @@ dw2_build_landing_pads ()
       emit_move_insn (cfun->eh->exc_ptr,
                      gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0)));
       emit_move_insn (cfun->eh->filter,
-                     gen_rtx_REG (word_mode, EH_RETURN_DATA_REGNO (1)));
+                     gen_rtx_REG (targetm.eh_return_filter_mode (), 
+                                  EH_RETURN_DATA_REGNO (1)));
 
       seq = get_insns ();
       end_sequence ();
 
-      emit_insn_before (seq, region->post_landing_pad);
+      bb = emit_to_new_bb_before (seq, region->post_landing_pad);
+      e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+      e->count = bb->count;
+      e->probability = REG_BR_PROB_BASE;
     }
 }
 
@@ -1939,8 +1542,7 @@ struct sjlj_lp_info
 };
 
 static bool
-sjlj_find_directly_reachable_regions (lp_info)
-     struct sjlj_lp_info *lp_info;
+sjlj_find_directly_reachable_regions (struct sjlj_lp_info *lp_info)
 {
   rtx insn;
   bool found_one = false;
@@ -1973,25 +1575,10 @@ sjlj_find_directly_reachable_regions (lp_info)
       rc = RNL_NOT_CAUGHT;
       for (; region; region = region->outer)
        {
-         rc = reachable_next_level (region, type_thrown, 0);
+         rc = reachable_next_level (region, type_thrown, NULL);
          if (rc != RNL_NOT_CAUGHT)
            break;
        }
-
-      /* Forced unwind exceptions aren't blocked.  */
-      if (flag_forced_unwind_exceptions && rc == RNL_BLOCKED)
-       {
-          struct eh_region *r;
-         for (r = region->outer; r ; r = r->outer)
-           if (r->type == ERT_CLEANUP)
-             {
-               rc = RNL_MAYBE_CAUGHT;
-               if (! region->label)
-                 region = r;
-               break;
-             }
-       }
-
       if (rc == RNL_MAYBE_CAUGHT || rc == RNL_CAUGHT)
        {
          lp_info[region->region_number].directly_reachable = 1;
@@ -2003,9 +1590,7 @@ sjlj_find_directly_reachable_regions (lp_info)
 }
 
 static void
-sjlj_assign_call_site_values (dispatch_label, lp_info)
-     rtx dispatch_label;
-     struct sjlj_lp_info *lp_info;
+sjlj_assign_call_site_values (rtx dispatch_label, struct sjlj_lp_info *lp_info)
 {
   htab_t ar_hash;
   int i, index;
@@ -2067,8 +1652,7 @@ sjlj_assign_call_site_values (dispatch_label, lp_info)
 }
 
 static void
-sjlj_mark_call_sites (lp_info)
-     struct sjlj_lp_info *lp_info;
+sjlj_mark_call_sites (struct sjlj_lp_info *lp_info)
 {
   int last_call_site = -2;
   rtx insn, mem;
@@ -2080,7 +1664,7 @@ sjlj_mark_call_sites (lp_info)
       rtx note, before, p;
 
       /* Reset value tracking at extended basic block boundaries.  */
-      if (GET_CODE (insn) == CODE_LABEL)
+      if (LABEL_P (insn))
        last_call_site = -2;
 
       if (! INSN_P (insn))
@@ -2092,7 +1676,7 @@ sjlj_mark_call_sites (lp_info)
          /* Calls (and trapping insns) without notes are outside any
             exception handling region in this function.  Mark them as
             no action.  */
-         if (GET_CODE (insn) == CALL_INSN
+         if (CALL_P (insn)
              || (flag_non_call_exceptions
                  && may_trap_p (PATTERN (insn))))
            this_call_site = -1;
@@ -2114,7 +1698,7 @@ sjlj_mark_call_sites (lp_info)
 
       /* Don't separate a call from it's argument loads.  */
       before = insn;
-      if (GET_CODE (insn) == CALL_INSN)
+      if (CALL_P (insn))
        before = find_first_parameter_load (insn, NULL_RTX);
 
       start_sequence ();
@@ -2132,8 +1716,7 @@ sjlj_mark_call_sites (lp_info)
 /* Construct the SjLj_Function_Context.  */
 
 static void
-sjlj_emit_function_enter (dispatch_label)
-     rtx dispatch_label;
+sjlj_emit_function_enter (rtx dispatch_label)
 {
   rtx fn_begin, fc, mem, seq;
 
@@ -2152,8 +1735,12 @@ sjlj_emit_function_enter (dispatch_label)
   if (cfun->uses_eh_lsda)
     {
       char buf[20];
+      rtx sym;
+
       ASM_GENERATE_INTERNAL_LABEL (buf, "LLSDA", current_function_funcdef_no);
-      emit_move_insn (mem, gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)));
+      sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
+      SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_LOCAL;
+      emit_move_insn (mem, sym);
     }
   else
     emit_move_insn (mem, const0_rtx);
@@ -2166,7 +1753,7 @@ sjlj_emit_function_enter (dispatch_label)
                                 plus_constant (XEXP (fc, 0),
                                                sjlj_fc_jbuf_ofs), Pmode);
 
-    note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE);
+    note = emit_note (NOTE_INSN_EXPECTED_VALUE);
     NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, x, const0_rtx);
 
     emit_cmp_and_jump_insns (x, const0_rtx, NE, 0,
@@ -2188,26 +1775,39 @@ sjlj_emit_function_enter (dispatch_label)
      can_throw_internal instructions.  */
 
   for (fn_begin = get_insns (); ; fn_begin = NEXT_INSN (fn_begin))
-    if (GET_CODE (fn_begin) == NOTE
-       && NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
+    if (NOTE_P (fn_begin)
+       && (NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG
+           || NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_BASIC_BLOCK))
       break;
-  emit_insn_after (seq, fn_begin);
+  if (NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
+    insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR));
+  else
+    {
+      rtx last = BB_END (single_succ (ENTRY_BLOCK_PTR));
+      for (; ; fn_begin = NEXT_INSN (fn_begin))
+       if ((NOTE_P (fn_begin)
+            && NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
+           || fn_begin == last)
+         break;
+      emit_insn_after (seq, fn_begin);
+    }
 }
 
 /* Call back from expand_function_end to know where we should put
    the call to unwind_sjlj_unregister_libfunc if needed.  */
 
 void
-sjlj_emit_function_exit_after (after)
-     rtx after;
+sjlj_emit_function_exit_after (rtx after)
 {
   cfun->eh->sjlj_exit_after = after;
 }
 
 static void
-sjlj_emit_function_exit ()
+sjlj_emit_function_exit (void)
 {
   rtx seq;
+  edge e;
+  edge_iterator ei;
 
   start_sequence ();
 
@@ -2221,16 +1821,41 @@ sjlj_emit_function_exit ()
      post-dominates all can_throw_internal instructions.  This is
      the last possible moment.  */
 
-  emit_insn_after (seq, cfun->eh->sjlj_exit_after);
+  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
+    if (e->flags & EDGE_FALLTHRU)
+      break;
+  if (e)
+    {
+      rtx insn;
+
+      /* Figure out whether the place we are supposed to insert libcall
+         is inside the last basic block or after it.  In the other case
+         we need to emit to edge.  */
+      gcc_assert (e->src->next_bb == EXIT_BLOCK_PTR);
+      for (insn = BB_HEAD (e->src); ; insn = NEXT_INSN (insn))
+       {
+         if (insn == cfun->eh->sjlj_exit_after)
+           {
+             if (LABEL_P (insn))
+               insn = NEXT_INSN (insn);
+             emit_insn_after (seq, insn);
+             return;
+           }
+         if (insn == BB_END (e->src))
+           break;
+       }
+      insert_insn_on_edge (seq, e);
+    }
 }
 
 static void
-sjlj_emit_dispatch_table (dispatch_label, lp_info)
-     rtx dispatch_label;
-     struct sjlj_lp_info *lp_info;
+sjlj_emit_dispatch_table (rtx dispatch_label, struct sjlj_lp_info *lp_info)
 {
   int i, first_reachable;
   rtx mem, dispatch, seq, fc;
+  rtx before;
+  basic_block bb;
+  edge e;
 
   fc = cfun->eh->sjlj_fc;
 
@@ -2249,12 +1874,12 @@ sjlj_emit_dispatch_table (dispatch_label, lp_info)
   dispatch = copy_to_reg (mem);
 
   mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs);
-  if (word_mode != Pmode)
+  if (word_mode != ptr_mode)
     {
 #ifdef POINTERS_EXTEND_UNSIGNED
-      mem = convert_memory_address (Pmode, mem);
+      mem = convert_memory_address (ptr_mode, mem);
 #else
-      mem = convert_to_mode (Pmode, mem, 0);
+      mem = convert_to_mode (ptr_mode, mem, 0);
 #endif
     }
   emit_move_insn (cfun->eh->exc_ptr, mem);
@@ -2285,17 +1910,21 @@ sjlj_emit_dispatch_table (dispatch_label, lp_info)
   seq = get_insns ();
   end_sequence ();
 
-  emit_insn_before (seq, (cfun->eh->region_array[first_reachable]
-                         ->post_landing_pad));
+  before = cfun->eh->region_array[first_reachable]->post_landing_pad;
+
+  bb = emit_to_new_bb_before (seq, before);
+  e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+  e->count = bb->count;
+  e->probability = REG_BR_PROB_BASE;
 }
 
 static void
-sjlj_build_landing_pads ()
+sjlj_build_landing_pads (void)
 {
   struct sjlj_lp_info *lp_info;
 
-  lp_info = (struct sjlj_lp_info *) xcalloc (cfun->eh->last_region_number + 1,
-                                            sizeof (struct sjlj_lp_info));
+  lp_info = xcalloc (cfun->eh->last_region_number + 1,
+                    sizeof (struct sjlj_lp_info));
 
   if (sjlj_find_directly_reachable_regions (lp_info))
     {
@@ -2318,8 +1947,10 @@ sjlj_build_landing_pads ()
 }
 
 void
-finish_eh_generation ()
+finish_eh_generation (void)
 {
+  basic_block bb;
+
   /* Nothing to do if no regions created.  */
   if (cfun->eh->region_tree == NULL)
     return;
@@ -2333,8 +1964,6 @@ finish_eh_generation ()
      connect many of the handlers, and then type information will not
      be effective.  Still, this is a win over previous implementations.  */
 
-  cleanup_cfg (CLEANUP_PRE_LOOP | CLEANUP_NO_INSN_DEL);
-
   /* These registers are used by the landing pads.  Make sure they
      have been generated.  */
   get_exception_pointer (cfun);
@@ -2354,14 +1983,31 @@ finish_eh_generation ()
 
   /* We've totally changed the CFG.  Start over.  */
   find_exception_handler_labels ();
-  rebuild_jump_labels (get_insns ());
-  find_basic_blocks (get_insns (), max_reg_num (), 0);
-  cleanup_cfg (CLEANUP_PRE_LOOP | CLEANUP_NO_INSN_DEL);
+  break_superblocks ();
+  if (USING_SJLJ_EXCEPTIONS)
+    commit_edge_insertions ();
+  FOR_EACH_BB (bb)
+    {
+      edge e;
+      edge_iterator ei;
+      bool eh = false;
+      for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
+       {
+         if (e->flags & EDGE_EH)
+           {
+             remove_edge (e);
+             eh = true;
+           }
+         else
+           ei_next (&ei);
+       }
+      if (eh)
+       rtl_make_eh_edge (NULL, bb, BB_END (bb));
+    }
 }
 \f
 static hashval_t
-ehl_hash (pentry)
-     const PTR pentry;
+ehl_hash (const void *pentry)
 {
   struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry;
 
@@ -2371,9 +2017,7 @@ ehl_hash (pentry)
 }
 
 static int
-ehl_eq (pentry, pdata)
-     const PTR pentry;
-     const PTR pdata;
+ehl_eq (const void *pentry, const void *pdata)
 {
   struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry;
   struct ehl_map_entry *data = (struct ehl_map_entry *) pdata;
@@ -2386,8 +2030,7 @@ ehl_eq (pentry, pdata)
 /* Remove LABEL from exception_handler_label_map.  */
 
 static void
-remove_exception_handler_label (label)
-     rtx label;
+remove_exception_handler_label (rtx label)
 {
   struct ehl_map_entry **slot, tmp;
 
@@ -2399,8 +2042,7 @@ remove_exception_handler_label (label)
   tmp.label = label;
   slot = (struct ehl_map_entry **)
     htab_find_slot (cfun->eh->exception_handler_label_map, &tmp, NO_INSERT);
-  if (! slot)
-    abort ();
+  gcc_assert (slot);
 
   htab_clear_slot (cfun->eh->exception_handler_label_map, (void **) slot);
 }
@@ -2408,8 +2050,7 @@ remove_exception_handler_label (label)
 /* Splice REGION from the region tree etc.  */
 
 static void
-remove_eh_handler (region)
-     struct eh_region *region;
+remove_eh_handler (struct eh_region *region)
 {
   struct eh_region **pp, **pp_start, *p, *outer, *inner;
   rtx lab;
@@ -2424,9 +2065,13 @@ remove_eh_handler (region)
   cfun->eh->region_array[region->region_number] = outer;
   if (region->aka)
     {
-      int i;
-      EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i,
-       { cfun->eh->region_array[i] = outer; });
+      unsigned i;
+      bitmap_iterator bi;
+
+      EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i, bi)
+       {
+         cfun->eh->region_array[i] = outer;
+       }
     }
 
   if (outer)
@@ -2434,7 +2079,7 @@ remove_eh_handler (region)
       if (!outer->aka)
         outer->aka = BITMAP_GGC_ALLOC ();
       if (region->aka)
-       bitmap_a_or_b (outer->aka, outer->aka, region->aka);
+       bitmap_ior_into (outer->aka, region->aka);
       bitmap_set_bit (outer->aka, region->region_number);
     }
 
@@ -2472,8 +2117,7 @@ remove_eh_handler (region)
           try->type == ERT_CATCH;
           try = try->next_peer)
        continue;
-      if (try->type != ERT_TRY)
-       abort ();
+      gcc_assert (try->type == ERT_TRY);
 
       next = region->u.catch.next_catch;
       prev = region->u.catch.prev_catch;
@@ -2498,8 +2142,7 @@ remove_eh_handler (region)
    delete the region.  */
 
 void
-maybe_remove_eh_handler (label)
-     rtx label;
+maybe_remove_eh_handler (rtx label)
 {
   struct ehl_map_entry **slot, tmp;
   struct eh_region *region;
@@ -2537,41 +2180,53 @@ maybe_remove_eh_handler (label)
    loop hackery; should not be used by new code.  */
 
 void
-for_each_eh_label (callback)
-     void (*callback) PARAMS ((rtx));
+for_each_eh_label (void (*callback) (rtx))
 {
   htab_traverse (cfun->eh->exception_handler_label_map, for_each_eh_label_1,
-                (void *)callback);
+                (void *) &callback);
 }
 
 static int
-for_each_eh_label_1 (pentry, data)
-     PTR *pentry;
-     PTR data;
+for_each_eh_label_1 (void **pentry, void *data)
 {
   struct ehl_map_entry *entry = *(struct ehl_map_entry **)pentry;
-  void (*callback) PARAMS ((rtx)) = (void (*) PARAMS ((rtx))) data;
+  void (*callback) (rtx) = *(void (**) (rtx)) data;
 
   (*callback) (entry->label);
   return 1;
 }
+
+/* Invoke CALLBACK for every exception region in the current function.  */
+
+void
+for_each_eh_region (void (*callback) (struct eh_region *))
+{
+  int i, n = cfun->eh->last_region_number;
+  for (i = 1; i <= n; ++i)
+    {
+      struct eh_region *region = cfun->eh->region_array[i];
+      if (region)
+       (*callback) (region);
+    }
+}
 \f
 /* This section describes CFG exception edges for flow.  */
 
 /* For communicating between calls to reachable_next_level.  */
-struct reachable_info GTY(())
+struct reachable_info
 {
   tree types_caught;
   tree types_allowed;
-  rtx handlers;
+  void (*callback) (struct eh_region *, void *);
+  void *callback_data;
+  bool saw_any_handlers;
 };
 
 /* A subroutine of reachable_next_level.  Return true if TYPE, or a
    base class of TYPE, is in HANDLED.  */
 
 static int
-check_handled (handled, type)
-     tree handled, type;
+check_handled (tree handled, tree type)
 {
   tree t;
 
@@ -2601,21 +2256,18 @@ check_handled (handled, type)
    LP_REGION contains the landing pad; REGION is the handler.  */
 
 static void
-add_reachable_handler (info, lp_region, region)
-     struct reachable_info *info;
-     struct eh_region *lp_region;
-     struct eh_region *region;
+add_reachable_handler (struct reachable_info *info,
+                      struct eh_region *lp_region, struct eh_region *region)
 {
   if (! info)
     return;
 
+  info->saw_any_handlers = true;
+
   if (cfun->eh->built_landing_pads)
-    {
-      if (! info->handlers)
-       info->handlers = alloc_INSN_LIST (lp_region->landing_pad, NULL_RTX);
-    }
+    info->callback (lp_region, info->callback_data);
   else
-    info->handlers = alloc_INSN_LIST (region->label, info->handlers);
+    info->callback (region, info->callback_data);
 }
 
 /* Process one level of exception regions for reachability.
@@ -2624,10 +2276,8 @@ add_reachable_handler (info, lp_region, region)
    and caught/allowed type information between invocations.  */
 
 static enum reachable_code
-reachable_next_level (region, type_thrown, info)
-     struct eh_region *region;
-     tree type_thrown;
-     struct reachable_info *info;
+reachable_next_level (struct eh_region *region, tree type_thrown,
+                     struct reachable_info *info)
 {
   switch (region->type)
     {
@@ -2765,8 +2415,13 @@ reachable_next_level (region, type_thrown, info)
       /* Here we end our search, since no exceptions may propagate.
         If we've touched down at some landing pad previous, then the
         explicit function call we generated may be used.  Otherwise
-        the call is made by the runtime.  */
-      if (info && info->handlers)
+        the call is made by the runtime. 
+
+         Before inlining, do not perform this optimization.  We may
+        inline a subroutine that contains handlers, and that will
+        change the value of saw_any_handlers.  */
+
+      if ((info && info->saw_any_handlers) || !cfun->after_inlining)
        {
          add_reachable_handler (info, region, region);
          return RNL_CAUGHT;
@@ -2778,73 +2433,49 @@ reachable_next_level (region, type_thrown, info)
     case ERT_FIXUP:
     case ERT_UNKNOWN:
       /* Shouldn't see these here.  */
+      gcc_unreachable ();
       break;
+    default:
+      gcc_unreachable ();
     }
-
-  abort ();
 }
 
-/* Retrieve a list of labels of exception handlers which can be
-   reached by a given insn.  */
+/* Invoke CALLBACK on each region reachable from REGION_NUMBER.  */
 
-rtx
-reachable_handlers (insn)
-     rtx insn;
+void
+foreach_reachable_handler (int region_number, bool is_resx,
+                          void (*callback) (struct eh_region *, void *),
+                          void *callback_data)
 {
   struct reachable_info info;
   struct eh_region *region;
   tree type_thrown;
-  int region_number;
-
-  if (GET_CODE (insn) == JUMP_INSN
-      && GET_CODE (PATTERN (insn)) == RESX)
-    region_number = XINT (PATTERN (insn), 0);
-  else
-    {
-      rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-      if (!note || INTVAL (XEXP (note, 0)) <= 0)
-       return NULL;
-      region_number = INTVAL (XEXP (note, 0));
-    }
 
   memset (&info, 0, sizeof (info));
+  info.callback = callback;
+  info.callback_data = callback_data;
 
   region = cfun->eh->region_array[region_number];
 
   type_thrown = NULL_TREE;
-  if (GET_CODE (insn) == JUMP_INSN
-      && GET_CODE (PATTERN (insn)) == RESX)
+  if (is_resx)
     {
       /* A RESX leaves a region instead of entering it.  Thus the
         region itself may have been deleted out from under us.  */
       if (region == NULL)
-       return NULL;
+       return;
       region = region->outer;
     }
   else if (region->type == ERT_THROW)
     {
       type_thrown = region->u.throw.type;
       region = region->outer;
-    }
-
-  while (region)
-    {
-      if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT)
-       {
-         /* Forced unwind exceptions are neither BLOCKED nor CAUGHT.
-            Make sure the cleanup regions are reachable.  */
-         if (flag_forced_unwind_exceptions)
-           {
-             while ((region = region->outer) != NULL)
-               if (region->type == ERT_CLEANUP)
-                 {
-                   add_reachable_handler (&info, region, region);
-                   break;
-                 }
-           }
-         break;
-       }
+    }
 
+  while (region)
+    {
+      if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT)
+       break;
       /* If we have processed one cleanup, there is no point in
         processing any more of them.  Each cleanup will have an edge
         to the next outer cleanup region, so the flow graph will be
@@ -2854,48 +2485,66 @@ reachable_handlers (insn)
       else
        region = region->outer;
     }
-    
-  return info.handlers;
 }
 
-/* Determine if the given INSN can throw an exception that is caught
-   within the function.  */
+/* Retrieve a list of labels of exception handlers which can be
+   reached by a given insn.  */
 
-bool
-can_throw_internal (insn)
-     rtx insn;
+static void
+arh_to_landing_pad (struct eh_region *region, void *data)
 {
-  struct eh_region *region;
-  tree type_thrown;
-  rtx note;
+  rtx *p_handlers = data;
+  if (! *p_handlers)
+    *p_handlers = alloc_INSN_LIST (region->landing_pad, NULL_RTX);
+}
 
-  if (! INSN_P (insn))
-    return false;
+static void
+arh_to_label (struct eh_region *region, void *data)
+{
+  rtx *p_handlers = data;
+  *p_handlers = alloc_INSN_LIST (region->label, *p_handlers);
+}
 
-  if (GET_CODE (insn) == INSN
-      && GET_CODE (PATTERN (insn)) == SEQUENCE)
-    insn = XVECEXP (PATTERN (insn), 0, 0);
+rtx
+reachable_handlers (rtx insn)
+{
+  bool is_resx = false;
+  rtx handlers = NULL;
+  int region_number;
 
-  if (GET_CODE (insn) == CALL_INSN
-      && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
+  if (JUMP_P (insn)
+      && GET_CODE (PATTERN (insn)) == RESX)
     {
-      int i;
-      for (i = 0; i < 3; ++i)
-       {
-         rtx sub = XEXP (PATTERN (insn), i);
-         for (; sub ; sub = NEXT_INSN (sub))
-           if (can_throw_internal (sub))
-             return true;
-       }
-      return false;
+      region_number = XINT (PATTERN (insn), 0);
+      is_resx = true;
+    }
+  else
+    {
+      rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+      if (!note || INTVAL (XEXP (note, 0)) <= 0)
+       return NULL;
+      region_number = INTVAL (XEXP (note, 0));
     }
 
-  /* Every insn that might throw has an EH_REGION note.  */
-  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-  if (!note || INTVAL (XEXP (note, 0)) <= 0)
-    return false;
+  foreach_reachable_handler (region_number, is_resx,
+                            (cfun->eh->built_landing_pads
+                             ? arh_to_landing_pad
+                             : arh_to_label),
+                            &handlers);
+
+  return handlers;
+}
+
+/* Determine if the given INSN can throw an exception that is caught
+   within the function.  */
+
+bool
+can_throw_internal_1 (int region_number)
+{
+  struct eh_region *region;
+  tree type_thrown;
 
-  region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
+  region = cfun->eh->region_array[region_number];
 
   type_thrown = NULL_TREE;
   if (region->type == ERT_THROW)
@@ -2919,58 +2568,41 @@ can_throw_internal (insn)
   return false;
 }
 
-/* Determine if the given INSN can throw an exception that is
-   visible outside the function.  */
-
 bool
-can_throw_external (insn)
-     rtx insn;
+can_throw_internal (rtx insn)
 {
-  struct eh_region *region;
-  tree type_thrown;
   rtx note;
 
   if (! INSN_P (insn))
     return false;
 
-  if (GET_CODE (insn) == INSN
+  if (JUMP_P (insn)
+      && GET_CODE (PATTERN (insn)) == RESX
+      && XINT (PATTERN (insn), 0) > 0)
+    return can_throw_internal_1 (XINT (PATTERN (insn), 0));
+
+  if (NONJUMP_INSN_P (insn)
       && GET_CODE (PATTERN (insn)) == SEQUENCE)
     insn = XVECEXP (PATTERN (insn), 0, 0);
 
-  if (GET_CODE (insn) == CALL_INSN
-      && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
-    {
-      int i;
-      for (i = 0; i < 3; ++i)
-       {
-         rtx sub = XEXP (PATTERN (insn), i);
-         for (; sub ; sub = NEXT_INSN (sub))
-           if (can_throw_external (sub))
-             return true;
-       }
-      return false;
-    }
-
+  /* Every insn that might throw has an EH_REGION note.  */
   note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-  if (!note)
-    {
-      /* Calls (and trapping insns) without notes are outside any
-        exception handling region in this function.  We have to
-        assume it might throw.  Given that the front end and middle
-        ends mark known NOTHROW functions, this isn't so wildly
-        inaccurate.  */
-      return (GET_CODE (insn) == CALL_INSN
-             || (flag_non_call_exceptions
-                 && may_trap_p (PATTERN (insn))));
-    }
-  if (INTVAL (XEXP (note, 0)) <= 0)
+  if (!note || INTVAL (XEXP (note, 0)) <= 0)
     return false;
 
-  /* Forced unwind excptions are not catchable.  */
-  if (flag_forced_unwind_exceptions && GET_CODE (insn) == CALL_INSN)
-    return true;
+  return can_throw_internal_1 (INTVAL (XEXP (note, 0)));
+}
+
+/* Determine if the given INSN can throw an exception that is
+   visible outside the function.  */
+
+bool
+can_throw_external_1 (int region_number)
+{
+  struct eh_region *region;
+  tree type_thrown;
 
-  region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
+  region = cfun->eh->region_array[region_number];
 
   type_thrown = NULL_TREE;
   if (region->type == ERT_THROW)
@@ -2988,14 +2620,44 @@ can_throw_external (insn)
   return true;
 }
 
-/* Set current_function_nothrow and cfun->all_throwers_are_sibcalls.  */
+bool
+can_throw_external (rtx insn)
+{
+  rtx note;
+
+  if (! INSN_P (insn))
+    return false;
+
+  if (NONJUMP_INSN_P (insn)
+      && GET_CODE (PATTERN (insn)) == SEQUENCE)
+    insn = XVECEXP (PATTERN (insn), 0, 0);
+
+  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+  if (!note)
+    {
+      /* Calls (and trapping insns) without notes are outside any
+        exception handling region in this function.  We have to
+        assume it might throw.  Given that the front end and middle
+        ends mark known NOTHROW functions, this isn't so wildly
+        inaccurate.  */
+      return (CALL_P (insn)
+             || (flag_non_call_exceptions
+                 && may_trap_p (PATTERN (insn))));
+    }
+  if (INTVAL (XEXP (note, 0)) <= 0)
+    return false;
+
+  return can_throw_external_1 (INTVAL (XEXP (note, 0)));
+}
+
+/* Set TREE_NOTHROW and cfun->all_throwers_are_sibcalls.  */
 
 void
-set_nothrow_function_flags ()
+set_nothrow_function_flags (void)
 {
   rtx insn;
-  
-  current_function_nothrow = 1;
+
+  TREE_NOTHROW (current_function_decl) = 1;
 
   /* Assume cfun->all_throwers_are_sibcalls until we encounter
      something that can throw an exception.  We specifically exempt
@@ -3007,13 +2669,13 @@ set_nothrow_function_flags ()
 
   if (! flag_exceptions)
     return;
-  
+
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     if (can_throw_external (insn))
       {
-       current_function_nothrow = 0;
+        TREE_NOTHROW (current_function_decl) = 0;
 
-       if (GET_CODE (insn) != CALL_INSN || !SIBLING_CALL_P (insn))
+       if (!CALL_P (insn) || !SIBLING_CALL_P (insn))
          {
            cfun->all_throwers_are_sibcalls = 0;
            return;
@@ -3024,9 +2686,9 @@ set_nothrow_function_flags ()
        insn = XEXP (insn, 1))
     if (can_throw_external (insn))
       {
-       current_function_nothrow = 0;
+        TREE_NOTHROW (current_function_decl) = 0;
 
-       if (GET_CODE (insn) != CALL_INSN || !SIBLING_CALL_P (insn))
+       if (!CALL_P (insn) || !SIBLING_CALL_P (insn))
          {
            cfun->all_throwers_are_sibcalls = 0;
            return;
@@ -3041,7 +2703,7 @@ set_nothrow_function_flags ()
    On the SPARC, this means flushing the register windows.  */
 
 void
-expand_builtin_unwind_init ()
+expand_builtin_unwind_init (void)
 {
   /* Set this so all the registers get saved in our frame; we need to be
      able to copy the saved values for any registers from frames we unwind.  */
@@ -3053,15 +2715,14 @@ expand_builtin_unwind_init ()
 }
 
 rtx
-expand_builtin_eh_return_data_regno (arglist)
-     tree arglist;
+expand_builtin_eh_return_data_regno (tree arglist)
 {
   tree which = TREE_VALUE (arglist);
   unsigned HOST_WIDE_INT iwhich;
 
   if (TREE_CODE (which) != INTEGER_CST)
     {
-      error ("argument of `__builtin_eh_return_regno' must be constant");
+      error ("argument of %<__builtin_eh_return_regno%> must be constant");
       return constm1_rtx;
     }
 
@@ -3083,8 +2744,7 @@ expand_builtin_eh_return_data_regno (arglist)
    return the actual address encoded in that value.  */
 
 rtx
-expand_builtin_extract_return_addr (addr_tree)
-     tree addr_tree;
+expand_builtin_extract_return_addr (tree addr_tree)
 {
   rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
 
@@ -3116,15 +2776,11 @@ expand_builtin_extract_return_addr (addr_tree)
    stack slot so the epilogue will return to that address.  */
 
 rtx
-expand_builtin_frob_return_addr (addr_tree)
-     tree addr_tree;
+expand_builtin_frob_return_addr (tree addr_tree)
 {
   rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0);
 
-#ifdef POINTERS_EXTEND_UNSIGNED
-  if (GET_MODE (addr) != Pmode)
-    addr = convert_memory_address (Pmode, addr);
-#endif
+  addr = convert_memory_address (Pmode, addr);
 
 #ifdef RETURN_ADDR_OFFSET
   addr = force_reg (Pmode, addr);
@@ -3138,82 +2794,91 @@ expand_builtin_frob_return_addr (addr_tree)
    exception handler.  */
 
 void
-expand_builtin_eh_return (stackadj_tree, handler_tree)
-    tree stackadj_tree, handler_tree;
-{
-  rtx stackadj, handler;
-
-  stackadj = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0);
-  handler = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0);
-
-#ifdef POINTERS_EXTEND_UNSIGNED
-  if (GET_MODE (stackadj) != Pmode)
-    stackadj = convert_memory_address (Pmode, stackadj);
-
-  if (GET_MODE (handler) != Pmode)
-    handler = convert_memory_address (Pmode, handler);
+expand_builtin_eh_return (tree stackadj_tree ATTRIBUTE_UNUSED,
+                         tree handler_tree)
+{
+  rtx tmp;
+
+#ifdef EH_RETURN_STACKADJ_RTX
+  tmp = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0);
+  tmp = convert_memory_address (Pmode, tmp);
+  if (!cfun->eh->ehr_stackadj)
+    cfun->eh->ehr_stackadj = copy_to_reg (tmp);
+  else if (tmp != cfun->eh->ehr_stackadj)
+    emit_move_insn (cfun->eh->ehr_stackadj, tmp);
 #endif
 
-  if (! cfun->eh->ehr_label)
-    {
-      cfun->eh->ehr_stackadj = copy_to_reg (stackadj);
-      cfun->eh->ehr_handler = copy_to_reg (handler);
-      cfun->eh->ehr_label = gen_label_rtx ();
-    }
-  else
-    {
-      if (stackadj != cfun->eh->ehr_stackadj)
-       emit_move_insn (cfun->eh->ehr_stackadj, stackadj);
-      if (handler != cfun->eh->ehr_handler)
-       emit_move_insn (cfun->eh->ehr_handler, handler);
-    }
+  tmp = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0);
+  tmp = convert_memory_address (Pmode, tmp);
+  if (!cfun->eh->ehr_handler)
+    cfun->eh->ehr_handler = copy_to_reg (tmp);
+  else if (tmp != cfun->eh->ehr_handler)
+    emit_move_insn (cfun->eh->ehr_handler, tmp);
 
+  if (!cfun->eh->ehr_label)
+    cfun->eh->ehr_label = gen_label_rtx ();
   emit_jump (cfun->eh->ehr_label);
 }
 
 void
-expand_eh_return ()
+expand_eh_return (void)
 {
-  rtx sa, ra, around_label;
+  rtx around_label;
 
   if (! cfun->eh->ehr_label)
     return;
 
-  sa = EH_RETURN_STACKADJ_RTX;
-  if (! sa)
-    {
-      error ("__builtin_eh_return not supported on this target");
-      return;
-    }
-
   current_function_calls_eh_return = 1;
 
+#ifdef EH_RETURN_STACKADJ_RTX
+  emit_move_insn (EH_RETURN_STACKADJ_RTX, const0_rtx);
+#endif
+
   around_label = gen_label_rtx ();
-  emit_move_insn (sa, const0_rtx);
   emit_jump (around_label);
 
   emit_label (cfun->eh->ehr_label);
   clobber_return_register ();
 
+#ifdef EH_RETURN_STACKADJ_RTX
+  emit_move_insn (EH_RETURN_STACKADJ_RTX, cfun->eh->ehr_stackadj);
+#endif
+
 #ifdef HAVE_eh_return
   if (HAVE_eh_return)
-    emit_insn (gen_eh_return (cfun->eh->ehr_stackadj, cfun->eh->ehr_handler));
+    emit_insn (gen_eh_return (cfun->eh->ehr_handler));
   else
 #endif
     {
-      ra = EH_RETURN_HANDLER_RTX;
-      if (! ra)
-       {
-         error ("__builtin_eh_return not supported on this target");
-         ra = gen_reg_rtx (Pmode);
-       }
-
-      emit_move_insn (sa, cfun->eh->ehr_stackadj);
-      emit_move_insn (ra, cfun->eh->ehr_handler);
+#ifdef EH_RETURN_HANDLER_RTX
+      emit_move_insn (EH_RETURN_HANDLER_RTX, cfun->eh->ehr_handler);
+#else
+      error ("__builtin_eh_return not supported on this target");
+#endif
     }
 
   emit_label (around_label);
 }
+
+/* Convert a ptr_mode address ADDR_TREE to a Pmode address controlled by
+   POINTERS_EXTEND_UNSIGNED and return it.  */
+
+rtx
+expand_builtin_extend_pointer (tree addr_tree)
+{
+  rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0);
+  int extend;
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+  extend = POINTERS_EXTEND_UNSIGNED;
+#else
+  /* The previous EH code did an unsigned extend by default, so we do this also
+     for consistency.  */
+  extend = 1;
+#endif
+
+  return convert_modes (word_mode, ptr_mode, addr, extend);
+}
 \f
 /* In the following functions, we represent entries in the action table
    as 1-based indices.  Special cases are:
@@ -3234,9 +2899,7 @@ struct action_record
 };
 
 static int
-action_record_eq (pentry, pdata)
-     const PTR pentry;
-     const PTR pdata;
+action_record_eq (const void *pentry, const void *pdata)
 {
   const struct action_record *entry = (const struct action_record *) pentry;
   const struct action_record *data = (const struct action_record *) pdata;
@@ -3244,17 +2907,14 @@ action_record_eq (pentry, pdata)
 }
 
 static hashval_t
-action_record_hash (pentry)
-     const PTR pentry;
+action_record_hash (const void *pentry)
 {
   const struct action_record *entry = (const struct action_record *) pentry;
   return entry->next * 1009 + entry->filter;
 }
 
 static int
-add_action_record (ar_hash, filter, next)
-     htab_t ar_hash;
-     int filter, next;
+add_action_record (htab_t ar_hash, int filter, int next)
 {
   struct action_record **slot, *new, tmp;
 
@@ -3264,7 +2924,7 @@ add_action_record (ar_hash, filter, next)
 
   if ((new = *slot) == NULL)
     {
-      new = (struct action_record *) xmalloc (sizeof (*new));
+      new = xmalloc (sizeof (*new));
       new->offset = VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data) + 1;
       new->filter = filter;
       new->next = next;
@@ -3285,9 +2945,7 @@ add_action_record (ar_hash, filter, next)
 }
 
 static int
-collect_one_action_chain (ar_hash, region)
-     htab_t ar_hash;
-     struct eh_region *region;
+collect_one_action_chain (htab_t ar_hash, struct eh_region *region)
 {
   struct eh_region *c;
   int next;
@@ -3324,26 +2982,12 @@ collect_one_action_chain (ar_hash, region)
        {
          if (c->u.catch.type_list == NULL)
            {
-             int filter;
-
-             /* Forced exceptions run cleanups, always.  Record them if
-                they exist.  */
-             next = 0;
-             if (flag_forced_unwind_exceptions)
-               {
-                 struct eh_region *r;
-                 for (r = c->outer; r ; r = r->outer)
-                   if (r->type == ERT_CLEANUP)
-                     {
-                       next = add_action_record (ar_hash, 0, 0);
-                       break;
-                     }
-               }
-
              /* Retrieve the filter from the head of the filter list
                 where we have stored it (see assign_filter_values).  */
-             filter = TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list));
-             next = add_action_record (ar_hash, filter, next);
+             int filter
+               = TREE_INT_CST_LOW (TREE_VALUE (c->u.catch.filter_list));
+
+             next = add_action_record (ar_hash, filter, 0);
            }
          else
            {
@@ -3380,21 +3024,24 @@ collect_one_action_chain (ar_hash, region)
       /* An exception specification adds its filter to the
         beginning of the chain.  */
       next = collect_one_action_chain (ar_hash, region->outer);
-      return add_action_record (ar_hash, region->u.allowed.filter,
-                               next < 0 ? 0 : next);
+
+      /* If there is no next action, terminate the chain.  */
+      if (next == -1)
+       next = 0;
+      /* If all outer actions are cleanups or must_not_throw,
+        we'll have no action record for it, since we had wanted
+        to encode these states in the call-site record directly.
+        Add a cleanup action to the chain to catch these.  */
+      else if (next <= 0)
+       next = add_action_record (ar_hash, 0, 0);
+      
+      return add_action_record (ar_hash, region->u.allowed.filter, next);
 
     case ERT_MUST_NOT_THROW:
       /* A must-not-throw region with no inner handlers or cleanups
         requires no call-site entry.  Note that this differs from
         the no handler or cleanup case in that we do require an lsda
         to be generated.  Return a magic -2 value to record this.  */
-      if (flag_forced_unwind_exceptions)
-       {
-         struct eh_region *r;
-         for (r = region->outer; r ; r = r->outer)
-           if (r->type == ERT_CLEANUP)
-             return 0;
-       }
       return -2;
 
     case ERT_CATCH:
@@ -3404,14 +3051,12 @@ collect_one_action_chain (ar_hash, region)
       return collect_one_action_chain (ar_hash, region->outer);
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
 static int
-add_call_site (landing_pad, action)
-     rtx landing_pad;
-     int action;
+add_call_site (rtx landing_pad, int action)
 {
   struct call_site_record *data = cfun->eh->call_site_data;
   int used = cfun->eh->call_site_data_used;
@@ -3420,8 +3065,7 @@ add_call_site (landing_pad, action)
   if (used >= size)
     {
       size = (size ? size * 2 : 64);
-      data = (struct call_site_record *)
-       ggc_realloc (data, sizeof (*data) * size);
+      data = ggc_realloc (data, sizeof (*data) * size);
       cfun->eh->call_site_data = data;
       cfun->eh->call_site_data_size = size;
     }
@@ -3439,7 +3083,7 @@ add_call_site (landing_pad, action)
    instead to call site entries.  */
 
 void
-convert_to_eh_region_ranges ()
+convert_to_eh_region_ranges (void)
 {
   rtx insn, iter, note;
   htab_t ar_hash;
@@ -3464,14 +3108,14 @@ convert_to_eh_region_ranges ()
        rtx this_landing_pad;
 
        insn = iter;
-       if (GET_CODE (insn) == INSN
+       if (NONJUMP_INSN_P (insn)
            && GET_CODE (PATTERN (insn)) == SEQUENCE)
          insn = XVECEXP (PATTERN (insn), 0, 0);
 
        note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
        if (!note)
          {
-           if (! (GET_CODE (insn) == CALL_INSN
+           if (! (CALL_P (insn)
                   || (flag_non_call_exceptions
                       && may_trap_p (PATTERN (insn)))))
              continue;
@@ -3563,9 +3207,7 @@ convert_to_eh_region_ranges ()
 
 \f
 static void
-push_uleb128 (data_area, value)
-     varray_type *data_area;
-     unsigned int value;
+push_uleb128 (varray_type *data_area, unsigned int value)
 {
   do
     {
@@ -3579,9 +3221,7 @@ push_uleb128 (data_area, value)
 }
 
 static void
-push_sleb128 (data_area, value)
-     varray_type *data_area;
-     int value;
+push_sleb128 (varray_type *data_area, int value)
 {
   unsigned char byte;
   int more;
@@ -3602,7 +3242,7 @@ push_sleb128 (data_area, value)
 \f
 #ifndef HAVE_AS_LEB128
 static int
-dw2_size_of_call_site_table ()
+dw2_size_of_call_site_table (void)
 {
   int n = cfun->eh->call_site_data_used;
   int size = n * (4 + 4 + 4);
@@ -3618,7 +3258,7 @@ dw2_size_of_call_site_table ()
 }
 
 static int
-sjlj_size_of_call_site_table ()
+sjlj_size_of_call_site_table (void)
 {
   int n = cfun->eh->call_site_data_used;
   int size = 0;
@@ -3636,10 +3276,8 @@ sjlj_size_of_call_site_table ()
 #endif
 
 static void
-dw2_output_call_site_table ()
+dw2_output_call_site_table (void)
 {
-  const char *const function_start_lab
-    = IDENTIFIER_POINTER (current_function_func_begin_label);
   int n = cfun->eh->call_site_data_used;
   int i;
 
@@ -3662,21 +3300,25 @@ dw2_output_call_site_table ()
       /* ??? Perhaps use attr_length to choose data1 or data2 instead of
         data4 if the function is small enough.  */
 #ifdef HAVE_AS_LEB128
-      dw2_asm_output_delta_uleb128 (reg_start_lab, function_start_lab,
+      dw2_asm_output_delta_uleb128 (reg_start_lab,
+                                   current_function_func_begin_label,
                                    "region %d start", i);
       dw2_asm_output_delta_uleb128 (reg_end_lab, reg_start_lab,
                                    "length");
       if (cs->landing_pad)
-       dw2_asm_output_delta_uleb128 (landing_pad_lab, function_start_lab,
+       dw2_asm_output_delta_uleb128 (landing_pad_lab,
+                                     current_function_func_begin_label,
                                      "landing pad");
       else
        dw2_asm_output_data_uleb128 (0, "landing pad");
 #else
-      dw2_asm_output_delta (4, reg_start_lab, function_start_lab,
+      dw2_asm_output_delta (4, reg_start_lab,
+                           current_function_func_begin_label,
                            "region %d start", i);
       dw2_asm_output_delta (4, reg_end_lab, reg_start_lab, "length");
       if (cs->landing_pad)
-       dw2_asm_output_delta (4, landing_pad_lab, function_start_lab,
+       dw2_asm_output_delta (4, landing_pad_lab,
+                             current_function_func_begin_label,
                              "landing pad");
       else
        dw2_asm_output_data (4, 0, "landing pad");
@@ -3688,7 +3330,7 @@ dw2_output_call_site_table ()
 }
 
 static void
-sjlj_output_call_site_table ()
+sjlj_output_call_site_table (void)
 {
   int n = cfun->eh->call_site_data_used;
   int i;
@@ -3709,21 +3351,23 @@ sjlj_output_call_site_table ()
    table.  */
 
 void
-default_exception_section ()
+default_exception_section (void)
 {
   if (targetm.have_named_sections)
     {
       int flags;
-#ifdef HAVE_LD_RO_RW_SECTION_MIXING
-      int tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
 
-      flags = (! flag_pic
-              || ((tt_format & 0x70) != DW_EH_PE_absptr
-                  && (tt_format & 0x70) != DW_EH_PE_aligned))
-             ? 0 : SECTION_WRITE;
-#else
-      flags = SECTION_WRITE;
-#endif
+      if (EH_TABLES_CAN_BE_READ_ONLY)
+       {
+         int tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
+         
+         flags = (! flag_pic
+                  || ((tt_format & 0x70) != DW_EH_PE_absptr
+                      && (tt_format & 0x70) != DW_EH_PE_aligned))
+           ? 0 : SECTION_WRITE;
+       }
+      else
+       flags = SECTION_WRITE;
       named_section_flags (".gcc_except_table", flags);
     }
   else if (flag_pic)
@@ -3733,7 +3377,7 @@ default_exception_section ()
 }
 
 void
-output_function_exception_table ()
+output_function_exception_table (void)
 {
   int tt_format, cs_format, lp_format, i, n;
 #ifdef HAVE_AS_LEB128
@@ -3750,17 +3394,19 @@ output_function_exception_table ()
   if (! cfun->uses_eh_lsda)
     return;
 
-#ifdef IA64_UNWIND_INFO
+#ifdef TARGET_UNWIND_INFO
+  /* TODO: Move this into target file.  */
+  assemble_external_libcall (eh_personality_libfunc);
   fputs ("\t.personality\t", asm_out_file);
   output_addr_const (asm_out_file, eh_personality_libfunc);
   fputs ("\n\t.handlerdata\n", asm_out_file);
   /* Note that varasm still thinks we're in the function's code section.
      The ".endp" directive that will immediately follow will take us back.  */
 #else
-  (*targetm.asm_out.exception_section) ();
+  targetm.asm_out.exception_section ();
 #endif
 
-  have_tt_data = (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) > 0
+  have_tt_data = (VEC_length (tree, cfun->eh->ttype_data) > 0
                  || VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) > 0);
 
   /* Indicate the format of the @TType entries.  */
@@ -3778,7 +3424,7 @@ output_function_exception_table ()
       assemble_align (tt_format_size * BITS_PER_UNIT);
     }
 
-  (*targetm.asm_out.internal_label) (asm_out_file, "LLSDA",
+  targetm.asm_out.internal_label (asm_out_file, "LLSDA",
                             current_function_funcdef_no);
 
   /* The LSDA header.  */
@@ -3823,7 +3469,7 @@ output_function_exception_table ()
       after_disp = (1 + size_of_uleb128 (call_site_len)
                    + call_site_len
                    + VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data)
-                   + (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data)
+                   + (VEC_length (tree, cfun->eh->ttype_data)
                       * tt_format_size));
 
       disp = after_disp;
@@ -3885,18 +3531,39 @@ output_function_exception_table ()
   if (have_tt_data)
     assemble_align (tt_format_size * BITS_PER_UNIT);
 
-  i = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data);
+  i = VEC_length (tree, cfun->eh->ttype_data);
   while (i-- > 0)
     {
-      tree type = VARRAY_TREE (cfun->eh->ttype_data, i);
+      tree type = VEC_index (tree, cfun->eh->ttype_data, i);
       rtx value;
 
       if (type == NULL_TREE)
-       type = integer_zero_node;
+       value = const0_rtx;
       else
-       type = lookup_type_for_runtime (type);
+       {
+         struct cgraph_varpool_node *node;
+
+         type = lookup_type_for_runtime (type);
+         value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
+
+         /* Let cgraph know that the rtti decl is used.  Not all of the
+            paths below go through assemble_integer, which would take
+            care of this for us.  */
+         STRIP_NOPS (type);
+         if (TREE_CODE (type) == ADDR_EXPR)
+           {
+             type = TREE_OPERAND (type, 0);
+             if (TREE_CODE (type) == VAR_DECL)
+               {
+                 node = cgraph_varpool_node (type);
+                 if (node)
+                   cgraph_varpool_mark_needed_node (node);
+               }
+           }
+         else
+           gcc_assert (TREE_CODE (type) == INTEGER_CST);
+       }
 
-      value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
       if (tt_format == DW_EH_PE_absptr || tt_format == DW_EH_PE_aligned)
        assemble_integer (value, tt_format_size,
                          tt_format_size * BITS_PER_UNIT, 1);
@@ -3915,7 +3582,151 @@ output_function_exception_table ()
     dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->ehspec_data, i),
                         (i ? NULL : "Exception specification table"));
 
-  function_section (current_function_decl);
+  current_function_section (current_function_decl);
+}
+
+void
+set_eh_throw_stmt_table (struct function *fun, struct htab *table)
+{
+  fun->eh->throw_stmt_table = table;
+}
+
+htab_t
+get_eh_throw_stmt_table (struct function *fun)
+{
+  return fun->eh->throw_stmt_table;
+}
+
+/* Dump EH information to OUT.  */
+void 
+dump_eh_tree (FILE *out, struct function *fun)
+{
+  struct eh_region *i;
+  int depth = 0;
+  static const char * const type_name[] = {"unknown", "cleanup", "try", "catch",
+                                          "allowed_exceptions", "must_not_throw",
+                                          "throw", "fixup"};
+
+  i = fun->eh->region_tree;
+  if (! i)
+    return;
+
+  fprintf (out, "Eh tree:\n");
+  while (1)
+    {
+      fprintf (out, "  %*s %i %s", depth * 2, "",
+              i->region_number, type_name [(int)i->type]);
+      if (i->tree_label)
+       {
+          fprintf (out, " tree_label:");
+         print_generic_expr (out, i->tree_label, 0);
+       }
+      fprintf (out, "\n");
+      /* If there are sub-regions, process them.  */
+      if (i->inner)
+       i = i->inner, depth++;
+      /* If there are peers, process them.  */
+      else if (i->next_peer)
+       i = i->next_peer;
+      /* Otherwise, step back up the tree to the next peer.  */
+      else
+       {
+         do {
+           i = i->outer;
+           depth--;
+           if (i == NULL)
+             return;
+         } while (i->next_peer == NULL);
+         i = i->next_peer;
+       }
+    }
 }
 
+/* Verify some basic invariants on EH datastructures.  Could be extended to
+   catch more.  */
+void 
+verify_eh_tree (struct function *fun)
+{
+  struct eh_region *i, *outer = NULL;
+  bool err = false;
+  int nvisited = 0;
+  int count = 0;
+  int j;
+  int depth = 0;
+
+  i = fun->eh->region_tree;
+  if (! i)
+    return;
+  for (j = fun->eh->last_region_number; j > 0; --j)
+    if (fun->eh->region_array[j])
+      {
+       count++;
+       if (fun->eh->region_array[j]->region_number != j)
+         {
+           error ("region_array is corrupted for region %i", i->region_number);
+           err = true;
+         }
+      }
+
+  while (1)
+    {
+      if (fun->eh->region_array[i->region_number] != i)
+       {
+         error ("region_array is corrupted for region %i", i->region_number);
+         err = true;
+       }
+      if (i->outer != outer)
+       {
+         error ("outer block of region %i is wrong", i->region_number);
+         err = true;
+       }
+      if (i->may_contain_throw && outer && !outer->may_contain_throw)
+       {
+         error ("region %i may contain throw and is contained in region that may not",
+                i->region_number);
+         err = true;
+       }
+      if (depth < 0)
+       {
+         error ("negative nesting depth of region %i", i->region_number);
+         err = true;
+       }
+      nvisited ++;
+      /* If there are sub-regions, process them.  */
+      if (i->inner)
+       outer = i, i = i->inner, depth++;
+      /* If there are peers, process them.  */
+      else if (i->next_peer)
+       i = i->next_peer;
+      /* Otherwise, step back up the tree to the next peer.  */
+      else
+       {
+         do {
+           i = i->outer;
+           depth--;
+           if (i == NULL)
+             {
+               if (depth != -1)
+                 {
+                   error ("Tree list ends on depth %i", depth + 1);
+                   err = true;
+                 }
+               if (count != nvisited)
+                 {
+                   error ("array does not match the region tree");
+                   err = true;
+                 }
+               if (err)
+                 {
+                   dump_eh_tree (stderr, fun);
+                   internal_error ("verify_eh_tree failed.");
+                 }
+               return;
+             }
+           outer = i->outer;
+         } while (i->next_peer == NULL);
+         i = i->next_peer;
+       }
+    }
+}
 #include "gt-except.h"