]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/except.c
gcov: rename 2 options.
[thirdparty/gcc.git] / gcc / except.c
index c8dbc50141c6f6357ae0f60e614f8afd79452315..5df0a4c163d426275efe52d41ac541e71a6add6b 100644 (file)
@@ -1,5 +1,5 @@
 /* Implements exception handling.
-   Copyright (C) 1989-2014 Free Software Foundation, Inc.
+   Copyright (C) 1989-2020 Free Software Foundation, Inc.
    Contributed by Mike Stump <mrs@cygnus.com>.
 
 This file is part of GCC.
@@ -27,14 +27,14 @@ along with GCC; see the file COPYING3.  If not see
    the compilation process:
 
    In the beginning, in the front end, we have the GENERIC trees
-   TRY_CATCH_EXPR, TRY_FINALLY_EXPR, WITH_CLEANUP_EXPR,
+   TRY_CATCH_EXPR, TRY_FINALLY_EXPR, EH_ELSE_EXPR, WITH_CLEANUP_EXPR,
    CLEANUP_POINT_EXPR, CATCH_EXPR, and EH_FILTER_EXPR.
 
-   During initial gimplification (gimplify.c) these are lowered
-   to the GIMPLE_TRY, GIMPLE_CATCH, and GIMPLE_EH_FILTER nodes.
-   The WITH_CLEANUP_EXPR and CLEANUP_POINT_EXPR nodes are converted
-   into GIMPLE_TRY_FINALLY nodes; the others are a more direct 1-1
-   conversion.
+   During initial gimplification (gimplify.c) these are lowered to the
+   GIMPLE_TRY, GIMPLE_CATCH, GIMPLE_EH_ELSE, and GIMPLE_EH_FILTER
+   nodes.  The WITH_CLEANUP_EXPR and CLEANUP_POINT_EXPR nodes are
+   converted into GIMPLE_TRY_FINALLY nodes; the others are a more
+   direct 1-1 conversion.
 
    During pass_lower_eh (tree-eh.c) we record the nested structure
    of the TRY nodes in EH_REGION nodes in CFUN->EH->REGION_TREE.
@@ -112,46 +112,44 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "cfghooks.h"
+#include "tree-pass.h"
+#include "memmodel.h"
+#include "tm_p.h"
 #include "stringpool.h"
+#include "expmed.h"
+#include "optabs.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "diagnostic.h"
+#include "fold-const.h"
 #include "stor-layout.h"
-#include "flags.h"
-#include "function.h"
+#include "explow.h"
+#include "stmt.h"
 #include "expr.h"
+#include "calls.h"
 #include "libfuncs.h"
-#include "insn-config.h"
 #include "except.h"
-#include "hard-reg-set.h"
 #include "output.h"
 #include "dwarf2asm.h"
 #include "dwarf2out.h"
-#include "dwarf2.h"
-#include "toplev.h"
-#include "hash-table.h"
-#include "intl.h"
-#include "tm_p.h"
-#include "target.h"
 #include "common/common-target.h"
 #include "langhooks.h"
-#include "cgraph.h"
-#include "diagnostic.h"
+#include "cfgrtl.h"
 #include "tree-pretty-print.h"
-#include "tree-pass.h"
-#include "pointer-set.h"
 #include "cfgloop.h"
 #include "builtins.h"
-
-/* Provide defaults for stuff that may not be defined when using
-   sjlj exceptions.  */
-#ifndef EH_RETURN_DATA_REGNO
-#define EH_RETURN_DATA_REGNO(N) INVALID_REGNUM
-#endif
+#include "tree-hash-traits.h"
 
 static GTY(()) int call_site_base;
-static GTY ((param_is (union tree_node)))
-  htab_t type_to_runtime_map;
+
+static GTY(()) hash_map<tree_hash, tree> *type_to_runtime_map;
+
+static GTY(()) tree setjmp_fn;
 
 /* Describe the SjLj_Function_Context structure.  */
 static GTY(()) tree sjlj_fc_type_node;
@@ -189,22 +187,21 @@ struct action_record
 
 /* Hashtable helpers.  */
 
-struct action_record_hasher : typed_free_remove <action_record>
+struct action_record_hasher : free_ptr_hash <action_record>
 {
-  typedef action_record value_type;
-  typedef action_record compare_type;
-  static inline hashval_t hash (const value_type *);
-  static inline bool equal (const value_type *, const compare_type *);
+  static inline hashval_t hash (const action_record *);
+  static inline bool equal (const action_record *, const action_record *);
 };
 
 inline hashval_t
-action_record_hasher::hash (const value_type *entry)
+action_record_hasher::hash (const action_record *entry)
 {
   return entry->next * 1009 + entry->filter;
 }
 
 inline bool
-action_record_hasher::equal (const value_type *entry, const compare_type *data)
+action_record_hasher::equal (const action_record *entry,
+                            const action_record *data)
 {
   return entry->filter == data->filter && entry->next == data->next;
 }
@@ -214,9 +211,6 @@ typedef hash_table<action_record_hasher> action_hash_type;
 static bool get_eh_region_and_lp_from_rtx (const_rtx, eh_region *,
                                           eh_landing_pad *);
 
-static int t2r_eq (const void *, const void *);
-static hashval_t t2r_hash (const void *);
-
 static void dw2_build_landing_pads (void);
 
 static int collect_one_action_chain (action_hash_type *, eh_region);
@@ -224,10 +218,8 @@ static int add_call_site (rtx, int, int);
 
 static void push_uleb128 (vec<uchar, va_gc> **, unsigned int);
 static void push_sleb128 (vec<uchar, va_gc> **, int);
-#ifndef HAVE_AS_LEB128
 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 (int, int);
 static void sjlj_output_call_site_table (void);
 
@@ -238,7 +230,7 @@ init_eh (void)
   if (! flag_exceptions)
     return;
 
-  type_to_runtime_map = htab_create_ggc (31, t2r_hash, t2r_eq, NULL);
+  type_to_runtime_map = hash_map<tree_hash, tree>::create_ggc (31);
 
   /* Create the SjLj_Function_Context structure.  This should match
      the definition in unwind-sjlj.c.  */
@@ -310,7 +302,7 @@ init_eh (void)
 #ifdef DONT_USE_BUILTIN_SETJMP
       /* We don't know what the alignment requirements of the
         runtime's jmp_buf has.  Overestimate.  */
-      DECL_ALIGN (f_jbuf) = BIGGEST_ALIGNMENT;
+      SET_DECL_ALIGN (f_jbuf, BIGGEST_ALIGNMENT);
       DECL_USER_ALIGN (f_jbuf) = 1;
 #endif
       DECL_FIELD_CONTEXT (f_jbuf) = sjlj_fc_type_node;
@@ -341,6 +333,16 @@ init_eh (void)
       sjlj_fc_jbuf_ofs
        = (tree_to_uhwi (DECL_FIELD_OFFSET (f_jbuf))
           + tree_to_uhwi (DECL_FIELD_BIT_OFFSET (f_jbuf)) / BITS_PER_UNIT);
+
+#ifdef DONT_USE_BUILTIN_SETJMP
+      tmp = build_function_type_list (integer_type_node, TREE_TYPE (f_jbuf),
+                                     NULL);
+      setjmp_fn = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
+                             get_identifier ("setjmp"), tmp);
+      TREE_PUBLIC (setjmp_fn) = 1;
+      DECL_EXTERNAL (setjmp_fn) = 1;
+      DECL_ASSEMBLER_NAME (setjmp_fn);
+#endif
     }
 }
 
@@ -527,7 +529,7 @@ struct duplicate_eh_regions_data
 {
   duplicate_eh_regions_map label_map;
   void *label_map_data;
-  struct pointer_map_t *eh_map;
+  hash_map<void *, void *> *eh_map;
 };
 
 static void
@@ -536,12 +538,9 @@ duplicate_eh_regions_1 (struct duplicate_eh_regions_data *data,
 {
   eh_landing_pad old_lp, new_lp;
   eh_region new_r;
-  void **slot;
 
   new_r = gen_eh_region (old_r->type, outer);
-  slot = pointer_map_insert (data->eh_map, (void *)old_r);
-  gcc_assert (*slot == NULL);
-  *slot = (void *)new_r;
+  gcc_assert (!data->eh_map->put (old_r, new_r));
 
   switch (old_r->type)
     {
@@ -586,9 +585,7 @@ duplicate_eh_regions_1 (struct duplicate_eh_regions_data *data,
        continue;
 
       new_lp = gen_eh_landing_pad (new_r);
-      slot = pointer_map_insert (data->eh_map, (void *)old_lp);
-      gcc_assert (*slot == NULL);
-      *slot = (void *)new_lp;
+      gcc_assert (!data->eh_map->put (old_lp, new_lp));
 
       new_lp->post_landing_pad
        = data->label_map (old_lp->post_landing_pad, data->label_map_data);
@@ -609,7 +606,7 @@ duplicate_eh_regions_1 (struct duplicate_eh_regions_data *data,
    that allows the caller to remap uses of both EH regions and
    EH landing pads.  */
 
-struct pointer_map_t *
+hash_map<void *, void *> *
 duplicate_eh_regions (struct function *ifun,
                      eh_region copy_region, int outer_lp,
                      duplicate_eh_regions_map map, void *map_data)
@@ -617,15 +614,14 @@ duplicate_eh_regions (struct function *ifun,
   struct duplicate_eh_regions_data data;
   eh_region outer_region;
 
-#ifdef ENABLE_CHECKING
-  verify_eh_tree (ifun);
-#endif
+  if (flag_checking)
+    verify_eh_tree (ifun);
 
   data.label_map = map;
   data.label_map_data = map_data;
-  data.eh_map = pointer_map_create ();
+  data.eh_map = new hash_map<void *, void *>;
 
-  outer_region = get_eh_region_from_lp_number (outer_lp);
+  outer_region = get_eh_region_from_lp_number_fn (cfun, outer_lp);
 
   /* Copy all the regions in the subtree.  */
   if (copy_region)
@@ -637,9 +633,8 @@ duplicate_eh_regions (struct function *ifun,
        duplicate_eh_regions_1 (&data, r, outer_region);
     }
 
-#ifdef ENABLE_CHECKING
-  verify_eh_tree (cfun);
-#endif
+  if (flag_checking)
+    verify_eh_tree (cfun);
 
   return data.eh_map;
 }
@@ -650,12 +645,10 @@ eh_region
 eh_region_outermost (struct function *ifun, eh_region region_a,
                     eh_region region_b)
 {
-  sbitmap b_outer;
-
   gcc_assert (ifun->eh->region_array);
   gcc_assert (ifun->eh->region_tree);
 
-  b_outer = sbitmap_alloc (ifun->eh->region_array->length ());
+  auto_sbitmap b_outer (ifun->eh->region_array->length ());
   bitmap_clear (b_outer);
 
   do
@@ -673,58 +666,31 @@ eh_region_outermost (struct function *ifun, eh_region region_a,
     }
   while (region_a);
 
-  sbitmap_free (b_outer);
   return region_a;
 }
 \f
-static int
-t2r_eq (const void *pentry, const void *pdata)
-{
-  const_tree const entry = (const_tree) pentry;
-  const_tree const data = (const_tree) pdata;
-
-  return TREE_PURPOSE (entry) == data;
-}
-
-static hashval_t
-t2r_hash (const void *pentry)
-{
-  const_tree const entry = (const_tree) pentry;
-  return TREE_HASH (TREE_PURPOSE (entry));
-}
-
 void
 add_type_for_runtime (tree type)
 {
-  tree *slot;
-
   /* If TYPE is NOP_EXPR, it means that it already is a runtime type.  */
   if (TREE_CODE (type) == NOP_EXPR)
     return;
 
-  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
-                                           TREE_HASH (type), INSERT);
-  if (*slot == NULL)
-    {
-      tree runtime = lang_hooks.eh_runtime_type (type);
-      *slot = tree_cons (type, runtime, NULL_TREE);
-    }
+  bool existed = false;
+  tree *slot = &type_to_runtime_map->get_or_insert (type, &existed);
+  if (!existed)
+    *slot = lang_hooks.eh_runtime_type (type);
 }
 
 tree
 lookup_type_for_runtime (tree type)
 {
-  tree *slot;
-
   /* If TYPE is NOP_EXPR, it means that it already is a runtime type.  */
   if (TREE_CODE (type) == NOP_EXPR)
     return type;
 
-  slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type,
-                                           TREE_HASH (type), NO_INSERT);
-
   /* We should have always inserted the data earlier.  */
-  return TREE_VALUE (*slot);
+  return *type_to_runtime_map->get (type);
 }
 
 \f
@@ -737,25 +703,24 @@ struct ttypes_filter {
 
 /* Helper for ttypes_filter hashing.  */
 
-struct ttypes_filter_hasher : typed_free_remove <ttypes_filter>
+struct ttypes_filter_hasher : free_ptr_hash <ttypes_filter>
 {
-  typedef ttypes_filter value_type;
-  typedef tree_node compare_type;
-  static inline hashval_t hash (const value_type *);
-  static inline bool equal (const value_type *, const compare_type *);
+  typedef tree_node *compare_type;
+  static inline hashval_t hash (const ttypes_filter *);
+  static inline bool equal (const ttypes_filter *, const tree_node *);
 };
 
 /* Compare ENTRY (a ttypes_filter entry in the hash table) with DATA
    (a tree) for a @TTypes type node we are thinking about adding.  */
 
 inline bool
-ttypes_filter_hasher::equal (const value_type *entry, const compare_type *data)
+ttypes_filter_hasher::equal (const ttypes_filter *entry, const tree_node *data)
 {
   return entry->t == data;
 }
 
 inline hashval_t
-ttypes_filter_hasher::hash (const value_type *entry)
+ttypes_filter_hasher::hash (const ttypes_filter *entry)
 {
   return TREE_HASH (entry->t);
 }
@@ -765,12 +730,10 @@ typedef hash_table<ttypes_filter_hasher> ttypes_hash_type;
 
 /* Helper for ehspec hashing.  */
 
-struct ehspec_hasher : typed_free_remove <ttypes_filter>
+struct ehspec_hasher : free_ptr_hash <ttypes_filter>
 {
-  typedef ttypes_filter value_type;
-  typedef ttypes_filter compare_type;
-  static inline hashval_t hash (const value_type *);
-  static inline bool equal (const value_type *, const compare_type *);
+  static inline hashval_t hash (const ttypes_filter *);
+  static inline bool equal (const ttypes_filter *, const ttypes_filter *);
 };
 
 /* Compare ENTRY with DATA (both struct ttypes_filter) for a @TTypes
@@ -779,7 +742,7 @@ struct ehspec_hasher : typed_free_remove <ttypes_filter>
    should put these in some canonical order.  */
 
 inline bool
-ehspec_hasher::equal (const value_type *entry, const compare_type *data)
+ehspec_hasher::equal (const ttypes_filter *entry, const ttypes_filter *data)
 {
   return type_list_equal (entry->t, data->t);
 }
@@ -787,7 +750,7 @@ ehspec_hasher::equal (const value_type *entry, const compare_type *data)
 /* Hash function for exception specification lists.  */
 
 inline hashval_t
-ehspec_hasher::hash (const value_type *entry)
+ehspec_hasher::hash (const ttypes_filter *entry)
 {
   hashval_t h = 0;
   tree list;
@@ -956,9 +919,9 @@ assign_filter_values (void)
    first instruction of some existing BB and return the newly
    produced block.  */
 static basic_block
-emit_to_new_bb_before (rtx seq, rtx insn)
+emit_to_new_bb_before (rtx_insn *seq, rtx_insn *insn)
 {
-  rtx last;
+  rtx_insn *next, *last;
   basic_block bb;
   edge e;
   edge_iterator ei;
@@ -971,7 +934,16 @@ emit_to_new_bb_before (rtx seq, rtx insn)
       force_nonfallthru (e);
     else
       ei_next (&ei);
-  last = emit_insn_before (seq, insn);
+
+  /* Make sure to put the location of INSN or a subsequent instruction on SEQ
+     to avoid inheriting the location of the previous instruction.  */
+  next = insn;
+  while (next && !NONDEBUG_INSN_P (next))
+    next = NEXT_INSN (next);
+  if (next)
+    last = emit_insn_before_setloc (seq, insn, INSN_LOCATION (next));
+  else
+    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);
@@ -984,19 +956,14 @@ emit_to_new_bb_before (rtx seq, rtx insn)
    at the rtl level.  Emit the code required by the target at a landing
    pad for the given region.  */
 
-void
+static void
 expand_dw2_landing_pad_for_region (eh_region region)
 {
-#ifdef HAVE_exception_receiver
-  if (HAVE_exception_receiver)
-    emit_insn (gen_exception_receiver ());
+  if (targetm.have_exception_receiver ())
+    emit_insn (targetm.gen_exception_receiver ());
+  else if (targetm.have_nonlocal_goto_receiver ())
+    emit_insn (targetm.gen_nonlocal_goto_receiver ());
   else
-#endif
-#ifdef HAVE_nonlocal_goto_receiver
-  if (HAVE_nonlocal_goto_receiver)
-    emit_insn (gen_nonlocal_goto_receiver ());
-  else
-#endif
     { /* Nothing */ }
 
   if (region->exc_ptr_reg)
@@ -1027,8 +994,7 @@ dw2_build_landing_pads (void)
   for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
     {
       basic_block bb;
-      rtx seq;
-      edge e;
+      rtx_insn *seq;
 
       if (lp == NULL || lp->post_landing_pad == NULL)
        continue;
@@ -1045,12 +1011,11 @@ dw2_build_landing_pads (void)
       end_sequence ();
 
       bb = emit_to_new_bb_before (seq, label_rtx (lp->post_landing_pad));
-      e = make_edge (bb, bb->next_bb, e_flags);
-      e->count = bb->count;
-      e->probability = REG_BR_PROB_BASE;
+      bb->count = bb->next_bb->count;
+      make_single_succ_edge (bb, bb->next_bb, e_flags);
       if (current_loops)
        {
-         struct loop *loop = bb->next_bb->loop_father;
+         class loop *loop = bb->next_bb->loop_father;
          /* If we created a pre-header block, add the new block to the
             outer loop, otherwise to the loop itself.  */
          if (bb->next_bb == loop->header)
@@ -1113,7 +1078,8 @@ static void
 sjlj_mark_call_sites (void)
 {
   int last_call_site = -2;
-  rtx insn, mem;
+  rtx_insn *insn;
+  rtx mem;
 
   for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
     {
@@ -1121,12 +1087,27 @@ sjlj_mark_call_sites (void)
       eh_region r;
       bool nothrow;
       int this_call_site;
-      rtx before, p;
+      rtx_insn *before, *p;
 
       /* Reset value tracking at extended basic block boundaries.  */
       if (LABEL_P (insn))
        last_call_site = -2;
 
+      /* If the function allocates dynamic stack space, the context must
+        be updated after every allocation/deallocation accordingly.  */
+      if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_UPDATE_SJLJ_CONTEXT)
+       {
+         rtx buf_addr;
+
+         start_sequence ();
+         buf_addr = plus_constant (Pmode, XEXP (crtl->eh.sjlj_fc, 0),
+                                   sjlj_fc_jbuf_ofs);
+         expand_builtin_update_setjmp_buf (buf_addr);
+         p = get_insns ();
+         end_sequence ();
+         emit_insn_before (p, insn);
+       }
+
       if (! INSN_P (insn))
        continue;
 
@@ -1157,7 +1138,7 @@ sjlj_mark_call_sites (void)
       /* Don't separate a call from it's argument loads.  */
       before = insn;
       if (CALL_P (insn))
-       before = find_first_parameter_load (insn, NULL_RTX);
+       before = find_first_parameter_load (insn, NULL);
 
       start_sequence ();
       mem = adjust_address (crtl->eh.sjlj_fc, TYPE_MODE (integer_type_node),
@@ -1174,9 +1155,10 @@ sjlj_mark_call_sites (void)
 /* Construct the SjLj_Function_Context.  */
 
 static void
-sjlj_emit_function_enter (rtx dispatch_label)
+sjlj_emit_function_enter (rtx_code_label *dispatch_label)
 {
-  rtx fn_begin, fc, mem, seq;
+  rtx_insn *fn_begin, *seq;
+  rtx fc, mem;
   bool fn_begin_outside_block;
   rtx personality = get_personality_function (current_function_decl);
 
@@ -1186,7 +1168,7 @@ sjlj_emit_function_enter (rtx dispatch_label)
 
   /* We're storing this libcall's address into memory instead of
      calling it directly.  Thus, we must call assemble_external_libcall
-     here, as we can not depend on emit_library_call to do it for us.  */
+     here, as we cannot depend on emit_library_call to do it for us.  */
   assemble_external_libcall (personality);
   mem = adjust_address (fc, Pmode, sjlj_fc_personality_ofs);
   emit_move_insn (mem, personality);
@@ -1207,25 +1189,27 @@ sjlj_emit_function_enter (rtx dispatch_label)
 
   if (dispatch_label)
     {
+      rtx addr = plus_constant (Pmode, XEXP (fc, 0), sjlj_fc_jbuf_ofs);
+
 #ifdef DONT_USE_BUILTIN_SETJMP
-      rtx x;
-      x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_RETURNS_TWICE,
-                                  TYPE_MODE (integer_type_node), 1,
-                                  plus_constant (Pmode, XEXP (fc, 0),
-                                                 sjlj_fc_jbuf_ofs), Pmode);
+      addr = copy_addr_to_reg (addr);
+      addr = convert_memory_address (ptr_mode, addr);
+      tree addr_tree = make_tree (ptr_type_node, addr);
+
+      tree call_expr = build_call_expr (setjmp_fn, 1, addr_tree);
+      rtx x = expand_call (call_expr, NULL_RTX, false);
 
       emit_cmp_and_jump_insns (x, const0_rtx, NE, 0,
                               TYPE_MODE (integer_type_node), 0,
-                              dispatch_label, REG_BR_PROB_BASE / 100);
+                              dispatch_label,
+                              profile_probability::unlikely ());
 #else
-      expand_builtin_setjmp_setup (plus_constant (Pmode, XEXP (fc, 0),
-                                                 sjlj_fc_jbuf_ofs),
-                                  dispatch_label);
+      expand_builtin_setjmp_setup (addr, dispatch_label);
 #endif
     }
 
   emit_library_call (unwind_sjlj_register_libfunc, LCT_NORMAL, VOIDmode,
-                    1, XEXP (fc, 0), Pmode);
+                    XEXP (fc, 0), Pmode);
 
   seq = get_insns ();
   end_sequence ();
@@ -1244,6 +1228,28 @@ sjlj_emit_function_enter (rtx dispatch_label)
          fn_begin_outside_block = false;
       }
 
+#ifdef DONT_USE_BUILTIN_SETJMP
+  if (dispatch_label)
+    {
+      /* The sequence contains a branch in the middle so we need to force
+        the creation of a new basic block by means of BB_SUPERBLOCK.  */
+      if (fn_begin_outside_block)
+       {
+         basic_block bb
+           = split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+         if (JUMP_P (BB_END (bb)))
+           emit_insn_before (seq, BB_END (bb));
+         else
+           emit_insn_after (seq, BB_END (bb));
+       }
+      else
+       emit_insn_after (seq, fn_begin);
+
+      single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))->flags |= BB_SUPERBLOCK;
+      return;
+    }
+#endif
+
   if (fn_begin_outside_block)
     insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
   else
@@ -1254,7 +1260,7 @@ sjlj_emit_function_enter (rtx dispatch_label)
    the call to unwind_sjlj_unregister_libfunc if needed.  */
 
 void
-sjlj_emit_function_exit_after (rtx after)
+sjlj_emit_function_exit_after (rtx_insn *after)
 {
   crtl->eh.sjlj_exit_after = after;
 }
@@ -1262,12 +1268,12 @@ sjlj_emit_function_exit_after (rtx after)
 static void
 sjlj_emit_function_exit (void)
 {
-  rtx seq, insn;
+  rtx_insn *seq, *insn;
 
   start_sequence ();
 
   emit_library_call (unwind_sjlj_unregister_libfunc, LCT_NORMAL, VOIDmode,
-                    1, XEXP (crtl->eh.sjlj_fc, 0), Pmode);
+                    XEXP (crtl->eh.sjlj_fc, 0), Pmode);
 
   seq = get_insns ();
   end_sequence ();
@@ -1284,16 +1290,15 @@ sjlj_emit_function_exit (void)
 }
 
 static void
-sjlj_emit_dispatch_table (rtx dispatch_label, int num_dispatch)
+sjlj_emit_dispatch_table (rtx_code_label *dispatch_label, int num_dispatch)
 {
-  enum machine_mode unwind_word_mode = targetm.unwind_word_mode ();
-  enum machine_mode filter_mode = targetm.eh_return_filter_mode ();
+  scalar_int_mode unwind_word_mode = targetm.unwind_word_mode ();
+  scalar_int_mode filter_mode = targetm.eh_return_filter_mode ();
   eh_landing_pad lp;
-  rtx mem, seq, fc, before, exc_ptr_reg, filter_reg;
-  rtx first_reachable_label;
+  rtx mem, fc, exc_ptr_reg, filter_reg;
+  rtx_insn *seq;
   basic_block bb;
   eh_region r;
-  edge e;
   int i, disp_index;
   vec<tree> dispatch_labels = vNULL;
 
@@ -1312,8 +1317,7 @@ sjlj_emit_dispatch_table (rtx dispatch_label, int num_dispatch)
      label on the nonlocal_goto_label list.  Since we're modeling these
      CFG edges more exactly, we can use the forced_labels list instead.  */
   LABEL_PRESERVE_P (dispatch_label) = 1;
-  forced_labels
-    = gen_rtx_EXPR_LIST (VOIDmode, dispatch_label, forced_labels);
+  vec_safe_push<rtx_insn *> (forced_labels, dispatch_label);
 #endif
 
   /* Load up exc_ptr and filter values from the function context.  */
@@ -1337,7 +1341,7 @@ sjlj_emit_dispatch_table (rtx dispatch_label, int num_dispatch)
   /* Jump to one of the directly reachable regions.  */
 
   disp_index = 0;
-  first_reachable_label = NULL;
+  rtx_code_label *first_reachable_label = NULL;
 
   /* If there's exactly one call site in the function, don't bother
      generating a switch statement.  */
@@ -1347,7 +1351,8 @@ sjlj_emit_dispatch_table (rtx dispatch_label, int num_dispatch)
   for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
     if (lp && lp->post_landing_pad)
       {
-       rtx seq2, label;
+       rtx_insn *seq2;
+       rtx_code_label *label;
 
        start_sequence ();
 
@@ -1361,7 +1366,7 @@ sjlj_emit_dispatch_table (rtx dispatch_label, int num_dispatch)
            t = build_int_cst (integer_type_node, disp_index);
            case_elt = build_case_label (t, NULL, t_label);
            dispatch_labels.quick_push (case_elt);
-           label = label_rtx (t_label);
+           label = jump_target_rtx (t_label);
          }
        else
          label = gen_label_rtx ();
@@ -1379,14 +1384,12 @@ sjlj_emit_dispatch_table (rtx dispatch_label, int num_dispatch)
        seq2 = get_insns ();
        end_sequence ();
 
-       before = label_rtx (lp->post_landing_pad);
+       rtx_insn *before = label_rtx (lp->post_landing_pad);
        bb = emit_to_new_bb_before (seq2, before);
-       e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-       e->count = bb->count;
-       e->probability = REG_BR_PROB_BASE;
+       make_single_succ_edge (bb, bb->next_bb, EDGE_FALLTHRU);
        if (current_loops)
          {
-           struct loop *loop = bb->next_bb->loop_father;
+           class loop *loop = bb->next_bb->loop_father;
            /* If we created a pre-header block, add the new block to the
               outer loop, otherwise to the loop itself.  */
            if (bb->next_bb == loop->header)
@@ -1400,10 +1403,7 @@ sjlj_emit_dispatch_table (rtx dispatch_label, int num_dispatch)
              {
                for (loop = bb->loop_father;
                     loop_outer (loop); loop = loop_outer (loop))
-                 {
-                   loop->header = NULL;
-                   loop->latch = NULL;
-                 }
+                 mark_loop_for_removal (loop);
              }
          }
 
@@ -1424,12 +1424,10 @@ sjlj_emit_dispatch_table (rtx dispatch_label, int num_dispatch)
   bb = emit_to_new_bb_before (seq, first_reachable_label);
   if (num_dispatch == 1)
     {
-      e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-      e->count = bb->count;
-      e->probability = REG_BR_PROB_BASE;
+      make_single_succ_edge (bb, bb->next_bb, EDGE_FALLTHRU);
       if (current_loops)
        {
-         struct loop *loop = bb->next_bb->loop_father;
+         class loop *loop = bb->next_bb->loop_father;
          /* If we created a pre-header block, add the new block to the
             outer loop, otherwise to the loop itself.  */
          if (bb->next_bb == loop->header)
@@ -1461,7 +1459,7 @@ sjlj_build_landing_pads (void)
   num_dispatch = sjlj_assign_call_site_values ();
   if (num_dispatch > 0)
     {
-      rtx dispatch_label = gen_label_rtx ();
+      rtx_code_label *dispatch_label = gen_label_rtx ();
       int align = STACK_SLOT_ALIGNMENT (sjlj_fc_type_node,
                                        TYPE_MODE (sjlj_fc_type_node),
                                        TYPE_ALIGN (sjlj_fc_type_node));
@@ -1489,13 +1487,25 @@ sjlj_build_landing_pads (void)
                              align);
 
       sjlj_mark_call_sites ();
-      sjlj_emit_function_enter (NULL_RTX);
+      sjlj_emit_function_enter (NULL);
       sjlj_emit_function_exit ();
     }
 
   sjlj_lp_call_site_index.release ();
 }
 
+/* Update the sjlj function context.  This function should be called
+   whenever we allocate or deallocate dynamic stack space.  */
+
+void
+update_sjlj_context (void)
+{
+  if (!flag_exceptions)
+    return;
+
+  emit_note (NOTE_INSN_UPDATE_SJLJ_CONTEXT);
+}
+
 /* After initial rtl generation, call back to finish generating
    exception support code.  */
 
@@ -1509,12 +1519,8 @@ finish_eh_generation (void)
     sjlj_build_landing_pads ();
   else
     dw2_build_landing_pads ();
-  break_superblocks ();
 
-  if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ
-      /* Kludge for Alpha (see alpha_gp_save_rtx).  */
-      || single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))->insns.r)
-    commit_edge_insertions ();
+  break_superblocks ();
 
   /* Redirect all EH edges from the post_landing_pad to the landing pad.  */
   FOR_EACH_BB_FN (bb, cfun)
@@ -1545,6 +1551,11 @@ finish_eh_generation (void)
                       : EDGE_ABNORMAL);
        }
     }
+
+  if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ
+      /* Kludge for Alpha (see alpha_gp_save_rtx).  */
+      || single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))->insns.r)
+    commit_edge_insertions ();
 }
 \f
 /* This section handles removing dead code for flow.  */
@@ -1663,7 +1674,7 @@ for_each_eh_label (void (*callback) (rtx))
     {
       if (lp)
        {
-         rtx lab = lp->landing_pad;
+         rtx_code_label *lab = lp->landing_pad;
          if (lab && LABEL_P (lab))
            (*callback) (lab);
        }
@@ -1695,7 +1706,7 @@ for_each_eh_label (void (*callback) (rtx))
   direct call cases) and just pull the data out of the trees.  */
 
 void
-make_reg_eh_region_note (rtx insn, int ecf_flags, int lp_nr)
+make_reg_eh_region_note (rtx_insn *insn, int ecf_flags, int lp_nr)
 {
   rtx value;
   if (ecf_flags & ECF_NOTHROW)
@@ -1712,7 +1723,7 @@ make_reg_eh_region_note (rtx insn, int ecf_flags, int lp_nr)
    already exists.  */
 
 void
-make_reg_eh_region_note_nothrow_nononlocal (rtx insn)
+make_reg_eh_region_note_nothrow_nononlocal (rtx_insn *insn)
 {
   rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
   rtx intmin = GEN_INT (INT_MIN);
@@ -1743,9 +1754,10 @@ insn_could_throw_p (const_rtx insn)
    to look for a note, or the note itself.  */
 
 void
-copy_reg_eh_region_note_forward (rtx note_or_insn, rtx first, rtx last)
+copy_reg_eh_region_note_forward (rtx note_or_insn, rtx_insn *first, rtx last)
 {
-  rtx insn, note = note_or_insn;
+  rtx_insn *insn;
+  rtx note = note_or_insn;
 
   if (INSN_P (note_or_insn))
     {
@@ -1753,6 +1765,8 @@ copy_reg_eh_region_note_forward (rtx note_or_insn, rtx first, rtx last)
       if (note == NULL)
        return;
     }
+  else if (is_a <rtx_insn *> (note_or_insn))
+    return;
   note = XEXP (note, 0);
 
   for (insn = first; insn != last ; insn = NEXT_INSN (insn))
@@ -1764,9 +1778,10 @@ copy_reg_eh_region_note_forward (rtx note_or_insn, rtx first, rtx last)
 /* Likewise, but iterate backward.  */
 
 void
-copy_reg_eh_region_note_backward (rtx note_or_insn, rtx last, rtx first)
+copy_reg_eh_region_note_backward (rtx note_or_insn, rtx_insn *last, rtx first)
 {
-  rtx insn, note = note_or_insn;
+  rtx_insn *insn;
+  rtx note = note_or_insn;
 
   if (INSN_P (note_or_insn))
     {
@@ -1774,6 +1789,8 @@ copy_reg_eh_region_note_backward (rtx note_or_insn, rtx last, rtx first)
       if (note == NULL)
        return;
     }
+  else if (is_a <rtx_insn *> (note_or_insn))
+    return;
   note = XEXP (note, 0);
 
   for (insn = last; insn != first; insn = PREV_INSN (insn))
@@ -1879,11 +1896,11 @@ can_throw_external (const_rtx insn)
   if (NONJUMP_INSN_P (insn)
       && GET_CODE (PATTERN (insn)) == SEQUENCE)
     {
-      rtx seq = PATTERN (insn);
-      int i, n = XVECLEN (seq, 0);
+      rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (insn));
+      int i, n = seq->len ();
 
       for (i = 0; i < n; i++)
-       if (can_throw_external (XVECEXP (seq, 0, i)))
+       if (can_throw_external (seq->element (i)))
          return true;
 
       return false;
@@ -1923,11 +1940,11 @@ insn_nothrow_p (const_rtx insn)
   if (NONJUMP_INSN_P (insn)
       && GET_CODE (PATTERN (insn)) == SEQUENCE)
     {
-      rtx seq = PATTERN (insn);
-      int i, n = XVECLEN (seq, 0);
+      rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (insn));
+      int i, n = seq->len ();
 
       for (i = 0; i < n; i++)
-       if (!insn_nothrow_p (XVECEXP (seq, 0, i)))
+       if (!insn_nothrow_p (seq->element (i)))
          return false;
 
       return true;
@@ -1940,7 +1957,7 @@ insn_nothrow_p (const_rtx insn)
 /* ??? This test is here in this file because it (ab)uses REG_EH_REGION.  */
 
 bool
-can_nonlocal_goto (const_rtx insn)
+can_nonlocal_goto (const rtx_insn *insn)
 {
   if (nonlocal_goto_handler_labels && CALL_P (insn))
     {
@@ -1956,7 +1973,7 @@ can_nonlocal_goto (const_rtx insn)
 static unsigned int
 set_nothrow_function_flags (void)
 {
-  rtx insn;
+  rtx_insn *insn;
 
   crtl->nothrow = 1;
 
@@ -2102,7 +2119,7 @@ expand_builtin_eh_copy_values (tree exp)
     = expand_builtin_eh_common (CALL_EXPR_ARG (exp, 0));
   eh_region src
     = expand_builtin_eh_common (CALL_EXPR_ARG (exp, 1));
-  enum machine_mode fmode = targetm.eh_return_filter_mode ();
+  scalar_int_mode fmode = targetm.eh_return_filter_mode ();
 
   if (dst->exc_ptr_reg == NULL)
     dst->exc_ptr_reg = gen_reg_rtx (ptr_mode);
@@ -2130,9 +2147,7 @@ expand_builtin_unwind_init (void)
      able to copy the saved values for any registers from frames we unwind.  */
   crtl->saves_all_registers = 1;
 
-#ifdef SETUP_FRAME_ADDRESSES
   SETUP_FRAME_ADDRESSES ();
-#endif
 }
 
 /* Map a non-negative number to an eh return data register number; expands
@@ -2184,14 +2199,13 @@ expand_builtin_extract_return_addr (tree addr_tree)
     }
 
   /* First mask out any unwanted bits.  */
-#ifdef MASK_RETURN_ADDR
-  expand_and (Pmode, addr, MASK_RETURN_ADDR, addr);
-#endif
+  rtx mask = MASK_RETURN_ADDR;
+  if (mask)
+    expand_and (Pmode, addr, mask, addr);
 
   /* Then adjust to find the real return address.  */
-#if defined (RETURN_ADDR_OFFSET)
-  addr = plus_constant (Pmode, addr, RETURN_ADDR_OFFSET);
-#endif
+  if (RETURN_ADDR_OFFSET)
+    addr = plus_constant (Pmode, addr, RETURN_ADDR_OFFSET);
 
   return addr;
 }
@@ -2207,10 +2221,11 @@ expand_builtin_frob_return_addr (tree addr_tree)
 
   addr = convert_memory_address (Pmode, addr);
 
-#ifdef RETURN_ADDR_OFFSET
-  addr = force_reg (Pmode, addr);
-  addr = plus_constant (Pmode, addr, -RETURN_ADDR_OFFSET);
-#endif
+  if (RETURN_ADDR_OFFSET)
+    {
+      addr = force_reg (Pmode, addr);
+      addr = plus_constant (Pmode, addr, -RETURN_ADDR_OFFSET);
+    }
 
   return addr;
 }
@@ -2229,7 +2244,7 @@ expand_builtin_eh_return (tree stackadj_tree ATTRIBUTE_UNUSED,
                     VOIDmode, EXPAND_NORMAL);
   tmp = convert_memory_address (Pmode, tmp);
   if (!crtl->eh.ehr_stackadj)
-    crtl->eh.ehr_stackadj = copy_to_reg (tmp);
+    crtl->eh.ehr_stackadj = copy_addr_to_reg (tmp);
   else if (tmp != crtl->eh.ehr_stackadj)
     emit_move_insn (crtl->eh.ehr_stackadj, tmp);
 #endif
@@ -2238,7 +2253,7 @@ expand_builtin_eh_return (tree stackadj_tree ATTRIBUTE_UNUSED,
                     VOIDmode, EXPAND_NORMAL);
   tmp = convert_memory_address (Pmode, tmp);
   if (!crtl->eh.ehr_handler)
-    crtl->eh.ehr_handler = copy_to_reg (tmp);
+    crtl->eh.ehr_handler = copy_addr_to_reg (tmp);
   else if (tmp != crtl->eh.ehr_handler)
     emit_move_insn (crtl->eh.ehr_handler, tmp);
 
@@ -2254,7 +2269,7 @@ expand_builtin_eh_return (tree stackadj_tree ATTRIBUTE_UNUSED,
 void
 expand_eh_return (void)
 {
-  rtx around_label;
+  rtx_code_label *around_label;
 
   if (! crtl->eh.ehr_label)
     return;
@@ -2275,17 +2290,14 @@ expand_eh_return (void)
   emit_move_insn (EH_RETURN_STACKADJ_RTX, crtl->eh.ehr_stackadj);
 #endif
 
-#ifdef HAVE_eh_return
-  if (HAVE_eh_return)
-    emit_insn (gen_eh_return (crtl->eh.ehr_handler));
+  if (targetm.have_eh_return ())
+    emit_insn (targetm.gen_eh_return (crtl->eh.ehr_handler));
   else
-#endif
     {
-#ifdef EH_RETURN_HANDLER_RTX
-      emit_move_insn (EH_RETURN_HANDLER_RTX, crtl->eh.ehr_handler);
-#else
-      error ("__builtin_eh_return not supported on this target");
-#endif
+      if (rtx handler = EH_RETURN_HANDLER_RTX)
+       emit_move_insn (handler, crtl->eh.ehr_handler);
+      else
+       error ("%<__builtin_eh_return%> not supported on this target");
     }
 
   emit_label (around_label);
@@ -2464,18 +2476,65 @@ add_call_site (rtx landing_pad, int action, int section)
   return call_site_base + crtl->eh.call_site_record_v[section]->length () - 1;
 }
 
-static rtx
-emit_note_eh_region_end (rtx insn)
+static rtx_note *
+emit_note_eh_region_end (rtx_insn *insn)
 {
-  rtx next = NEXT_INSN (insn);
+  return emit_note_after (NOTE_INSN_EH_REGION_END, insn);
+}
 
-  /* Make sure we do not split a call and its corresponding
-     CALL_ARG_LOCATION note.  */
-  if (next && NOTE_P (next)
-      && NOTE_KIND (next) == NOTE_INSN_CALL_ARG_LOCATION)
-    insn = next;
+/* Add NOP after NOTE_INSN_SWITCH_TEXT_SECTIONS when the cold section starts
+   with landing pad.
+   With landing pad being at offset 0 from the start label of the section
+   we would miss EH delivery because 0 is special and means no landing pad.  */
 
-  return emit_note_after (NOTE_INSN_EH_REGION_END, insn);
+static bool
+maybe_add_nop_after_section_switch (void)
+{
+  if (!crtl->uses_eh_lsda
+      || !crtl->eh.call_site_record_v[1])
+    return false;
+  int n = vec_safe_length (crtl->eh.call_site_record_v[1]);
+  hash_set<rtx_insn *> visited;
+
+  for (int i = 0; i < n; ++i)
+    {
+      struct call_site_record_d *cs
+        = (*crtl->eh.call_site_record_v[1])[i];
+      if (cs->landing_pad)
+       {
+         rtx_insn *insn = as_a <rtx_insn *> (cs->landing_pad);
+         while (true)
+           {
+             /* Landing pads have LABEL_PRESERVE_P flag set.  This check make
+                sure that we do not walk past landing pad visited earlier
+                which would result in possible quadratic behaviour.  */
+             if (LABEL_P (insn) && LABEL_PRESERVE_P (insn)
+                 && visited.add (insn))
+               break;
+
+             /* Conservatively assume that ASM insn may be empty.  We have
+                now way to tell what they contain.  */
+             if (active_insn_p (insn)
+                 && GET_CODE (PATTERN (insn)) != ASM_INPUT
+                 && GET_CODE (PATTERN (insn)) != ASM_OPERANDS)
+               break;
+
+             /* If we reached the start of hot section, then NOP will be
+                needed.  */
+             if (GET_CODE (insn) == NOTE
+                 && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
+               {
+                 emit_insn_after (gen_nop (), insn);
+                 break;
+               }
+
+             /* We visit only labels from cold section.  We should never hit
+                begining of the insn stream here.  */
+             insn = PREV_INSN (insn);
+           }
+       }
+    }
+  return false;
 }
 
 /* Turn REG_EH_REGION notes back into NOTE_INSN_EH_REGION notes.
@@ -2485,17 +2544,19 @@ emit_note_eh_region_end (rtx insn)
 static unsigned int
 convert_to_eh_region_ranges (void)
 {
-  rtx insn, iter, note;
+  rtx insn;
+  rtx_insn *iter;
+  rtx_note *note;
   action_hash_type ar_hash (31);
   int last_action = -3;
-  rtx last_action_insn = NULL_RTX;
+  rtx_insn *last_action_insn = NULL;
   rtx last_landing_pad = NULL_RTX;
-  rtx first_no_action_insn = NULL_RTX;
+  rtx_insn *first_no_action_insn = NULL;
   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_insn *section_switch_note = NULL;
+  rtx_insn *first_no_action_insn_before_switch = NULL;
+  rtx_insn *last_no_action_insn_before_switch = NULL;
   int saved_call_site_base = call_site_base;
 
   vec_alloc (crtl->eh.action_record_data, 64);
@@ -2507,7 +2568,7 @@ convert_to_eh_region_ranges (void)
        eh_region region;
        bool nothrow;
        int this_action;
-       rtx this_landing_pad;
+       rtx_code_label *this_landing_pad;
 
        insn = iter;
        if (NONJUMP_INSN_P (insn)
@@ -2538,7 +2599,7 @@ convert_to_eh_region_ranges (void)
        if (this_action >= 0)
          this_landing_pad = lp->landing_pad;
        else
-         this_landing_pad = NULL_RTX;
+         this_landing_pad = NULL;
 
        /* Differing actions or landing pads implies a change in call-site
           info, which implies some EH_REGION note should be emitted.  */
@@ -2562,8 +2623,8 @@ convert_to_eh_region_ranges (void)
                gcc_assert (last_action != -3
                            || (last_action_insn
                                == last_no_action_insn_before_switch));
-               first_no_action_insn_before_switch = NULL_RTX;
-               last_no_action_insn_before_switch = NULL_RTX;
+               first_no_action_insn_before_switch = NULL;
+               last_no_action_insn_before_switch = NULL;
                call_site_base++;
              }
            /* If we'd not seen a previous action (-3) or the previous
@@ -2578,7 +2639,7 @@ convert_to_eh_region_ranges (void)
                    note = emit_note_before (NOTE_INSN_EH_REGION_BEG,
                                             first_no_action_insn);
                    NOTE_EH_HANDLER (note) = call_site;
-                   first_no_action_insn = NULL_RTX;
+                   first_no_action_insn = NULL;
                  }
 
                note = emit_note_eh_region_end (last_action_insn);
@@ -2611,7 +2672,7 @@ convert_to_eh_region_ranges (void)
          {
            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;
+           first_no_action_insn = NULL;
            gcc_assert (last_action == -1);
            last_action = -3;
          }
@@ -2663,7 +2724,9 @@ public:
   virtual bool gate (function *);
   virtual unsigned int execute (function *)
     {
-      return convert_to_eh_region_ranges ();
+      int ret = convert_to_eh_region_ranges ();
+      maybe_add_nop_after_section_switch ();
+      return ret;
     }
 
 }; // class pass_convert_to_eh_region_ranges
@@ -2721,7 +2784,6 @@ push_sleb128 (vec<uchar, va_gc> **data_area, int value)
 }
 
 \f
-#ifndef HAVE_AS_LEB128
 static int
 dw2_size_of_call_site_table (int section)
 {
@@ -2756,7 +2818,6 @@ sjlj_size_of_call_site_table (void)
 
   return size;
 }
-#endif
 
 static void
 dw2_output_call_site_table (int cs_format, int section)
@@ -2848,24 +2909,24 @@ switch_to_exception_section (const char * ARG_UNUSED (fnname))
     s = exception_section;
   else
     {
+      int flags;
+
+      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;
+
       /* Compute the section and cache it into exception_section,
         unless it depends on the function name.  */
       if (targetm_common.have_named_sections)
        {
-         int flags;
-
-         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;
-
 #ifdef HAVE_LD_EH_GC_SECTIONS
          if (flag_function_sections
              || (DECL_COMDAT_GROUP (current_function_decl) && HAVE_COMDAT_GROUP))
@@ -2886,13 +2947,12 @@ switch_to_exception_section (const char * ARG_UNUSED (fnname))
        }
       else
        exception_section
-         = s = flag_pic ? data_section : readonly_data_section;
+         = s = flags == SECTION_WRITE ? data_section : readonly_data_section;
     }
 
   switch_to_section (s);
 }
 
-
 /* Output a reference from an exception table to the type_info object TYPE.
    TT_FORMAT and TT_FORMAT_SIZE describe the DWARF encoding method used for
    the value.  */
@@ -2924,7 +2984,7 @@ output_ttype (tree type, int tt_format, int tt_format_size)
       if (TREE_CODE (type) == ADDR_EXPR)
        {
          type = TREE_OPERAND (type, 0);
-         if (TREE_CODE (type) == VAR_DECL)
+         if (VAR_P (type))
            is_public = TREE_PUBLIC (type);
        }
       else
@@ -2942,17 +3002,21 @@ output_ttype (tree type, int tt_format, int tt_format_size)
     dw2_asm_output_encoded_addr_rtx (tt_format, value, is_public, NULL);
 }
 
+/* Output an exception table for the current function according to SECTION.
+
+   If the function has been partitioned into hot and cold parts, value 0 for
+   SECTION refers to the table associated with the hot part while value 1
+   refers to the table associated with the cold part.  If the function has
+   not been partitioned, value 0 refers to the single exception table.  */
 static void
 output_one_function_exception_table (int section)
 {
   int tt_format, cs_format, lp_format, i;
-#ifdef HAVE_AS_LEB128
   char ttype_label[32];
   char cs_after_size_label[32];
   char cs_end_label[32];
-#else
   int call_site_len;
-#endif
   int have_tt_data;
   int tt_format_size = 0;
 
@@ -2967,11 +3031,11 @@ output_one_function_exception_table (int section)
   else
     {
       tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
-#ifdef HAVE_AS_LEB128
-      ASM_GENERATE_INTERNAL_LABEL (ttype_label,
-                                  section ? "LLSDATTC" : "LLSDATT",
-                                  current_function_funcdef_no);
-#endif
+      if (HAVE_AS_LEB128)
+       ASM_GENERATE_INTERNAL_LABEL (ttype_label,
+                                    section ? "LLSDATTC" : "LLSDATT",
+                                    current_function_funcdef_no);
+
       tt_format_size = size_of_encoded_value (tt_format);
 
       assemble_align (tt_format_size * BITS_PER_UNIT);
@@ -2997,86 +3061,93 @@ output_one_function_exception_table (int section)
   dw2_asm_output_data (1, tt_format, "@TType format (%s)",
                       eh_data_format_name (tt_format));
 
-#ifndef HAVE_AS_LEB128
-  if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
-    call_site_len = sjlj_size_of_call_site_table ();
-  else
-    call_site_len = dw2_size_of_call_site_table (section);
-#endif
+  if (!HAVE_AS_LEB128)
+    {
+      if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
+       call_site_len = sjlj_size_of_call_site_table ();
+      else
+       call_site_len = dw2_size_of_call_site_table (section);
+    }
 
   /* A pc-relative 4-byte displacement to the @TType data.  */
   if (have_tt_data)
     {
-#ifdef HAVE_AS_LEB128
-      char ttype_after_disp_label[32];
-      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");
-      ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label);
-#else
-      /* Ug.  Alignment queers things.  */
-      unsigned int before_disp, after_disp, last_disp, disp;
+      if (HAVE_AS_LEB128)
+       {
+         char ttype_after_disp_label[32];
+         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");
+         ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label);
+       }
+      else
+       {
+         /* Ug.  Alignment queers things.  */
+         unsigned int before_disp, after_disp, last_disp, disp;
 
-      before_disp = 1 + 1;
-      after_disp = (1 + size_of_uleb128 (call_site_len)
-                   + call_site_len
-                   + vec_safe_length (crtl->eh.action_record_data)
-                   + (vec_safe_length (cfun->eh->ttype_data)
-                      * tt_format_size));
+         before_disp = 1 + 1;
+         after_disp = (1 + size_of_uleb128 (call_site_len)
+                       + call_site_len
+                       + vec_safe_length (crtl->eh.action_record_data)
+                       + (vec_safe_length (cfun->eh->ttype_data)
+                          * tt_format_size));
 
-      disp = after_disp;
-      do
-       {
-         unsigned int disp_size, pad;
+         disp = after_disp;
+         do
+           {
+             unsigned int disp_size, pad;
 
-         last_disp = disp;
-         disp_size = size_of_uleb128 (disp);
-         pad = before_disp + disp_size + after_disp;
-         if (pad % tt_format_size)
-           pad = tt_format_size - (pad % tt_format_size);
-         else
-           pad = 0;
-         disp = after_disp + pad;
-       }
-      while (disp != last_disp);
+             last_disp = disp;
+             disp_size = size_of_uleb128 (disp);
+             pad = before_disp + disp_size + after_disp;
+             if (pad % tt_format_size)
+               pad = tt_format_size - (pad % tt_format_size);
+             else
+               pad = 0;
+             disp = after_disp + pad;
+           }
+         while (disp != last_disp);
 
-      dw2_asm_output_data_uleb128 (disp, "@TType base offset");
-#endif
-    }
+         dw2_asm_output_data_uleb128 (disp, "@TType base offset");
+       }
+       }
 
   /* Indicate the format of the call-site offsets.  */
-#ifdef HAVE_AS_LEB128
-  cs_format = DW_EH_PE_uleb128;
-#else
-  cs_format = DW_EH_PE_udata4;
-#endif
+  if (HAVE_AS_LEB128)
+    cs_format = DW_EH_PE_uleb128;
+  else
+    cs_format = DW_EH_PE_udata4;
+
   dw2_asm_output_data (1, cs_format, "call-site format (%s)",
                       eh_data_format_name (cs_format));
 
-#ifdef HAVE_AS_LEB128
-  ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label,
-                              section ? "LLSDACSBC" : "LLSDACSB",
-                              current_function_funcdef_no);
-  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");
-  ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label);
-  if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
-    sjlj_output_call_site_table ();
-  else
-    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");
-  if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
-    sjlj_output_call_site_table ();
+  if (HAVE_AS_LEB128)
+    {
+      ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label,
+                                  section ? "LLSDACSBC" : "LLSDACSB",
+                                  current_function_funcdef_no);
+      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");
+      ASM_OUTPUT_LABEL (asm_out_file, cs_after_size_label);
+      if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
+       sjlj_output_call_site_table ();
+      else
+       dw2_output_call_site_table (cs_format, section);
+      ASM_OUTPUT_LABEL (asm_out_file, cs_end_label);
+    }
   else
-    dw2_output_call_site_table (cs_format, section);
-#endif
+    {
+      dw2_asm_output_data_uleb128 (call_site_len, "Call-site table length");
+      if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
+       sjlj_output_call_site_table ();
+      else
+       dw2_output_call_site_table (cs_format, section);
+    }
 
   /* ??? Decode and interpret the data for flag_debug_asm.  */
   {
@@ -3095,10 +3166,8 @@ output_one_function_exception_table (int section)
       output_ttype (type, tt_format, tt_format_size);
     }
 
-#ifdef HAVE_AS_LEB128
-  if (have_tt_data)
-      ASM_OUTPUT_LABEL (asm_out_file, ttype_label);
-#endif
+  if (HAVE_AS_LEB128 && have_tt_data)
+    ASM_OUTPUT_LABEL (asm_out_file, ttype_label);
 
   /* ??? Decode and interpret the data for flag_debug_asm.  */
   if (targetm.arm_eabi_unwinder)
@@ -3118,13 +3187,27 @@ output_one_function_exception_table (int section)
     }
 }
 
+/* Output an exception table for the current function according to SECTION,
+   switching back and forth from the function section appropriately.
+
+   If the function has been partitioned into hot and cold parts, value 0 for
+   SECTION refers to the table associated with the hot part while value 1
+   refers to the table associated with the cold part.  If the function has
+   not been partitioned, value 0 refers to the single exception table.  */
+
 void
-output_function_exception_table (const char *fnname)
+output_function_exception_table (int section)
 {
+  const char *fnname = get_fnname_from_decl (current_function_decl);
   rtx personality = get_personality_function (current_function_decl);
 
   /* Not all functions need anything.  */
-  if (! crtl->uses_eh_lsda)
+  if (!crtl->uses_eh_lsda
+      || targetm_common.except_unwind_info (&global_options) == UI_NONE)
+    return;
+
+  /* No need to emit any boilerplate stuff for the cold part.  */
+  if (section == 1 && !crtl->eh.call_site_record_v[1])
     return;
 
   if (personality)
@@ -3140,20 +3223,19 @@ output_function_exception_table (const char *fnname)
   /* If the target wants a label to begin the table, emit it here.  */
   targetm.asm_out.emit_except_table_label (asm_out_file);
 
-  output_one_function_exception_table (0);
-  if (crtl->eh.call_site_record_v[1])
-    output_one_function_exception_table (1);
+  /* Do the real work.  */
+  output_one_function_exception_table (section);
 
   switch_to_section (current_function_section ());
 }
 
 void
-set_eh_throw_stmt_table (struct function *fun, struct htab *table)
+set_eh_throw_stmt_table (function *fun, hash_map<gimple *, int> *table)
 {
   fun->eh->throw_stmt_table = table;
 }
 
-htab_t
+hash_map<gimple *, int> *
 get_eh_throw_stmt_table (struct function *fun)
 {
   return fun->eh->throw_stmt_table;
@@ -3223,7 +3305,7 @@ dump_eh_tree (FILE * out, struct function *fun)
              for (lp = i->landing_pads; lp ; lp = lp->next_lp)
                {
                  fprintf (out, "{%i,", lp->index);
-                 print_generic_expr (out, lp->post_landing_pad, 0);
+                 print_generic_expr (out, lp->post_landing_pad);
                  fputc ('}', out);
                  if (lp->next_lp)
                    fputc (',', out);
@@ -3241,7 +3323,7 @@ dump_eh_tree (FILE * out, struct function *fun)
                    fprintf (out, "(nil),");
                  if (lp->post_landing_pad)
                    {
-                     rtx lab = label_rtx (lp->post_landing_pad);
+                     rtx_insn *lab = label_rtx (lp->post_landing_pad);
                      fprintf (out, "%i%s}", INSN_UID (lab),
                               NOTE_P (lab) ? "(del)" : "");
                    }
@@ -3269,10 +3351,10 @@ dump_eh_tree (FILE * out, struct function *fun)
                if (c->label)
                  {
                    fprintf (out, "lab:");
-                   print_generic_expr (out, c->label, 0);
+                   print_generic_expr (out, c->label);
                    fputc (';', out);
                  }
-               print_generic_expr (out, c->type_list, 0);
+               print_generic_expr (out, c->type_list);
                fputc ('}', out);
                if (c->next_catch)
                  fputc (',', out);
@@ -3282,7 +3364,7 @@ dump_eh_tree (FILE * out, struct function *fun)
 
        case ERT_ALLOWED_EXCEPTIONS:
          fprintf (out, " filter :%i types:", i->u.allowed.filter);
-         print_generic_expr (out, i->u.allowed.type_list, 0);
+         print_generic_expr (out, i->u.allowed.type_list);
          break;
        }
       fputc ('\n', out);
@@ -3339,7 +3421,7 @@ verify_eh_tree (struct function *fun)
          count_r++;
        else
          {
-           error ("region_array is corrupted for region %i", r->index);
+           error ("%<region_array%> is corrupted for region %i", r->index);
            err = true;
          }
       }
@@ -3352,7 +3434,7 @@ verify_eh_tree (struct function *fun)
          count_lp++;
        else
          {
-           error ("lp_array is corrupted for lp %i", lp->index);
+           error ("%<lp_array%> is corrupted for lp %i", lp->index);
            err = true;
          }
       }
@@ -3364,7 +3446,7 @@ verify_eh_tree (struct function *fun)
     {
       if ((*fun->eh->region_array)[r->index] != r)
        {
-         error ("region_array is corrupted for region %i", r->index);
+         error ("%<region_array%> is corrupted for region %i", r->index);
          err = true;
        }
       if (r->outer != outer)
@@ -3383,7 +3465,7 @@ verify_eh_tree (struct function *fun)
        {
          if ((*fun->eh->lp_array)[lp->index] != lp)
            {
-             error ("lp_array is corrupted for lp %i", lp->index);
+             error ("%<lp_array%> is corrupted for lp %i", lp->index);
              err = true;
            }
          if (lp->region != r)
@@ -3420,19 +3502,19 @@ verify_eh_tree (struct function *fun)
     }
   if (count_r != nvisited_r)
     {
-      error ("region_array does not match region_tree");
+      error ("%<region_array%> does not match %<region_tree%>");
       err = true;
     }
   if (count_lp != nvisited_lp)
     {
-      error ("lp_array does not match region_tree");
+      error ("%<lp_array%> does not match %<region_tree%>");
       err = true;
     }
 
   if (err)
     {
       dump_eh_tree (stderr, fun);
-      internal_error ("verify_eh_tree failed");
+      internal_error ("%qs failed", __func__);
     }
 }
 \f