OSDN Git Service

* config/sh/t-sh (TARGET_LIBGCC2_CFLAGS): Define.
[pf3gnuchains/gcc-fork.git] / gcc / except.c
index a33f309..9fa60ff 100644 (file)
@@ -99,7 +99,7 @@ tree (*lang_eh_runtime_type) (tree);
 
 struct GTY(()) ehl_map_entry {
   rtx label;
-  struct eh_region *region;
+  struct eh_region_d *region;
 };
 
 static GTY(()) int call_site_base;
@@ -115,7 +115,7 @@ static int sjlj_fc_lsda_ofs;
 static int sjlj_fc_jbuf_ofs;
 \f
 
-struct GTY(()) call_site_record
+struct GTY(()) call_site_record_d
 {
   rtx landing_pad;
   int action;
@@ -144,9 +144,9 @@ 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 void remove_eh_handler (struct eh_region *);
-static void remove_eh_handler_and_replace (struct eh_region *,
-                                          struct eh_region *, bool);
+static void remove_eh_handler (struct eh_region_d *);
+static void remove_eh_handler_and_replace (struct eh_region_d *,
+                                          struct eh_region_d *, bool);
 
 /* The return value of reachable_next_level.  */
 enum reachable_code
@@ -162,22 +162,22 @@ enum reachable_code
 };
 
 struct reachable_info;
-static enum reachable_code reachable_next_level (struct eh_region *, tree,
+static enum reachable_code reachable_next_level (struct eh_region_d *, tree,
                                                 struct reachable_info *, bool);
 
 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 int collect_one_action_chain (htab_t, struct eh_region_d *);
+static int add_call_site (rtx, int, 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 (void);
+static int dw2_size_of_call_site_table (int);
 static int sjlj_size_of_call_site_table (void);
 #endif
-static void dw2_output_call_site_table (void);
+static void dw2_output_call_site_table (int, int);
 static void sjlj_output_call_site_table (void);
 
 \f
@@ -221,11 +221,13 @@ init_eh (void)
 
       sjlj_fc_type_node = lang_hooks.types.make_type (RECORD_TYPE);
 
-      f_prev = build_decl (FIELD_DECL, get_identifier ("__prev"),
+      f_prev = build_decl (BUILTINS_LOCATION,
+                          FIELD_DECL, get_identifier ("__prev"),
                           build_pointer_type (sjlj_fc_type_node));
       DECL_FIELD_CONTEXT (f_prev) = sjlj_fc_type_node;
 
-      f_cs = build_decl (FIELD_DECL, get_identifier ("__call_site"),
+      f_cs = build_decl (BUILTINS_LOCATION,
+                        FIELD_DECL, get_identifier ("__call_site"),
                         integer_type_node);
       DECL_FIELD_CONTEXT (f_cs) = sjlj_fc_type_node;
 
@@ -233,14 +235,17 @@ init_eh (void)
       tmp = build_array_type (lang_hooks.types.type_for_mode
                                (targetm.unwind_word_mode (), 1),
                              tmp);
-      f_data = build_decl (FIELD_DECL, get_identifier ("__data"), tmp);
+      f_data = build_decl (BUILTINS_LOCATION,
+                          FIELD_DECL, get_identifier ("__data"), tmp);
       DECL_FIELD_CONTEXT (f_data) = sjlj_fc_type_node;
 
-      f_per = build_decl (FIELD_DECL, get_identifier ("__personality"),
+      f_per = build_decl (BUILTINS_LOCATION,
+                         FIELD_DECL, get_identifier ("__personality"),
                          ptr_type_node);
       DECL_FIELD_CONTEXT (f_per) = sjlj_fc_type_node;
 
-      f_lsda = build_decl (FIELD_DECL, get_identifier ("__lsda"),
+      f_lsda = build_decl (BUILTINS_LOCATION,
+                          FIELD_DECL, get_identifier ("__lsda"),
                           ptr_type_node);
       DECL_FIELD_CONTEXT (f_lsda) = sjlj_fc_type_node;
 
@@ -260,7 +265,8 @@ init_eh (void)
 #endif
       tmp = build_index_type (tmp);
       tmp = build_array_type (ptr_type_node, tmp);
-      f_jbuf = build_decl (FIELD_DECL, get_identifier ("__jbuf"), tmp);
+      f_jbuf = build_decl (BUILTINS_LOCATION,
+                          FIELD_DECL, get_identifier ("__jbuf"), tmp);
 #ifdef DONT_USE_BUILTIN_SETJMP
       /* We don't know what the alignment requirements of the
         runtime's jmp_buf has.  Overestimate.  */
@@ -308,17 +314,17 @@ init_eh_for_function (void)
    These are used from tree-eh.c when processing exception related
    nodes during tree optimization.  */
 
-static struct eh_region *
-gen_eh_region (enum eh_region_type type, struct eh_region *outer)
+static struct eh_region_d *
+gen_eh_region (enum eh_region_type type, struct eh_region_d *outer)
 {
-  struct eh_region *new_eh;
+  struct eh_region_d *new_eh;
 
 #ifdef ENABLE_CHECKING
   gcc_assert (doing_eh (0));
 #endif
 
   /* Insert a new blank region as a leaf in the tree.  */
-  new_eh = GGC_CNEW (struct eh_region);
+  new_eh = GGC_CNEW (struct eh_region_d);
   new_eh->type = type;
   new_eh->outer = outer;
   if (outer)
@@ -337,23 +343,23 @@ gen_eh_region (enum eh_region_type type, struct eh_region *outer)
   return new_eh;
 }
 
-struct eh_region *
-gen_eh_region_cleanup (struct eh_region *outer)
+struct eh_region_d *
+gen_eh_region_cleanup (struct eh_region_d *outer)
 {
-  struct eh_region *cleanup = gen_eh_region (ERT_CLEANUP, outer);
+  struct eh_region_d *cleanup = gen_eh_region (ERT_CLEANUP, outer);
   return cleanup;
 }
 
-struct eh_region *
-gen_eh_region_try (struct eh_region *outer)
+struct eh_region_d *
+gen_eh_region_try (struct eh_region_d *outer)
 {
   return gen_eh_region (ERT_TRY, outer);
 }
 
-struct eh_region *
-gen_eh_region_catch (struct eh_region *t, tree type_or_list)
+struct eh_region_d *
+gen_eh_region_catch (struct eh_region_d *t, tree type_or_list)
 {
-  struct eh_region *c, *l;
+  struct eh_region_d *c, *l;
   tree type_list, type_node;
 
   /* Ensure to always end up with a type list to normalize further
@@ -382,10 +388,10 @@ gen_eh_region_catch (struct eh_region *t, tree type_or_list)
   return c;
 }
 
-struct eh_region *
-gen_eh_region_allowed (struct eh_region *outer, tree allowed)
+struct eh_region_d *
+gen_eh_region_allowed (struct eh_region_d *outer, tree allowed)
 {
-  struct eh_region *region = gen_eh_region (ERT_ALLOWED_EXCEPTIONS, outer);
+  struct eh_region_d *region = gen_eh_region (ERT_ALLOWED_EXCEPTIONS, outer);
   region->u.allowed.type_list = allowed;
 
   for (; allowed ; allowed = TREE_CHAIN (allowed))
@@ -394,26 +400,26 @@ gen_eh_region_allowed (struct eh_region *outer, tree allowed)
   return region;
 }
 
-struct eh_region *
-gen_eh_region_must_not_throw (struct eh_region *outer)
+struct eh_region_d *
+gen_eh_region_must_not_throw (struct eh_region_d *outer)
 {
   return gen_eh_region (ERT_MUST_NOT_THROW, outer);
 }
 
 int
-get_eh_region_number (struct eh_region *region)
+get_eh_region_number (struct eh_region_d *region)
 {
   return region->region_number;
 }
 
 bool
-get_eh_region_may_contain_throw (struct eh_region *region)
+get_eh_region_may_contain_throw (struct eh_region_d *region)
 {
   return region->may_contain_throw;
 }
 
 tree
-get_eh_region_tree_label (struct eh_region *region)
+get_eh_region_tree_label (struct eh_region_d *region)
 {
   return region->tree_label;
 }
@@ -425,7 +431,7 @@ get_eh_region_no_tree_label (int region)
 }
 
 void
-set_eh_region_tree_label (struct eh_region *region, tree lab)
+set_eh_region_tree_label (struct eh_region_d *region, tree lab)
 {
   region->tree_label = lab;
 }
@@ -434,12 +440,16 @@ void
 expand_resx_expr (tree exp)
 {
   int region_nr = TREE_INT_CST_LOW (TREE_OPERAND (exp, 0));
-  struct eh_region *reg = VEC_index (eh_region,
-                                    cfun->eh->region_array, region_nr);
+  rtx insn;
+  struct eh_region_d *reg = VEC_index (eh_region,
+                                      cfun->eh->region_array, region_nr);
 
-  gcc_assert (!reg->resume);
   do_pending_stack_adjust ();
-  reg->resume = emit_jump_insn (gen_rtx_RESX (VOIDmode, region_nr));
+  insn = emit_jump_insn (gen_rtx_RESX (VOIDmode, region_nr));
+  if (reg->resume)
+    reg->resume = gen_rtx_INSN_LIST (VOIDmode, insn, reg->resume);
+  else
+    reg->resume = insn;
   emit_barrier ();
 }
 
@@ -447,7 +457,7 @@ expand_resx_expr (tree exp)
    call to a function which itself may contain a throw.  */
 
 void
-note_eh_region_may_contain_throw (struct eh_region *region)
+note_eh_region_may_contain_throw (struct eh_region_d *region)
 {
   while (region && !region->may_contain_throw)
     {
@@ -486,7 +496,7 @@ get_exception_filter (void)
 void
 collect_eh_region_array (void)
 {
-  struct eh_region *i;
+  struct eh_region_d *i;
 
   i = cfun->eh->region_tree;
   if (! i)
@@ -538,9 +548,9 @@ collect_eh_region_array (void)
    a problem.  */
 
 static bool
-can_be_reached_by_runtime (sbitmap contains_stmt, struct eh_region *r)
+can_be_reached_by_runtime (sbitmap contains_stmt, struct eh_region_d *r)
 {
-  struct eh_region *i = r->inner;
+  struct eh_region_d *i = r->inner;
   unsigned n;
   bitmap_iterator bi;
 
@@ -559,7 +569,7 @@ can_be_reached_by_runtime (sbitmap contains_stmt, struct eh_region *r)
       if (i->type != ERT_MUST_NOT_THROW)
        {
          bool found = TEST_BIT (contains_stmt, i->region_number);
-         if (!found)
+         if (!found && i->aka)
            EXECUTE_IF_SET_IN_BITMAP (i->aka, 0, n, bi)
              if (TEST_BIT (contains_stmt, n))
              {
@@ -574,7 +584,7 @@ can_be_reached_by_runtime (sbitmap contains_stmt, struct eh_region *r)
             firest place.  */
          if (found)
            {
-             struct eh_region *i1 = i;
+             struct eh_region_d *i1 = i;
              tree type_thrown = NULL_TREE;
 
              if (i1->type == ERT_THROW)
@@ -614,10 +624,10 @@ can_be_reached_by_runtime (sbitmap contains_stmt, struct eh_region *r)
 /* Bring region R to the root of tree.  */
 
 static void
-bring_to_root (struct eh_region *r)
+bring_to_root (struct eh_region_d *r)
 {
-  struct eh_region **pp;
-  struct eh_region *outer = r->outer;
+  struct eh_region_d **pp;
+  struct eh_region_d *outer = r->outer;
   if (!r->outer)
     return;
   for (pp = &outer->inner; *pp != r; pp = &(*pp)->next_peer)
@@ -631,8 +641,8 @@ bring_to_root (struct eh_region *r)
 /* Return true if region R2 can be replaced by R1.  */
 
 static bool
-eh_region_replaceable_by_p (const struct eh_region *r1,
-                           const struct eh_region *r2)
+eh_region_replaceable_by_p (const struct eh_region_d *r1,
+                           const struct eh_region_d *r2)
 {
   /* Regions are semantically same if they are of same type,
      have same label and type.  */
@@ -649,7 +659,7 @@ eh_region_replaceable_by_p (const struct eh_region *r1,
        break;
       case ERT_TRY:
        {
-         struct eh_region *c1, *c2;
+         struct eh_region_d *c1, *c2;
          for (c1 = r1->u.eh_try.eh_catch,
               c2 = r2->u.eh_try.eh_catch;
               c1 && c2;
@@ -690,10 +700,10 @@ eh_region_replaceable_by_p (const struct eh_region *r1,
 /* Replace region R2 by R1.  */
 
 static void
-replace_region (struct eh_region *r1, struct eh_region *r2)
+replace_region (struct eh_region_d *r1, struct eh_region_d *r2)
 {
-  struct eh_region *next1 = r1->u.eh_try.eh_catch;
-  struct eh_region *next2 = r2->u.eh_try.eh_catch;
+  struct eh_region_d *next1 = r1->u.eh_try.eh_catch;
+  struct eh_region_d *next2 = r2->u.eh_try.eh_catch;
   bool is_try = r1->type == ERT_TRY;
 
   gcc_assert (r1->type != ERT_CATCH);
@@ -729,7 +739,7 @@ hash_type_list (tree t)
 static hashval_t
 hash_eh_region (const void *r)
 {
-  const struct eh_region *region = (const struct eh_region *)r;
+  const struct eh_region_d *region = (const struct eh_region_d *) r;
   hashval_t val = region->type;
 
   if (region->tree_label)
@@ -741,7 +751,7 @@ hash_eh_region (const void *r)
        break;
       case ERT_TRY:
        {
-         struct eh_region *c;
+         struct eh_region_d *c;
          for (c = region->u.eh_try.eh_catch;
               c; c = c->u.eh_catch.next_catch)
            val = iterative_hash_hashval_t (hash_eh_region (c), val);
@@ -770,8 +780,8 @@ hash_eh_region (const void *r)
 static int
 eh_regions_equal_p (const void *r1, const void *r2)
 {
-  return eh_region_replaceable_by_p ((const struct eh_region *)r1,
-                                    (const struct eh_region *)r2);
+  return eh_region_replaceable_by_p ((const struct eh_region_d *) r1,
+                                    (const struct eh_region_d *) r2);
 }
 
 /* Walk all peers of REGION and try to merge those regions
@@ -779,9 +789,9 @@ eh_regions_equal_p (const void *r1, const void *r2)
    recursively too.  */
 
 static bool
-merge_peers (struct eh_region *region)
+merge_peers (struct eh_region_d *region)
 {
-  struct eh_region *r1, *r2, *outer = NULL, *next;
+  struct eh_region_d *r1, *r2, *outer = NULL, *next;
   bool merged = false;
   int num_regions = 0;
   if (region)
@@ -851,7 +861,7 @@ merge_peers (struct eh_region *region)
          if (!*slot)
            *slot = r1;
          else
-           replace_region ((struct eh_region *)*slot, r1);
+           replace_region ((struct eh_region_d *) *slot, r1);
        }
       htab_delete (hash);
     }
@@ -868,10 +878,10 @@ void
 remove_unreachable_regions (sbitmap reachable, sbitmap contains_stmt)
 {
   int i;
-  struct eh_region *r;
+  struct eh_region_d *r;
   VEC(eh_region,heap) *must_not_throws = VEC_alloc (eh_region, heap, 16);
-  struct eh_region *local_must_not_throw = NULL;
-  struct eh_region *first_must_not_throw = NULL;
+  struct eh_region_d *local_must_not_throw = NULL;
+  struct eh_region_d *first_must_not_throw = NULL;
 
   for (i = cfun->eh->last_region_number; i > 0; --i)
     {
@@ -907,7 +917,7 @@ remove_unreachable_regions (sbitmap reachable, sbitmap contains_stmt)
              {
                /* TRY regions are reachable if any of its CATCH regions
                   are reachable.  */
-               struct eh_region *c;
+               struct eh_region_d *c;
                for (c = r->u.eh_try.eh_catch; c;
                     c = c->u.eh_catch.next_catch)
                  if (TEST_BIT (reachable, c->region_number))
@@ -1001,7 +1011,7 @@ label_to_region_map (void)
                         cfun->cfg->last_label_uid + 1);
   for (i = cfun->eh->last_region_number; i > 0; --i)
     {
-      struct eh_region *r = VEC_index (eh_region, cfun->eh->region_array, i);
+      struct eh_region_d *r = VEC_index (eh_region, cfun->eh->region_array, i);
       if (r && r->region_number == i
          && r->tree_label && LABEL_DECL_UID (r->tree_label) >= 0)
        {
@@ -1030,7 +1040,7 @@ num_eh_regions (void)
 int
 get_next_region_sharing_label (int region)
 {
-  struct eh_region *r;
+  struct eh_region_d *r;
   if (!region)
     return 0;
   r = VEC_index (eh_region, cfun->eh->region_array, region);
@@ -1039,6 +1049,43 @@ get_next_region_sharing_label (int region)
   return r->next_region_sharing_label->region_number;
 }
 
+/* Return bitmap of all labels that are handlers of must not throw regions.  */
+
+bitmap
+must_not_throw_labels (void)
+{
+  struct eh_region_d *i;
+  bitmap labels = BITMAP_ALLOC (NULL);
+
+  i = cfun->eh->region_tree;
+  if (! i)
+    return labels;
+
+  while (1)
+    {
+      if (i->type == ERT_MUST_NOT_THROW && i->tree_label
+          && LABEL_DECL_UID (i->tree_label) >= 0)
+        bitmap_set_bit (labels, LABEL_DECL_UID (i->tree_label));
+
+      /* If there are sub-regions, process them.  */
+      if (i->inner)
+       i = i->inner;
+      /* 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;
+           if (i == NULL)
+             return labels;
+         } while (i->next_peer == NULL);
+         i = i->next_peer;
+       }
+    }
+}
+
 /* Set up EH labels for RTL.  */
 
 void
@@ -1052,7 +1099,7 @@ convert_from_eh_region_ranges (void)
      we allocated earlier.  */
   for (i = 1; i <= n; ++i)
     {
-      struct eh_region *region;
+      struct eh_region_d *region;
 
       region = VEC_index (eh_region, cfun->eh->region_array, i);
       if (region && region->tree_label)
@@ -1070,7 +1117,7 @@ find_exception_handler_labels (void)
 
   for (i = cfun->eh->last_region_number; i > 0; --i)
     {
-      struct eh_region *region;
+      struct eh_region_d *region;
       rtx lab;
 
       region = VEC_index (eh_region, cfun->eh->region_array, i);
@@ -1092,7 +1139,7 @@ current_function_has_exception_handlers (void)
 
   for (i = cfun->eh->last_region_number; i > 0; --i)
     {
-      struct eh_region *region;
+      struct eh_region_d *region;
 
       region = VEC_index (eh_region, cfun->eh->region_array, i);
       if (region
@@ -1147,7 +1194,7 @@ duplicate_eh_regions_1 (eh_region old, eh_region outer, int eh_offset)
 {
   eh_region ret, n;
 
-  ret = n = GGC_NEW (struct eh_region);
+  ret = n = GGC_NEW (struct eh_region_d);
 
   *n = *old;
   n->outer = outer;
@@ -1185,8 +1232,8 @@ duplicate_eh_regions_1 (eh_region old, eh_region outer, int eh_offset)
 /* Look for first outer region of R (or R itself) that is
    TRY region. Return NULL if none.  */
 
-static struct eh_region *
-find_prev_try (struct eh_region * r)
+static struct eh_region_d *
+find_prev_try (struct eh_region_d * r)
 {
   for (; r && r->type != ERT_TRY; r = r->outer)
     if (r->type == ERT_MUST_NOT_THROW
@@ -1361,10 +1408,10 @@ duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
 /* Return new copy of eh region OLD inside region NEW_OUTER.
    Do not care about updating the tree otherwise.  */
 
-static struct eh_region *
-copy_eh_region_1 (struct eh_region *old, struct eh_region *new_outer)
+static struct eh_region_d *
+copy_eh_region_1 (struct eh_region_d *old, struct eh_region_d *new_outer)
 {
-  struct eh_region *new_eh = gen_eh_region (old->type, new_outer);
+  struct eh_region_d *new_eh = gen_eh_region (old->type, new_outer);
   new_eh->u = old->u;
   new_eh->tree_label = old->tree_label;
   new_eh->may_contain_throw = old->may_contain_throw;
@@ -1380,10 +1427,10 @@ copy_eh_region_1 (struct eh_region *old, struct eh_region *new_outer)
   
    Copy whole catch-try chain if neccesary.  */
 
-static struct eh_region *
-copy_eh_region (struct eh_region *old, struct eh_region *new_outer)
+static struct eh_region_d *
+copy_eh_region (struct eh_region_d *old, struct eh_region_d *new_outer)
 {
-  struct eh_region *r, *n, *old_try, *new_try, *ret = NULL;
+  struct eh_region_d *r, *n, *old_try, *new_try, *ret = NULL;
   VEC(eh_region,heap) *catch_list = NULL;
 
   if (old->type != ERT_CATCH)
@@ -1438,7 +1485,7 @@ copy_eh_region (struct eh_region *old, struct eh_region *new_outer)
 /* Callback for forach_reachable_handler that push REGION into single VECtor DATA.  */
 
 static void
-push_reachable_handler (struct eh_region *region, void *data)
+push_reachable_handler (struct eh_region_d *region, void *data)
 {
   VEC(eh_region,heap) **trace = (VEC(eh_region,heap) **) data;
   VEC_safe_push (eh_region, heap, *trace, region);
@@ -1448,17 +1495,17 @@ push_reachable_handler (struct eh_region *region, void *data)
    IS_RESX, INLINABLE_CALL and REGION_NMUBER match the parameter of
    foreach_reachable_handler.  */
 
-struct eh_region *
+struct eh_region_d *
 redirect_eh_edge_to_label (edge e, tree new_dest_label, bool is_resx,
                           bool inlinable_call, int region_number)
 {
-  struct eh_region *outer;
-  struct eh_region *region;
+  struct eh_region_d *outer;
+  struct eh_region_d *region;
   VEC (eh_region, heap) * trace = NULL;
   int i;
   int start_here = -1;
   basic_block old_bb = e->dest;
-  struct eh_region *old, *r = NULL;
+  struct eh_region_d *old, *r = NULL;
   bool update_inplace = true;
   edge_iterator ei;
   edge e2;
@@ -1584,7 +1631,7 @@ redirect_eh_edge_to_label (edge e, tree new_dest_label, bool is_resx,
 int
 eh_region_outermost (struct function *ifun, int region_a, int region_b)
 {
-  struct eh_region *rp_a, *rp_b;
+  struct eh_region_d *rp_a, *rp_b;
   sbitmap b_outer;
 
   gcc_assert (ifun->eh->last_region_number > 0);
@@ -1810,7 +1857,7 @@ assign_filter_values (void)
 
   for (i = cfun->eh->last_region_number; i > 0; --i)
     {
-      struct eh_region *r;
+      struct eh_region_d *r;
 
       r = VEC_index (eh_region, cfun->eh->region_array, i);
 
@@ -1905,7 +1952,7 @@ build_post_landing_pads (void)
 
   for (i = cfun->eh->last_region_number; i > 0; --i)
     {
-      struct eh_region *region;
+      struct eh_region_d *region;
       rtx seq;
 
       region = VEC_index (eh_region, cfun->eh->region_array, i);
@@ -1938,7 +1985,7 @@ build_post_landing_pads (void)
             switch statement generation code in expand_end_case.
             Rapid prototyping sez a sequence of ifs.  */
          {
-           struct eh_region *c;
+           struct eh_region_d *c;
            for (c = region->u.eh_try.eh_catch; c ; c = c->u.eh_catch.next_catch)
              {
                if (c->u.eh_catch.type_list == NULL)
@@ -1969,6 +2016,7 @@ build_post_landing_pads (void)
          /* 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.  */
+         gcc_assert (!region->resume);
          region->resume
            = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
          emit_barrier ();
@@ -1997,6 +2045,7 @@ build_post_landing_pads (void)
          /* 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.  */
+         gcc_assert (!region->resume);
          region->resume
            = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
          emit_barrier ();
@@ -2033,10 +2082,11 @@ connect_post_landing_pads (void)
 
   for (i = cfun->eh->last_region_number; i > 0; --i)
     {
-      struct eh_region *region;
-      struct eh_region *outer;
+      struct eh_region_d *region;
+      struct eh_region_d *outer;
       rtx seq;
       rtx barrier;
+      rtx resume_list;
 
       region = VEC_index (eh_region, cfun->eh->region_array, i);
       /* Mind we don't process a region more than once.  */
@@ -2045,7 +2095,7 @@ connect_post_landing_pads (void)
 
       /* If there is no RESX, or it has been deleted by flow, there's
         nothing to fix up.  */
-      if (! region->resume || INSN_DELETED_P (region->resume))
+      if (! region->resume)
        continue;
 
       /* Search for another landing pad in this function.  */
@@ -2053,46 +2103,55 @@ connect_post_landing_pads (void)
        if (outer->post_landing_pad)
          break;
 
-      start_sequence ();
-
-      if (outer)
-       {
-         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
+      for (resume_list = region->resume; resume_list;
+          resume_list = (GET_CODE (resume_list) == INSN_LIST
+                         ? XEXP (resume_list, 1) : NULL_RTX))
        {
-         emit_library_call (unwind_resume_libfunc, LCT_THROW,
-                            VOIDmode, 1, crtl->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 ()));
-       }
+         rtx resume = (GET_CODE (resume_list) == INSN_LIST
+                       ? XEXP (resume_list, 0) : resume_list);
+          if (INSN_DELETED_P (resume))
+           continue;
+         start_sequence ();
 
-      seq = get_insns ();
-      end_sequence ();
-      barrier = emit_insn_before (seq, region->resume);
-      /* Avoid duplicate barrier.  */
-      gcc_assert (BARRIER_P (barrier));
-      delete_insn (barrier);
-      delete_insn (region->resume);
+         if (outer)
+           {
+             edge e;
+             basic_block src, dest;
+
+             emit_jump (outer->post_landing_pad);
+             src = BLOCK_FOR_INSN (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, crtl->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 ();
+         barrier = emit_insn_before (seq, resume);
+         /* Avoid duplicate barrier.  */
+         gcc_assert (BARRIER_P (barrier));
+         delete_insn (barrier);
+         delete_insn (resume);
+       }
 
       /* ??? From tree-ssa we can wind up with catch regions whose
         label is not instantiated, but whose resx is present.  Now
@@ -2110,7 +2169,7 @@ dw2_build_landing_pads (void)
 
   for (i = cfun->eh->last_region_number; i > 0; --i)
     {
-      struct eh_region *region;
+      struct eh_region_d *region;
       rtx seq;
       basic_block bb;
       edge e;
@@ -2178,7 +2237,7 @@ sjlj_find_directly_reachable_regions (struct sjlj_lp_info *lp_info)
 
   for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
     {
-      struct eh_region *region;
+      struct eh_region_d *region;
       enum reachable_code rc;
       tree type_thrown;
       rtx note;
@@ -2234,7 +2293,8 @@ sjlj_assign_call_site_values (rtx dispatch_label, struct sjlj_lp_info *lp_info)
   for (i = cfun->eh->last_region_number; i > 0; --i)
     if (lp_info[i].directly_reachable)
       {
-       struct eh_region *r = VEC_index (eh_region, cfun->eh->region_array, i);
+       struct eh_region_d *r =
+         VEC_index (eh_region, cfun->eh->region_array, i);
 
        r->landing_pad = dispatch_label;
        lp_info[i].action_index = collect_one_action_chain (ar_hash, r);
@@ -2277,7 +2337,8 @@ sjlj_assign_call_site_values (rtx dispatch_label, struct sjlj_lp_info *lp_info)
          index = -1;
        /* Otherwise, look it up in the table.  */
        else
-         index = add_call_site (GEN_INT (lp_info[i].dispatch_index), action);
+         index = add_call_site (GEN_INT (lp_info[i].dispatch_index),
+                                action, 0);
 
        lp_info[i].call_site_index = index;
       }
@@ -2291,7 +2352,7 @@ sjlj_mark_call_sites (struct sjlj_lp_info *lp_info)
 
   for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
     {
-      struct eh_region *region;
+      struct eh_region_d *region;
       int this_call_site;
       rtx note, before, p;
 
@@ -2518,14 +2579,17 @@ sjlj_emit_dispatch_table (rtx dispatch_label, struct sjlj_lp_info *lp_info)
 
       emit_cmp_and_jump_insns (dispatch, GEN_INT (lp_info[i].dispatch_index),
                               EQ, NULL_RTX, TYPE_MODE (integer_type_node), 0,
-                              ((struct eh_region *)VEC_index (eh_region, cfun->eh->region_array, i))
-                               ->post_landing_pad);
+                              (((struct eh_region_d *)
+                                VEC_index (eh_region,
+                                           cfun->eh->region_array, i))
+                               ->post_landing_pad));
     }
 
   seq = get_insns ();
   end_sequence ();
 
-  before = (((struct eh_region *)VEC_index (eh_region, cfun->eh->region_array, first_reachable))
+  before = (((struct eh_region_d *)
+            VEC_index (eh_region, cfun->eh->region_array, first_reachable))
            ->post_landing_pad);
 
   bb = emit_to_new_bb_before (seq, before);
@@ -2636,11 +2700,11 @@ finish_eh_generation (void)
    region.*/
 
 static void
-remove_eh_handler_and_replace (struct eh_region *region,
-                              struct eh_region *replace,
+remove_eh_handler_and_replace (struct eh_region_d *region,
+                              struct eh_region_d *replace,
                               bool update_catch_try)
 {
-  struct eh_region **pp, **pp_start, *p, *outer, *inner;
+  struct eh_region_d **pp, **pp_start, *p, *outer, *inner;
   rtx lab;
 
   outer = region->outer;
@@ -2703,7 +2767,7 @@ remove_eh_handler_and_replace (struct eh_region *region,
   if (region->type == ERT_CATCH
       && update_catch_try)
     {
-      struct eh_region *eh_try, *next, *prev;
+      struct eh_region_d *eh_try, *next, *prev;
 
       for (eh_try = region->next_peer;
           eh_try->type == ERT_CATCH;
@@ -2733,7 +2797,7 @@ remove_eh_handler_and_replace (struct eh_region *region,
    etc.  */
 
 static void
-remove_eh_handler (struct eh_region *region)
+remove_eh_handler (struct eh_region_d *region)
 {
   remove_eh_handler_and_replace (region, region->outer, true);
 }
@@ -2743,7 +2807,7 @@ remove_eh_handler (struct eh_region *region)
 void
 remove_eh_region (int r)
 {
-  struct eh_region *region;
+  struct eh_region_d *region;
 
   region = VEC_index (eh_region, cfun->eh->region_array, r);
   remove_eh_handler (region);
@@ -2755,7 +2819,7 @@ remove_eh_region (int r)
 void
 remove_eh_region_and_replace_by_outer_of (int r, int r2)
 {
-  struct eh_region *region, *region2;
+  struct eh_region_d *region, *region2;
 
   region = VEC_index (eh_region, cfun->eh->region_array, r);
   region2 = VEC_index (eh_region, cfun->eh->region_array, r2);
@@ -2771,9 +2835,9 @@ for_each_eh_label (void (*callback) (rtx))
   int i;
   for (i = 0; i < cfun->eh->last_region_number; i++)
     {
-      struct eh_region *r = VEC_index (eh_region, cfun->eh->region_array, i);
+      struct eh_region_d *r = VEC_index (eh_region, cfun->eh->region_array, i);
       if (r && r->region_number == i && r->label
-          && GET_CODE (r->label) == CODE_LABEL)
+          && LABEL_P (r->label))
        (*callback) (r->label);
     }
 }
@@ -2781,12 +2845,12 @@ for_each_eh_label (void (*callback) (rtx))
 /* Invoke CALLBACK for every exception region in the current function.  */
 
 void
-for_each_eh_region (void (*callback) (struct eh_region *))
+for_each_eh_region (void (*callback) (struct eh_region_d *))
 {
   int i, n = cfun->eh->last_region_number;
   for (i = 1; i <= n; ++i)
     {
-      struct eh_region *region;
+      struct eh_region_d *region;
 
       region = VEC_index (eh_region, cfun->eh->region_array, i);
       if (region)
@@ -2801,7 +2865,7 @@ struct reachable_info
 {
   tree types_caught;
   tree types_allowed;
-  void (*callback) (struct eh_region *, void *);
+  void (*callback) (struct eh_region_d *, void *);
   void *callback_data;
 };
 
@@ -2840,7 +2904,8 @@ check_handled (tree handled, tree type)
 
 static void
 add_reachable_handler (struct reachable_info *info,
-                      struct eh_region *lp_region, struct eh_region *region)
+                      struct eh_region_d *lp_region,
+                      struct eh_region_d *region)
 {
   if (! info)
     return;
@@ -2857,7 +2922,7 @@ add_reachable_handler (struct reachable_info *info,
    and caught/allowed type information between invocations.  */
 
 static enum reachable_code
-reachable_next_level (struct eh_region *region, tree type_thrown,
+reachable_next_level (struct eh_region_d *region, tree type_thrown,
                      struct reachable_info *info,
                      bool maybe_resx)
 {
@@ -2872,7 +2937,7 @@ reachable_next_level (struct eh_region *region, tree type_thrown,
 
     case ERT_TRY:
       {
-       struct eh_region *c;
+       struct eh_region_d *c;
        enum reachable_code ret = RNL_NOT_CAUGHT;
 
        for (c = region->u.eh_try.eh_catch; c ; c = c->u.eh_catch.next_catch)
@@ -3026,11 +3091,11 @@ reachable_next_level (struct eh_region *region, tree type_thrown,
 
 void
 foreach_reachable_handler (int region_number, bool is_resx, bool inlinable_call,
-                          void (*callback) (struct eh_region *, void *),
+                          void (*callback) (struct eh_region_d *, void *),
                           void *callback_data)
 {
   struct reachable_info info;
-  struct eh_region *region;
+  struct eh_region_d *region;
   tree type_thrown;
 
   memset (&info, 0, sizeof (info));
@@ -3088,7 +3153,7 @@ foreach_reachable_handler (int region_number, bool is_resx, bool inlinable_call,
    reached by a given insn.  */
 
 static void
-arh_to_landing_pad (struct eh_region *region, void *data)
+arh_to_landing_pad (struct eh_region_d *region, void *data)
 {
   rtx *p_handlers = (rtx *) data;
   if (! *p_handlers)
@@ -3096,7 +3161,7 @@ arh_to_landing_pad (struct eh_region *region, void *data)
 }
 
 static void
-arh_to_label (struct eh_region *region, void *data)
+arh_to_label (struct eh_region_d *region, void *data)
 {
   rtx *p_handlers = (rtx *) data;
   *p_handlers = alloc_INSN_LIST (region->label, *p_handlers);
@@ -3138,7 +3203,7 @@ reachable_handlers (rtx insn)
 bool
 can_throw_internal_1 (int region_number, bool is_resx, bool inlinable_call)
 {
-  struct eh_region *region;
+  struct eh_region_d *region;
   tree type_thrown;
 
   region = VEC_index (eh_region, cfun->eh->region_array, region_number);
@@ -3201,7 +3266,7 @@ can_throw_internal (const_rtx insn)
 bool
 can_throw_external_1 (int region_number, bool is_resx, bool inlinable_call)
 {
-  struct eh_region *region;
+  struct eh_region_d *region;
   tree type_thrown;
 
   region = VEC_index (eh_region, cfun->eh->region_array, region_number);
@@ -3609,9 +3674,9 @@ add_action_record (htab_t ar_hash, int filter, int next)
 }
 
 static int
-collect_one_action_chain (htab_t ar_hash, struct eh_region *region)
+collect_one_action_chain (htab_t ar_hash, struct eh_region_d *region)
 {
-  struct eh_region *c;
+  struct eh_region_d *c;
   int next;
 
   /* If we've reached the top of the region chain, then we have
@@ -3720,17 +3785,19 @@ collect_one_action_chain (htab_t ar_hash, struct eh_region *region)
 }
 
 static int
-add_call_site (rtx landing_pad, int action)
+add_call_site (rtx landing_pad, int action, int section)
 {
   call_site_record record;
   
-  record = GGC_NEW (struct call_site_record);
+  record = GGC_NEW (struct call_site_record_d);
   record->landing_pad = landing_pad;
   record->action = action;
 
-  VEC_safe_push (call_site_record, gc, crtl->eh.call_site_record, record);
+  VEC_safe_push (call_site_record, gc,
+                crtl->eh.call_site_record[section], record);
 
-  return call_site_base + VEC_length (call_site_record, crtl->eh.call_site_record) - 1;
+  return call_site_base + VEC_length (call_site_record,
+                                     crtl->eh.call_site_record[section]) - 1;
 }
 
 /* Turn REG_EH_REGION notes back into NOTE_INSN_EH_REGION notes.
@@ -3747,6 +3814,14 @@ convert_to_eh_region_ranges (void)
   rtx last_landing_pad = NULL_RTX;
   rtx first_no_action_insn = NULL_RTX;
   int call_site = 0;
+  int cur_sec = 0;
+  rtx section_switch_note = NULL_RTX;
+  rtx first_no_action_insn_before_switch = NULL_RTX;
+  rtx last_no_action_insn_before_switch = NULL_RTX;
+  rtx *pad_map = NULL;
+  sbitmap pad_loc = NULL;
+  int min_labelno = 0, max_labelno = 0;
+  int saved_call_site_base = call_site_base;
 
   if (USING_SJLJ_EXCEPTIONS || cfun->eh->region_tree == NULL)
     return 0;
@@ -3758,7 +3833,7 @@ convert_to_eh_region_ranges (void)
   for (iter = get_insns (); iter ; iter = NEXT_INSN (iter))
     if (INSN_P (iter))
       {
-       struct eh_region *region;
+       struct eh_region_d *region;
        int this_action;
        rtx this_landing_pad;
 
@@ -3802,7 +3877,7 @@ convert_to_eh_region_ranges (void)
           landing pads.  Collect the landing pad for this region.  */
        if (this_action >= 0)
          {
-           struct eh_region *o;
+           struct eh_region_d *o;
            for (o = region; ! o->landing_pad ; o = o->outer)
              continue;
            this_landing_pad = o->landing_pad;
@@ -3821,9 +3896,27 @@ convert_to_eh_region_ranges (void)
            if (last_action >= -1)
              {
                /* If we delayed the creation of the begin, do it now.  */
+               if (first_no_action_insn_before_switch)
+                 {
+                   call_site = add_call_site (NULL_RTX, 0, 0);
+                   note
+                     = emit_note_before (NOTE_INSN_EH_REGION_BEG,
+                                         first_no_action_insn_before_switch);
+                   NOTE_EH_HANDLER (note) = call_site;
+                   if (first_no_action_insn)
+                     {
+                       note
+                         = emit_note_after (NOTE_INSN_EH_REGION_END,
+                                            last_no_action_insn_before_switch);
+                       NOTE_EH_HANDLER (note) = call_site;
+                     }
+                   else
+                     gcc_assert (last_action_insn
+                                 == last_no_action_insn_before_switch);
+                 }
                if (first_no_action_insn)
                  {
-                   call_site = add_call_site (NULL_RTX, 0);
+                   call_site = add_call_site (NULL_RTX, 0, cur_sec);
                    note = emit_note_before (NOTE_INSN_EH_REGION_BEG,
                                             first_no_action_insn);
                    NOTE_EH_HANDLER (note) = call_site;
@@ -3840,7 +3933,8 @@ convert_to_eh_region_ranges (void)
            if (this_action >= -1)
              {
                call_site = add_call_site (this_landing_pad,
-                                          this_action < 0 ? 0 : this_action);
+                                          this_action < 0 ? 0 : this_action,
+                                          cur_sec);
                note = emit_note_before (NOTE_INSN_EH_REGION_BEG, iter);
                NOTE_EH_HANDLER (note) = call_site;
              }
@@ -3850,6 +3944,37 @@ convert_to_eh_region_ranges (void)
          }
        last_action_insn = iter;
       }
+    else if (NOTE_P (iter)
+            && NOTE_KIND (iter) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
+      {
+       gcc_assert (section_switch_note == NULL_RTX);
+       gcc_assert (flag_reorder_blocks_and_partition);
+       section_switch_note = iter;
+       if (first_no_action_insn)
+         {
+           first_no_action_insn_before_switch = first_no_action_insn;
+           last_no_action_insn_before_switch = last_action_insn;
+           first_no_action_insn = NULL_RTX;
+           gcc_assert (last_action == -1);
+           last_action = -3;
+         }
+       /* Force closing of current EH region before section switch and
+          opening a new one afterwards.  */
+       else if (last_action != -3)
+         last_landing_pad = pc_rtx;
+       call_site_base += VEC_length (call_site_record,
+                                     crtl->eh.call_site_record[cur_sec]);
+       cur_sec++;
+       gcc_assert (crtl->eh.call_site_record[cur_sec] == NULL);
+       crtl->eh.call_site_record[cur_sec]
+         = VEC_alloc (call_site_record, gc, 10);
+       max_labelno = max_label_num ();
+       min_labelno = get_first_label_num ();
+       pad_map = XCNEWVEC (rtx, max_labelno - min_labelno + 1);
+       pad_loc = sbitmap_alloc (max_labelno - min_labelno + 1);
+      }
+    else if (LABEL_P (iter) && pad_map)
+      SET_BIT (pad_loc, CODE_LABEL_NUMBER (iter) - min_labelno);
 
   if (last_action >= -1 && ! first_no_action_insn)
     {
@@ -3857,6 +3982,105 @@ convert_to_eh_region_ranges (void)
       NOTE_EH_HANDLER (note) = call_site;
     }
 
+  call_site_base = saved_call_site_base;
+
+  if (pad_map)
+    {
+      /* When doing hot/cold partitioning, ensure landing pads are
+        always in the same section as the EH region, .gcc_except_table
+        can't express it otherwise.  */
+      for (cur_sec = 0; cur_sec < 2; cur_sec++)
+       {
+         int i, idx;
+         int n = VEC_length (call_site_record,
+                             crtl->eh.call_site_record[cur_sec]);
+         basic_block prev_bb = NULL, padbb;
+
+         for (i = 0; i < n; ++i)
+           {
+             struct call_site_record_d *cs =
+               VEC_index (call_site_record,
+                          crtl->eh.call_site_record[cur_sec], i);
+             rtx jump, note;
+
+             if (cs->landing_pad == NULL_RTX)
+               continue;
+             idx = CODE_LABEL_NUMBER (cs->landing_pad) - min_labelno;
+             /* If the landing pad is in the correct section, nothing
+                is needed.  */
+             if (TEST_BIT (pad_loc, idx) ^ (cur_sec == 0))
+               continue;
+             /* Otherwise, if we haven't seen this pad yet, we need to
+                add a new label and jump to the correct section.  */
+             if (pad_map[idx] == NULL_RTX)
+               {
+                 pad_map[idx] = gen_label_rtx ();
+                 if (prev_bb == NULL)
+                   for (iter = section_switch_note;
+                        iter; iter = PREV_INSN (iter))
+                     if (NOTE_INSN_BASIC_BLOCK_P (iter))
+                       {
+                         prev_bb = NOTE_BASIC_BLOCK (iter);
+                         break;
+                       }
+                 if (cur_sec == 0)
+                   {
+                     note = emit_label_before (pad_map[idx],
+                                               section_switch_note);
+                     jump = emit_jump_insn_before (gen_jump (cs->landing_pad),
+                                                   section_switch_note);
+                   }
+                 else
+                   {
+                     jump = emit_jump_insn_after (gen_jump (cs->landing_pad),
+                                                  section_switch_note);
+                     note = emit_label_after (pad_map[idx],
+                                              section_switch_note);
+                   }
+                 JUMP_LABEL (jump) = cs->landing_pad;
+                 add_reg_note (jump, REG_CROSSING_JUMP, NULL_RTX);
+                 iter = NEXT_INSN (cs->landing_pad);
+                 if (iter && NOTE_INSN_BASIC_BLOCK_P (iter))
+                   padbb = NOTE_BASIC_BLOCK (iter);
+                 else
+                   padbb = NULL;
+                 if (padbb && prev_bb
+                     && BB_PARTITION (padbb) != BB_UNPARTITIONED)
+                   {
+                     basic_block bb;
+                     int part
+                       = BB_PARTITION (padbb) == BB_COLD_PARTITION
+                         ? BB_HOT_PARTITION : BB_COLD_PARTITION;
+                     edge_iterator ei;
+                     edge e;
+
+                     bb = create_basic_block (note, jump, prev_bb);
+                     make_single_succ_edge (bb, padbb, EDGE_CROSSING);
+                     BB_SET_PARTITION (bb, part);
+                     for (ei = ei_start (padbb->preds);
+                          (e = ei_safe_edge (ei)); )
+                       {
+                         if ((e->flags & (EDGE_EH|EDGE_CROSSING))
+                             == (EDGE_EH|EDGE_CROSSING))
+                           {
+                             redirect_edge_succ (e, bb);
+                             e->flags &= ~EDGE_CROSSING;
+                           }
+                         else
+                           ei_next (&ei);
+                       }
+                     if (cur_sec == 0)
+                       prev_bb = bb;
+                   }
+               }
+             cs->landing_pad = pad_map[idx];
+           }
+       }
+
+      sbitmap_free (pad_loc);
+      XDELETEVEC (pad_map);
+    }
+
   htab_delete (ar_hash);
   return 0;
 }
@@ -3917,15 +4141,16 @@ push_sleb128 (varray_type *data_area, int value)
 \f
 #ifndef HAVE_AS_LEB128
 static int
-dw2_size_of_call_site_table (void)
+dw2_size_of_call_site_table (int section)
 {
-  int n = VEC_length (call_site_record, crtl->eh.call_site_record);
+  int n = VEC_length (call_site_record, crtl->eh.call_site_record[section]);
   int size = n * (4 + 4 + 4);
   int i;
 
   for (i = 0; i < n; ++i)
     {
-      struct call_site_record *cs = VEC_index (call_site_record, crtl->eh.call_site_record, i);
+      struct call_site_record_d *cs =
+       VEC_index (call_site_record, crtl->eh.call_site_record[section], i);
       size += size_of_uleb128 (cs->action);
     }
 
@@ -3935,13 +4160,14 @@ dw2_size_of_call_site_table (void)
 static int
 sjlj_size_of_call_site_table (void)
 {
-  int n = VEC_length (call_site_record, crtl->eh.call_site_record);
+  int n = VEC_length (call_site_record, crtl->eh.call_site_record[0]);
   int size = 0;
   int i;
 
   for (i = 0; i < n; ++i)
     {
-      struct call_site_record *cs = VEC_index (call_site_record, crtl->eh.call_site_record, i);
+      struct call_site_record_d *cs =
+       VEC_index (call_site_record, crtl->eh.call_site_record[0], i);
       size += size_of_uleb128 (INTVAL (cs->landing_pad));
       size += size_of_uleb128 (cs->action);
     }
@@ -3951,14 +4177,23 @@ sjlj_size_of_call_site_table (void)
 #endif
 
 static void
-dw2_output_call_site_table (void)
+dw2_output_call_site_table (int cs_format, int section)
 {
-  int n = VEC_length (call_site_record, crtl->eh.call_site_record);
+  int n = VEC_length (call_site_record, crtl->eh.call_site_record[section]);
   int i;
+  const char *begin;
+
+  if (section == 0)
+    begin = current_function_func_begin_label;
+  else if (first_function_block_is_cold)
+    begin = crtl->subsections.hot_section_label;
+  else
+    begin = crtl->subsections.cold_section_label;
 
   for (i = 0; i < n; ++i)
     {
-      struct call_site_record *cs = VEC_index (call_site_record, crtl->eh.call_site_record, i);
+      struct call_site_record_d *cs =
+       VEC_index (call_site_record, crtl->eh.call_site_record[section], i);
       char reg_start_lab[32];
       char reg_end_lab[32];
       char landing_pad_lab[32];
@@ -3974,30 +4209,29 @@ dw2_output_call_site_table (void)
         generic arithmetic.  */
       /* ??? 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,
-                                   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,
-                                     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,
-                           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,
-                             current_function_func_begin_label,
-                             "landing pad");
+      if (cs_format == DW_EH_PE_uleb128)
+       {
+         dw2_asm_output_delta_uleb128 (reg_start_lab, begin,
+                                       "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, begin,
+                                         "landing pad");
+         else
+           dw2_asm_output_data_uleb128 (0, "landing pad");
+       }
       else
-       dw2_asm_output_data (4, 0, "landing pad");
-#endif
+       {
+         dw2_asm_output_delta (4, reg_start_lab, begin,
+                               "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, begin,
+                                 "landing pad");
+         else
+           dw2_asm_output_data (4, 0, "landing pad");
+       }
       dw2_asm_output_data_uleb128 (cs->action, "action");
     }
 
@@ -4007,12 +4241,13 @@ dw2_output_call_site_table (void)
 static void
 sjlj_output_call_site_table (void)
 {
-  int n = VEC_length (call_site_record, crtl->eh.call_site_record);
+  int n = VEC_length (call_site_record, crtl->eh.call_site_record[0]);
   int i;
 
   for (i = 0; i < n; ++i)
     {
-      struct call_site_record *cs = VEC_index (call_site_record, crtl->eh.call_site_record, i);
+      struct call_site_record_d *cs =
+       VEC_index (call_site_record, crtl->eh.call_site_record[0], i);
 
       dw2_asm_output_data_uleb128 (INTVAL (cs->landing_pad),
                                   "region %d landing pad", i);
@@ -4124,8 +4359,9 @@ output_ttype (tree type, int tt_format, int tt_format_size)
     dw2_asm_output_encoded_addr_rtx (tt_format, value, is_public, NULL);
 }
 
-void
-output_function_exception_table (const char * ARG_UNUSED (fnname))
+static void
+output_one_function_exception_table (const char * ARG_UNUSED (fnname),
+                                    int section)
 {
   int tt_format, cs_format, lp_format, i, n;
 #ifdef HAVE_AS_LEB128
@@ -4138,13 +4374,6 @@ output_function_exception_table (const char * ARG_UNUSED (fnname))
   int have_tt_data;
   int tt_format_size = 0;
 
-  /* Not all functions need anything.  */
-  if (! crtl->uses_eh_lsda)
-    return;
-
-  if (eh_personality_libfunc)
-    assemble_external_libcall (eh_personality_libfunc);
-
 #ifdef TARGET_UNWIND_INFO
   /* TODO: Move this into target file.  */
   fputs ("\t.personality\t", asm_out_file);
@@ -4169,7 +4398,8 @@ output_function_exception_table (const char * ARG_UNUSED (fnname))
     {
       tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
 #ifdef HAVE_AS_LEB128
-      ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT",
+      ASM_GENERATE_INTERNAL_LABEL (ttype_label,
+                                  section ? "LLSDATTC" : "LLSDATT",
                                   current_function_funcdef_no);
 #endif
       tt_format_size = size_of_encoded_value (tt_format);
@@ -4177,8 +4407,8 @@ output_function_exception_table (const char * ARG_UNUSED (fnname))
       assemble_align (tt_format_size * BITS_PER_UNIT);
     }
 
-  targetm.asm_out.internal_label (asm_out_file, "LLSDA",
-                            current_function_funcdef_no);
+  targetm.asm_out.internal_label (asm_out_file, section ? "LLSDAC" : "LLSDA",
+                                 current_function_funcdef_no);
 
   /* The LSDA header.  */
 
@@ -4201,7 +4431,7 @@ output_function_exception_table (const char * ARG_UNUSED (fnname))
   if (USING_SJLJ_EXCEPTIONS)
     call_site_len = sjlj_size_of_call_site_table ();
   else
-    call_site_len = dw2_size_of_call_site_table ();
+    call_site_len = dw2_size_of_call_site_table (section);
 #endif
 
   /* A pc-relative 4-byte displacement to the @TType data.  */
@@ -4209,7 +4439,8 @@ output_function_exception_table (const char * ARG_UNUSED (fnname))
     {
 #ifdef HAVE_AS_LEB128
       char ttype_after_disp_label[32];
-      ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label, "LLSDATTD",
+      ASM_GENERATE_INTERNAL_LABEL (ttype_after_disp_label,
+                                  section ? "LLSDATTDC" : "LLSDATTD",
                                   current_function_funcdef_no);
       dw2_asm_output_delta_uleb128 (ttype_label, ttype_after_disp_label,
                                    "@TType base offset");
@@ -4255,9 +4486,11 @@ output_function_exception_table (const char * ARG_UNUSED (fnname))
                       eh_data_format_name (cs_format));
 
 #ifdef HAVE_AS_LEB128
-  ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label, "LLSDACSB",
+  ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label,
+                              section ? "LLSDACSBC" : "LLSDACSB",
                               current_function_funcdef_no);
-  ASM_GENERATE_INTERNAL_LABEL (cs_end_label, "LLSDACSE",
+  ASM_GENERATE_INTERNAL_LABEL (cs_end_label,
+                              section ? "LLSDACSEC" : "LLSDACSE",
                               current_function_funcdef_no);
   dw2_asm_output_delta_uleb128 (cs_end_label, cs_after_size_label,
                                "Call-site table length");
@@ -4265,14 +4498,14 @@ output_function_exception_table (const char * ARG_UNUSED (fnname))
   if (USING_SJLJ_EXCEPTIONS)
     sjlj_output_call_site_table ();
   else
-    dw2_output_call_site_table ();
+    dw2_output_call_site_table (cs_format, section);
   ASM_OUTPUT_LABEL (asm_out_file, cs_end_label);
 #else
-  dw2_asm_output_data_uleb128 (call_site_len,"Call-site table length");
+  dw2_asm_output_data_uleb128 (call_site_len, "Call-site table length");
   if (USING_SJLJ_EXCEPTIONS)
     sjlj_output_call_site_table ();
   else
-    dw2_output_call_site_table ();
+    dw2_output_call_site_table (cs_format, section);
 #endif
 
   /* ??? Decode and interpret the data for flag_debug_asm.  */
@@ -4309,6 +4542,21 @@ output_function_exception_table (const char * ARG_UNUSED (fnname))
        dw2_asm_output_data (1, VARRAY_UCHAR (crtl->eh.ehspec_data, i),
                             (i ? NULL : "Exception specification table"));
     }
+}
+
+void
+output_function_exception_table (const char * ARG_UNUSED (fnname))
+{
+  /* Not all functions need anything.  */
+  if (! crtl->uses_eh_lsda)
+    return;
+
+  if (eh_personality_libfunc)
+    assemble_external_libcall (eh_personality_libfunc);
+
+  output_one_function_exception_table (fnname, 0);
+  if (crtl->eh.call_site_record[1] != NULL)
+    output_one_function_exception_table (fnname, 1);
 
   switch_to_section (current_function_section ());
 }
@@ -4330,7 +4578,7 @@ get_eh_throw_stmt_table (struct function *fun)
 void
 dump_eh_tree (FILE * out, struct function *fun)
 {
-  struct eh_region *i;
+  struct eh_region_d *i;
   int depth = 0;
   static const char *const type_name[] = { "unknown", "cleanup", "try", "catch",
                                           "allowed_exceptions", "must_not_throw",
@@ -4356,19 +4604,28 @@ dump_eh_tree (FILE * out, struct function *fun)
       if (i->landing_pad)
        {
           fprintf (out, " landing_pad:%i", INSN_UID (i->landing_pad));
-         if (GET_CODE (i->landing_pad) == NOTE)
+         if (NOTE_P (i->landing_pad))
            fprintf (out, " (deleted)");
         }
       if (i->post_landing_pad)
        {
           fprintf (out, " post_landing_pad:%i", INSN_UID (i->post_landing_pad));
-         if (GET_CODE (i->post_landing_pad) == NOTE)
+         if (NOTE_P (i->post_landing_pad))
            fprintf (out, " (deleted)");
        }
       if (i->resume)
        {
+         rtx resume_list = i->resume;
+          fprintf (out, " resume:");
+         while (GET_CODE (resume_list) == INSN_LIST)
+           {
+             fprintf (out, "%i,", INSN_UID (XEXP (resume_list, 0)));
+             if (NOTE_P (XEXP (resume_list, 0)))
+               fprintf (out, " (deleted)");
+             resume_list = XEXP (resume_list, 1);
+           }
           fprintf (out, " resume:%i", INSN_UID (i->resume));
-         if (GET_CODE (i->resume) == NOTE)
+         if (NOTE_P (i->resume))
            fprintf (out, " (deleted)");
        }
       if (i->may_contain_throw)
@@ -4380,7 +4637,7 @@ dump_eh_tree (FILE * out, struct function *fun)
 
        case ERT_TRY:
          {
-           struct eh_region *c;
+           struct eh_region_d *c;
            fprintf (out, " catch regions:");
            for (c = i->u.eh_try.eh_catch; c; c = c->u.eh_catch.next_catch)
              fprintf (out, " %i", c->region_number);
@@ -4455,7 +4712,7 @@ debug_eh_tree (struct function *fn)
 /* Verify EH region invariants.  */
 
 static bool
-verify_eh_region (struct eh_region *region)
+verify_eh_region (struct eh_region_d *region)
 {
   bool found = false;
   if (!region)
@@ -4464,7 +4721,7 @@ verify_eh_region (struct eh_region *region)
     {
     case ERT_TRY:
       {
-       struct eh_region *c, *prev = NULL;
+       struct eh_region_d *c, *prev = NULL;
        if (region->u.eh_try.eh_catch->u.eh_catch.prev_catch)
          {
            error ("Try region %i has wrong rh_catch pointer to %i",
@@ -4526,7 +4783,7 @@ verify_eh_region (struct eh_region *region)
 void
 verify_eh_tree (struct function *fun)
 {
-  struct eh_region *i, *outer = NULL;
+  struct eh_region_d *i, *outer = NULL;
   bool err = false;
   int nvisited = 0;
   int count = 0;