re PR target/65697 (__atomic memory barriers not strong enough for __sync builtins)
[gcc.git] / gcc / function.c
index 1ef43c4dea7d4913eb7b9ba0bd7cf916f31cf992..4389bbd1aba6ef60bff632370c54cfdda26c05ee 100644 (file)
@@ -1,5 +1,5 @@
 /* Expands front end tree to back end RTL for GCC.
-   Copyright (C) 1987-2014 Free Software Foundation, Inc.
+   Copyright (C) 1987-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -36,24 +36,30 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "rtl-error.h"
+#include "alias.h"
+#include "symtab.h"
 #include "tree.h"
+#include "fold-const.h"
 #include "stor-layout.h"
 #include "varasm.h"
 #include "stringpool.h"
 #include "flags.h"
 #include "except.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "machmode.h"
 #include "hard-reg-set.h"
-#include "input.h"
 #include "function.h"
+#include "rtl.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
 #include "expr.h"
+#include "insn-codes.h"
 #include "optabs.h"
 #include "libfuncs.h"
 #include "regs.h"
-#include "insn-config.h"
 #include "recog.h"
 #include "output.h"
 #include "tm_p.h"
@@ -77,6 +83,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "shrink-wrap.h"
 #include "toplev.h"
 #include "rtl-iter.h"
+#include "tree-chkp.h"
+#include "rtl-chkp.h"
 
 /* So we can assign to cfun in this file.  */
 #undef cfun
@@ -113,10 +121,17 @@ struct machine_function * (*init_machine_status) (void);
 struct function *cfun = 0;
 
 /* These hashes record the prologue and epilogue insns.  */
-static GTY((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
-  htab_t prologue_insn_hash;
-static GTY((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
-  htab_t epilogue_insn_hash;
+
+struct insn_cache_hasher : ggc_cache_ptr_hash<rtx_def>
+{
+  static hashval_t hash (rtx x) { return htab_hash_pointer (x); }
+  static bool equal (rtx a, rtx b) { return a == b; }
+};
+
+static GTY((cache))
+  hash_table<insn_cache_hasher> *prologue_insn_hash;
+static GTY((cache))
+  hash_table<insn_cache_hasher> *epilogue_insn_hash;
 \f
 
 hash_table<used_type_hasher> *types_used_by_vars_hash = NULL;
@@ -133,8 +148,9 @@ static tree *get_block_vector (tree, int *);
 extern tree debug_find_var_in_block_tree (tree, tree);
 /* We always define `record_insns' even if it's not used so that we
    can always export `prologue_epilogue_contains'.  */
-static void record_insns (rtx_insn *, rtx, htab_t *) ATTRIBUTE_UNUSED;
-static bool contains (const_rtx, htab_t);
+static void record_insns (rtx_insn *, rtx, hash_table<insn_cache_hasher> **)
+     ATTRIBUTE_UNUSED;
+static bool contains (const_rtx, hash_table<insn_cache_hasher> *);
 static void prepare_function_start (void);
 static void do_clobber_return_reg (rtx, void *);
 static void do_use_return_reg (rtx, void *);
@@ -558,7 +574,7 @@ struct GTY((for_user)) temp_slot_address_entry {
   struct temp_slot *temp_slot;
 };
 
-struct temp_address_hasher : ggc_hasher<temp_slot_address_entry *>
+struct temp_address_hasher : ggc_ptr_hash<temp_slot_address_entry>
 {
   static hashval_t hash (temp_slot_address_entry *);
   static bool equal (temp_slot_address_entry *, temp_slot_address_entry *);
@@ -2017,9 +2033,14 @@ aggregate_value_p (const_tree exp, const_tree fntype)
       case CALL_EXPR:
        {
          tree fndecl = get_callee_fndecl (fntype);
-         fntype = (fndecl
-                   ? TREE_TYPE (fndecl)
-                   : TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (fntype))));
+         if (fndecl)
+           fntype = TREE_TYPE (fndecl);
+         else if (CALL_EXPR_FN (fntype))
+           fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (fntype)));
+         else
+           /* For internal functions, assume nothing needs to be
+              returned in memory.  */
+           return 0;
        }
        break;
       case FUNCTION_DECL:
@@ -2100,6 +2121,14 @@ use_register_for_decl (const_tree decl)
   if (TREE_ADDRESSABLE (decl))
     return false;
 
+  /* Decl is implicitly addressible by bound stores and loads
+     if it is an aggregate holding bounds.  */
+  if (chkp_function_instrumented_p (current_function_decl)
+      && TREE_TYPE (decl)
+      && !BOUNDED_P (decl)
+      && chkp_type_has_pointer (TREE_TYPE (decl)))
+    return false;
+
   /* Only register-like things go in registers.  */
   if (DECL_MODE (decl) == BLKmode)
     return false;
@@ -2130,7 +2159,7 @@ use_register_for_decl (const_tree decl)
       /* When not optimizing, disregard register keyword for variables with
         types containing methods, otherwise the methods won't be callable
         from the debugger.  */
-      if (TYPE_METHODS (TREE_TYPE (decl)))
+      if (TYPE_METHODS (TYPE_MAIN_VARIANT (TREE_TYPE (decl))))
        return false;
       break;
     default:
@@ -2140,49 +2169,6 @@ use_register_for_decl (const_tree decl)
   return true;
 }
 
-/* Return true if TYPE should be passed by invisible reference.  */
-
-bool
-pass_by_reference (CUMULATIVE_ARGS *ca, machine_mode mode,
-                  tree type, bool named_arg)
-{
-  if (type)
-    {
-      /* If this type contains non-trivial constructors, then it is
-        forbidden for the middle-end to create any new copies.  */
-      if (TREE_ADDRESSABLE (type))
-       return true;
-
-      /* GCC post 3.4 passes *all* variable sized types by reference.  */
-      if (!TYPE_SIZE (type) || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
-       return true;
-
-      /* If a record type should be passed the same as its first (and only)
-        member, use the type and mode of that member.  */
-      if (TREE_CODE (type) == RECORD_TYPE && TYPE_TRANSPARENT_AGGR (type))
-       {
-         type = TREE_TYPE (first_field (type));
-         mode = TYPE_MODE (type);
-       }
-    }
-
-  return targetm.calls.pass_by_reference (pack_cumulative_args (ca), mode,
-                                         type, named_arg);
-}
-
-/* Return true if TYPE, which is passed by reference, should be callee
-   copied instead of caller copied.  */
-
-bool
-reference_callee_copied (CUMULATIVE_ARGS *ca, machine_mode mode,
-                        tree type, bool named_arg)
-{
-  if (type && TREE_ADDRESSABLE (type))
-    return false;
-  return targetm.calls.callee_copies (pack_cumulative_args (ca), mode, type,
-                                     named_arg);
-}
-
 /* Structures to communicate between the subroutines of assign_parms.
    The first holds data persistent across all parameters, the second
    is cleared out for each parameter.  */
@@ -2220,6 +2206,15 @@ struct assign_parm_data_one
   BOOL_BITFIELD loaded_in_reg : 1;
 };
 
+struct bounds_parm_data
+{
+  assign_parm_data_one parm_data;
+  tree bounds_parm;
+  tree ptr_parm;
+  rtx ptr_entry;
+  int bound_no;
+};
+
 /* A subroutine of assign_parms.  Initialize ALL.  */
 
 static void
@@ -2331,6 +2326,23 @@ assign_parms_augmented_arg_list (struct assign_parm_data_all *all)
       fnargs.safe_insert (0, decl);
 
       all->function_result_decl = decl;
+
+      /* If function is instrumented then bounds of the
+        passed structure address is the second argument.  */
+      if (chkp_function_instrumented_p (fndecl))
+       {
+         decl = build_decl (DECL_SOURCE_LOCATION (fndecl),
+                            PARM_DECL, get_identifier (".result_bnd"),
+                            pointer_bounds_type_node);
+         DECL_ARG_TYPE (decl) = pointer_bounds_type_node;
+         DECL_ARTIFICIAL (decl) = 1;
+         DECL_NAMELESS (decl) = 1;
+         TREE_CONSTANT (decl) = 1;
+
+         DECL_CHAIN (decl) = DECL_CHAIN (all->orig_fnargs);
+         DECL_CHAIN (all->orig_fnargs) = decl;
+         fnargs.safe_insert (1, decl);
+       }
     }
 
   /* If the target wants to split complex arguments into scalars, do so.  */
@@ -2471,7 +2483,7 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all,
      it came in a register so that REG_PARM_STACK_SPACE isn't skipped.
      In this case, we call FUNCTION_ARG with NAMED set to 1 instead of 0
      as it was the previous time.  */
-  in_regs = entry_parm != 0;
+  in_regs = (entry_parm != 0) || POINTER_BOUNDS_TYPE_P (data->passed_type);
 #ifdef STACK_PARMS_IN_REG_PARM_AREA
   in_regs = true;
 #endif
@@ -2560,8 +2572,12 @@ static bool
 assign_parm_is_stack_parm (struct assign_parm_data_all *all,
                           struct assign_parm_data_one *data)
 {
+  /* Bounds are never passed on the stack to keep compatibility
+     with not instrumented code.  */
+  if (POINTER_BOUNDS_TYPE_P (data->passed_type))
+    return false;
   /* Trivially true if we've no incoming register.  */
-  if (data->entry_parm == NULL)
+  else if (data->entry_parm == NULL)
     ;
   /* Also true if we're partially in registers and partially not,
      since we've arranged to drop the entire argument on the stack.  */
@@ -3044,8 +3060,8 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
            }
          else
            t = op1;
-         rtx pat = gen_extend_insn (op0, t, promoted_nominal_mode,
-                                    data->passed_mode, unsignedp);
+         rtx_insn *pat = gen_extend_insn (op0, t, promoted_nominal_mode,
+                                          data->passed_mode, unsignedp);
          emit_insn (pat);
          insns = get_insns ();
 
@@ -3370,6 +3386,121 @@ assign_parms_unsplit_complex (struct assign_parm_data_all *all,
     }
 }
 
+/* Load bounds of PARM from bounds table.  */
+static void
+assign_parm_load_bounds (struct assign_parm_data_one *data,
+                        tree parm,
+                        rtx entry,
+                        unsigned bound_no)
+{
+  bitmap_iterator bi;
+  unsigned i, offs = 0;
+  int bnd_no = -1;
+  rtx slot = NULL, ptr = NULL;
+
+  if (parm)
+    {
+      bitmap slots;
+      bitmap_obstack_initialize (NULL);
+      slots = BITMAP_ALLOC (NULL);
+      chkp_find_bound_slots (TREE_TYPE (parm), slots);
+      EXECUTE_IF_SET_IN_BITMAP (slots, 0, i, bi)
+       {
+         if (bound_no)
+           bound_no--;
+         else
+           {
+             bnd_no = i;
+             break;
+           }
+       }
+      BITMAP_FREE (slots);
+      bitmap_obstack_release (NULL);
+    }
+
+  /* We may have bounds not associated with any pointer.  */
+  if (bnd_no != -1)
+    offs = bnd_no * POINTER_SIZE / BITS_PER_UNIT;
+
+  /* Find associated pointer.  */
+  if (bnd_no == -1)
+    {
+      /* If bounds are not associated with any bounds,
+        then it is passed in a register or special slot.  */
+      gcc_assert (data->entry_parm);
+      ptr = const0_rtx;
+    }
+  else if (MEM_P (entry))
+    slot = adjust_address (entry, Pmode, offs);
+  else if (REG_P (entry))
+    ptr = gen_rtx_REG (Pmode, REGNO (entry) + bnd_no);
+  else if (GET_CODE (entry) == PARALLEL)
+    ptr = chkp_get_value_with_offs (entry, GEN_INT (offs));
+  else
+    gcc_unreachable ();
+  data->entry_parm = targetm.calls.load_bounds_for_arg (slot, ptr,
+                                                       data->entry_parm);
+}
+
+/* Assign RTL expressions to the function's bounds parameters BNDARGS.  */
+
+static void
+assign_bounds (vec<bounds_parm_data> &bndargs,
+              struct assign_parm_data_all &all,
+              bool assign_regs, bool assign_special,
+              bool assign_bt)
+{
+  unsigned i, pass;
+  bounds_parm_data *pbdata;
+
+  if (!bndargs.exists ())
+    return;
+
+  /* We make few passes to store input bounds.  Firstly handle bounds
+     passed in registers.  After that we load bounds passed in special
+     slots.  Finally we load bounds from Bounds Table.  */
+  for (pass = 0; pass < 3; pass++)
+    FOR_EACH_VEC_ELT (bndargs, i, pbdata)
+      {
+       /* Pass 0 => regs only.  */
+       if (pass == 0
+           && (!assign_regs
+               ||(!pbdata->parm_data.entry_parm
+                  || GET_CODE (pbdata->parm_data.entry_parm) != REG)))
+         continue;
+       /* Pass 1 => slots only.  */
+       else if (pass == 1
+                && (!assign_special
+                    || (!pbdata->parm_data.entry_parm
+                        || GET_CODE (pbdata->parm_data.entry_parm) == REG)))
+         continue;
+       /* Pass 2 => BT only.  */
+       else if (pass == 2
+                && (!assign_bt
+                    || pbdata->parm_data.entry_parm))
+         continue;
+
+       if (!pbdata->parm_data.entry_parm
+           || GET_CODE (pbdata->parm_data.entry_parm) != REG)
+         assign_parm_load_bounds (&pbdata->parm_data, pbdata->ptr_parm,
+                                  pbdata->ptr_entry, pbdata->bound_no);
+
+       set_decl_incoming_rtl (pbdata->bounds_parm,
+                              pbdata->parm_data.entry_parm, false);
+
+       if (assign_parm_setup_block_p (&pbdata->parm_data))
+         assign_parm_setup_block (&all, pbdata->bounds_parm,
+                                  &pbdata->parm_data);
+       else if (pbdata->parm_data.passed_pointer
+                || use_register_for_decl (pbdata->bounds_parm))
+         assign_parm_setup_reg (&all, pbdata->bounds_parm,
+                                &pbdata->parm_data);
+       else
+         assign_parm_setup_stack (&all, pbdata->bounds_parm,
+                                  &pbdata->parm_data);
+      }
+}
+
 /* Assign RTL expressions to the function's parameters.  This may involve
    copying them into registers and using those registers as the DECL_RTL.  */
 
@@ -3379,7 +3510,11 @@ assign_parms (tree fndecl)
   struct assign_parm_data_all all;
   tree parm;
   vec<tree> fnargs;
-  unsigned i;
+  unsigned i, bound_no = 0;
+  tree last_arg = NULL;
+  rtx last_arg_entry = NULL;
+  vec<bounds_parm_data> bndargs = vNULL;
+  bounds_parm_data bdata;
 
   crtl->args.internal_arg_pointer
     = targetm.calls.internal_arg_pointer ();
@@ -3421,9 +3556,6 @@ assign_parms (tree fndecl)
            }
        }
 
-      if (cfun->stdarg && !DECL_CHAIN (parm))
-       assign_parms_setup_varargs (&all, &data, false);
-
       /* Find out where the parameter arrives in this function.  */
       assign_parm_find_entry_rtl (&all, &data);
 
@@ -3433,7 +3565,15 @@ assign_parms (tree fndecl)
          assign_parm_find_stack_rtl (parm, &data);
          assign_parm_adjust_entry_rtl (&data);
        }
-
+      if (!POINTER_BOUNDS_TYPE_P (data.passed_type))
+       {
+         /* Remember where last non bounds arg was passed in case
+            we have to load associated bounds for it from Bounds
+            Table.  */
+         last_arg = parm;
+         last_arg_entry = data.entry_parm;
+         bound_no = 0;
+       }
       /* Record permanently how this parm was passed.  */
       if (data.passed_pointer)
        {
@@ -3445,30 +3585,71 @@ assign_parms (tree fndecl)
       else
        set_decl_incoming_rtl (parm, data.entry_parm, false);
 
+      /* Boudns should be loaded in the particular order to
+        have registers allocated correctly.  Collect info about
+        input bounds and load them later.  */
+      if (POINTER_BOUNDS_TYPE_P (data.passed_type))
+       {
+         /* Expect bounds in instrumented functions only.  */
+         gcc_assert (chkp_function_instrumented_p (fndecl));
+
+         bdata.parm_data = data;
+         bdata.bounds_parm = parm;
+         bdata.ptr_parm = last_arg;
+         bdata.ptr_entry = last_arg_entry;
+         bdata.bound_no = bound_no;
+         bndargs.safe_push (bdata);
+       }
+      else
+       {
+         assign_parm_adjust_stack_rtl (&data);
+
+         if (assign_parm_setup_block_p (&data))
+           assign_parm_setup_block (&all, parm, &data);
+         else if (data.passed_pointer || use_register_for_decl (parm))
+           assign_parm_setup_reg (&all, parm, &data);
+         else
+           assign_parm_setup_stack (&all, parm, &data);
+       }
+
+      if (cfun->stdarg && !DECL_CHAIN (parm))
+       {
+         int pretend_bytes = 0;
+
+         assign_parms_setup_varargs (&all, &data, false);
+
+         if (chkp_function_instrumented_p (fndecl))
+           {
+             /* We expect this is the last parm.  Otherwise it is wrong
+                to assign bounds right now.  */
+             gcc_assert (i == (fnargs.length () - 1));
+             assign_bounds (bndargs, all, true, false, false);
+             targetm.calls.setup_incoming_vararg_bounds (all.args_so_far,
+                                                         data.promoted_mode,
+                                                         data.passed_type,
+                                                         &pretend_bytes,
+                                                         false);
+             assign_bounds (bndargs, all, false, true, true);
+             bndargs.release ();
+           }
+       }
+
       /* Update info on where next arg arrives in registers.  */
       targetm.calls.function_arg_advance (all.args_so_far, data.promoted_mode,
                                          data.passed_type, data.named_arg);
 
-      assign_parm_adjust_stack_rtl (&data);
-
-      if (assign_parm_setup_block_p (&data))
-       assign_parm_setup_block (&all, parm, &data);
-      else if (data.passed_pointer || use_register_for_decl (parm))
-       assign_parm_setup_reg (&all, parm, &data);
-      else
-       assign_parm_setup_stack (&all, parm, &data);
+      if (POINTER_BOUNDS_TYPE_P (data.passed_type))
+       bound_no++;
     }
 
+  assign_bounds (bndargs, all, true, true, true);
+  bndargs.release ();
+
   if (targetm.calls.split_complex_arg)
     assign_parms_unsplit_complex (&all, fnargs);
 
   fnargs.release ();
 
-  /* Initialize pic_offset_table_rtx with a pseudo register
-     if required.  */
-  if (targetm.use_pseudo_pic_reg ())
-    pic_offset_table_rtx = gen_reg_rtx (Pmode);
-
   /* Output all parameter conversion instructions (possibly including calls)
      now that all parameters have been copied out of hard registers.  */
   emit_insn (all.first_conversion_insn);
@@ -3537,15 +3718,16 @@ assign_parms (tree fndecl)
   crtl->args.size = CEIL_ROUND (crtl->args.size,
                                           PARM_BOUNDARY / BITS_PER_UNIT);
 
-#ifdef ARGS_GROW_DOWNWARD
-  crtl->args.arg_offset_rtx
-    = (all.stack_args_size.var == 0 ? GEN_INT (-all.stack_args_size.constant)
-       : expand_expr (size_diffop (all.stack_args_size.var,
-                                  size_int (-all.stack_args_size.constant)),
-                     NULL_RTX, VOIDmode, EXPAND_NORMAL));
-#else
-  crtl->args.arg_offset_rtx = ARGS_SIZE_RTX (all.stack_args_size);
-#endif
+  if (ARGS_GROW_DOWNWARD)
+    {
+      crtl->args.arg_offset_rtx
+       = (all.stack_args_size.var == 0 ? GEN_INT (-all.stack_args_size.constant)
+          : expand_expr (size_diffop (all.stack_args_size.var,
+                                      size_int (-all.stack_args_size.constant)),
+                         NULL_RTX, VOIDmode, EXPAND_NORMAL));
+    }
+  else
+    crtl->args.arg_offset_rtx = ARGS_SIZE_RTX (all.stack_args_size);
 
   /* See how many bytes, if any, of its args a function should try to pop
      on return.  */
@@ -3584,6 +3766,10 @@ assign_parms (tree fndecl)
 
          real_decl_rtl = targetm.calls.function_value (TREE_TYPE (decl_result),
                                                        fndecl, true);
+         if (chkp_function_instrumented_p (fndecl))
+           crtl->return_bnd
+             = targetm.calls.chkp_function_value_bounds (TREE_TYPE (decl_result),
+                                                         fndecl, true);
          REG_FUNCTION_VALUE_P (real_decl_rtl) = 1;
          /* The delay slot scheduler assumes that crtl->return_rtx
             holds the hard register containing the return value, not a
@@ -3832,68 +4018,71 @@ locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs,
   if (crtl->preferred_stack_boundary < boundary)
     crtl->preferred_stack_boundary = boundary;
 
-#ifdef ARGS_GROW_DOWNWARD
-  locate->slot_offset.constant = -initial_offset_ptr->constant;
-  if (initial_offset_ptr->var)
-    locate->slot_offset.var = size_binop (MINUS_EXPR, ssize_int (0),
-                                         initial_offset_ptr->var);
+  if (ARGS_GROW_DOWNWARD)
+    {
+      locate->slot_offset.constant = -initial_offset_ptr->constant;
+      if (initial_offset_ptr->var)
+       locate->slot_offset.var = size_binop (MINUS_EXPR, ssize_int (0),
+                                             initial_offset_ptr->var);
 
-  {
-    tree s2 = sizetree;
-    if (where_pad != none
-       && (!tree_fits_uhwi_p (sizetree)
-           || (tree_to_uhwi (sizetree) * BITS_PER_UNIT) % round_boundary))
-      s2 = round_up (s2, round_boundary / BITS_PER_UNIT);
-    SUB_PARM_SIZE (locate->slot_offset, s2);
-  }
+       {
+         tree s2 = sizetree;
+         if (where_pad != none
+             && (!tree_fits_uhwi_p (sizetree)
+                 || (tree_to_uhwi (sizetree) * BITS_PER_UNIT) % round_boundary))
+           s2 = round_up (s2, round_boundary / BITS_PER_UNIT);
+         SUB_PARM_SIZE (locate->slot_offset, s2);
+       }
+
+      locate->slot_offset.constant += part_size_in_regs;
+
+      if (!in_regs || reg_parm_stack_space > 0)
+       pad_to_arg_alignment (&locate->slot_offset, boundary,
+                             &locate->alignment_pad);
+
+      locate->size.constant = (-initial_offset_ptr->constant
+                              - locate->slot_offset.constant);
+      if (initial_offset_ptr->var)
+       locate->size.var = size_binop (MINUS_EXPR,
+                                      size_binop (MINUS_EXPR,
+                                                  ssize_int (0),
+                                                  initial_offset_ptr->var),
+                                      locate->slot_offset.var);
+
+      /* Pad_below needs the pre-rounded size to know how much to pad
+        below.  */
+      locate->offset = locate->slot_offset;
+      if (where_pad == downward)
+       pad_below (&locate->offset, passed_mode, sizetree);
 
-  locate->slot_offset.constant += part_size_in_regs;
-
-  if (!in_regs || reg_parm_stack_space > 0)
-    pad_to_arg_alignment (&locate->slot_offset, boundary,
-                         &locate->alignment_pad);
-
-  locate->size.constant = (-initial_offset_ptr->constant
-                          - locate->slot_offset.constant);
-  if (initial_offset_ptr->var)
-    locate->size.var = size_binop (MINUS_EXPR,
-                                  size_binop (MINUS_EXPR,
-                                              ssize_int (0),
-                                              initial_offset_ptr->var),
-                                  locate->slot_offset.var);
-
-  /* Pad_below needs the pre-rounded size to know how much to pad
-     below.  */
-  locate->offset = locate->slot_offset;
-  if (where_pad == downward)
-    pad_below (&locate->offset, passed_mode, sizetree);
-
-#else /* !ARGS_GROW_DOWNWARD */
-  if (!in_regs || reg_parm_stack_space > 0)
-    pad_to_arg_alignment (initial_offset_ptr, boundary,
-                         &locate->alignment_pad);
-  locate->slot_offset = *initial_offset_ptr;
+    }
+  else
+    {
+      if (!in_regs || reg_parm_stack_space > 0)
+       pad_to_arg_alignment (initial_offset_ptr, boundary,
+                             &locate->alignment_pad);
+      locate->slot_offset = *initial_offset_ptr;
 
 #ifdef PUSH_ROUNDING
-  if (passed_mode != BLKmode)
-    sizetree = size_int (PUSH_ROUNDING (TREE_INT_CST_LOW (sizetree)));
+      if (passed_mode != BLKmode)
+       sizetree = size_int (PUSH_ROUNDING (TREE_INT_CST_LOW (sizetree)));
 #endif
 
-  /* Pad_below needs the pre-rounded size to know how much to pad below
-     so this must be done before rounding up.  */
-  locate->offset = locate->slot_offset;
-  if (where_pad == downward)
-    pad_below (&locate->offset, passed_mode, sizetree);
+      /* Pad_below needs the pre-rounded size to know how much to pad below
+        so this must be done before rounding up.  */
+      locate->offset = locate->slot_offset;
+      if (where_pad == downward)
+       pad_below (&locate->offset, passed_mode, sizetree);
 
-  if (where_pad != none
-      && (!tree_fits_uhwi_p (sizetree)
-         || (tree_to_uhwi (sizetree) * BITS_PER_UNIT) % round_boundary))
-    sizetree = round_up (sizetree, round_boundary / BITS_PER_UNIT);
+      if (where_pad != none
+         && (!tree_fits_uhwi_p (sizetree)
+             || (tree_to_uhwi (sizetree) * BITS_PER_UNIT) % round_boundary))
+       sizetree = round_up (sizetree, round_boundary / BITS_PER_UNIT);
 
-  ADD_PARM_SIZE (locate->size, sizetree);
+      ADD_PARM_SIZE (locate->size, sizetree);
 
-  locate->size.constant -= part_size_in_regs;
-#endif /* ARGS_GROW_DOWNWARD */
+      locate->size.constant -= part_size_in_regs;
+    }
 
 #ifdef FUNCTION_ARG_OFFSET
   locate->offset.constant += FUNCTION_ARG_OFFSET (passed_mode, type);
@@ -3937,11 +4126,11 @@ pad_to_arg_alignment (struct args_size *offset_ptr, int boundary,
          tree offset = size_binop (PLUS_EXPR,
                                    ARGS_SIZE_TREE (*offset_ptr),
                                    sp_offset_tree);
-#ifdef ARGS_GROW_DOWNWARD
-         tree rounded = round_down (offset, boundary / BITS_PER_UNIT);
-#else
-         tree rounded = round_up   (offset, boundary / BITS_PER_UNIT);
-#endif
+         tree rounded;
+         if (ARGS_GROW_DOWNWARD)
+           rounded = round_down (offset, boundary / BITS_PER_UNIT);
+         else
+           rounded = round_up   (offset, boundary / BITS_PER_UNIT);
 
          offset_ptr->var = size_binop (MINUS_EXPR, rounded, sp_offset_tree);
          /* ARGS_SIZE_TREE includes constant term.  */
@@ -3953,11 +4142,10 @@ pad_to_arg_alignment (struct args_size *offset_ptr, int boundary,
       else
        {
          offset_ptr->constant = -sp_offset +
-#ifdef ARGS_GROW_DOWNWARD
-           FLOOR_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes);
-#else
-           CEIL_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes);
-#endif
+           (ARGS_GROW_DOWNWARD
+           ? FLOOR_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes)
+           : CEIL_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes));
+
            if (boundary > PARM_BOUNDARY)
              alignment_pad->constant = offset_ptr->constant - save_constant;
        }
@@ -4593,7 +4781,7 @@ push_struct_function (tree fndecl)
 static void
 prepare_function_start (void)
 {
-  gcc_assert (!crtl->emit.x_last_insn);
+  gcc_assert (!get_last_insn ());
   init_temp_slots ();
   init_emit ();
   init_varasm_status ();
@@ -4624,6 +4812,29 @@ prepare_function_start (void)
   frame_pointer_needed = 0;
 }
 
+void
+push_dummy_function (bool with_decl)
+{
+  tree fn_decl, fn_type, fn_result_decl;
+
+  gcc_assert (!in_dummy_function);
+  in_dummy_function = true;
+
+  if (with_decl)
+    {
+      fn_type = build_function_type_list (void_type_node, NULL_TREE);
+      fn_decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, NULL_TREE,
+                           fn_type);
+      fn_result_decl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+                                        NULL_TREE, void_type_node);
+      DECL_RESULT (fn_decl) = fn_result_decl;
+    }
+  else
+    fn_decl = NULL_TREE;
+
+  push_struct_function (fn_decl);
+}
+
 /* Initialize the rtl expansion mechanism so that we can do simple things
    like generate sequences.  This is used to provide a context during global
    initialization of some passes.  You must call expand_dummy_function_end
@@ -4632,9 +4843,7 @@ prepare_function_start (void)
 void
 init_dummy_function_start (void)
 {
-  gcc_assert (!in_dummy_function);
-  in_dummy_function = true;
-  push_struct_function (NULL_TREE);
+  push_dummy_function (false);
   prepare_function_start ();
 }
 
@@ -4682,7 +4891,7 @@ stack_protect_epilogue (void)
 
   /* Allow the target to compare Y with X without leaking either into
      a register.  */
-  switch ((int) (HAVE_stack_protect_test != 0))
+  switch (HAVE_stack_protect_test != 0)
     {
     case 1:
       tmp = gen_stack_protect_test (x, y, label);
@@ -4814,6 +5023,14 @@ expand_function_start (tree subr)
       /* Set DECL_REGISTER flag so that expand_function_end will copy the
         result to the real return register(s).  */
       DECL_REGISTER (DECL_RESULT (subr)) = 1;
+
+      if (chkp_function_instrumented_p (current_function_decl))
+       {
+         tree return_type = TREE_TYPE (DECL_RESULT (subr));
+         rtx bounds = targetm.calls.chkp_function_value_bounds (return_type,
+                                                                subr, 1);
+         SET_DECL_BOUNDS_RTL (DECL_RESULT (subr), bounds);
+       }
     }
 
   /* Initialize rtx for parameters and local variables.
@@ -4824,7 +5041,8 @@ expand_function_start (tree subr)
   if (cfun->static_chain_decl)
     {
       tree parm = cfun->static_chain_decl;
-      rtx local, chain, insn;
+      rtx local, chain;
+     rtx_insn *insn;
 
       local = gen_reg_rtx (Pmode);
       chain = targetm.calls.static_chain (current_function_decl, true);
@@ -4898,6 +5116,13 @@ expand_function_start (tree subr)
     stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
 }
 \f
+void
+pop_dummy_function (void)
+{
+  pop_cfun ();
+  in_dummy_function = false;
+}
+
 /* Undo the effects of init_dummy_function_start.  */
 void
 expand_dummy_function_end (void)
@@ -4913,18 +5138,14 @@ expand_dummy_function_end (void)
 
   free_after_parsing (cfun);
   free_after_compilation (cfun);
-  pop_cfun ();
-  in_dummy_function = false;
+  pop_dummy_function ();
 }
 
-/* Call DOIT for each hard register used as a return value from
-   the current function.  */
+/* Helper for diddle_return_value.  */
 
 void
-diddle_return_value (void (*doit) (rtx, void *), void *arg)
+diddle_return_value_1 (void (*doit) (rtx, void *), void *arg, rtx outgoing)
 {
-  rtx outgoing = crtl->return_rtx;
-
   if (! outgoing)
     return;
 
@@ -4944,6 +5165,16 @@ diddle_return_value (void (*doit) (rtx, void *), void *arg)
     }
 }
 
+/* Call DOIT for each hard register used as a return value from
+   the current function.  */
+
+void
+diddle_return_value (void (*doit) (rtx, void *), void *arg)
+{
+  diddle_return_value_1 (doit, arg, crtl->return_bnd);
+  diddle_return_value_1 (doit, arg, crtl->return_rtx);
+}
+
 static void
 do_clobber_return_reg (rtx reg, void *arg ATTRIBUTE_UNUSED)
 {
@@ -5011,8 +5242,6 @@ set_insn_locations (rtx_insn *insn, int loc)
 void
 expand_function_end (void)
 {
-  rtx clobber_after;
-
   /* If arg_pointer_save_area was referenced only from a nested
      function, we will not have initialized it yet.  Do that now.  */
   if (arg_pointer_save_area && ! crtl->arg_pointer_save_area_init)
@@ -5061,7 +5290,7 @@ expand_function_end (void)
 
      We delay actual code generation after the current_function_value_rtx
      is computed.  */
-  clobber_after = get_last_insn ();
+  rtx_insn *clobber_after = get_last_insn ();
 
   /* Output the label for the actual return from the function.  */
   emit_label (return_label);
@@ -5176,8 +5405,8 @@ expand_function_end (void)
      If returning a structure PCC style,
      the caller also depends on this value.
      And cfun->returns_pcc_struct is not necessarily set.  */
-  if (cfun->returns_struct
-      || cfun->returns_pcc_struct)
+  if ((cfun->returns_struct || cfun->returns_pcc_struct)
+      && !targetm.calls.omit_struct_return_reg)
     {
       rtx value_address = DECL_RTL (DECL_RESULT (current_function_decl));
       tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
@@ -5211,11 +5440,9 @@ expand_function_end (void)
      certainly doesn't fall thru into the exit block.  */
   if (!BARRIER_P (clobber_after))
     {
-      rtx seq;
-
       start_sequence ();
       clobber_return_register ();
-      seq = get_insns ();
+      rtx_insn *seq = get_insns ();
       end_sequence ();
 
       emit_insn_after (seq, clobber_after);
@@ -5242,11 +5469,11 @@ expand_function_end (void)
   if (! EXIT_IGNORE_STACK
       && cfun->calls_alloca)
     {
-      rtx tem = 0, seq;
+      rtx tem = 0;
 
       start_sequence ();
       emit_stack_save (SAVE_FUNCTION, &tem);
-      seq = get_insns ();
+      rtx_insn *seq = get_insns ();
       end_sequence ();
       emit_insn_before (seq, parm_birth_insn);
 
@@ -5273,15 +5500,13 @@ get_arg_pointer_save_area (void)
 
   if (! crtl->arg_pointer_save_area_init)
     {
-      rtx seq;
-
       /* Save the arg pointer at the beginning of the function.  The
         generated stack slot may not be a valid memory address, so we
         have to check it and fix it if necessary.  */
       start_sequence ();
       emit_move_insn (validize_mem (copy_rtx (ret)),
                       crtl->args.internal_arg_pointer);
-      seq = get_insns ();
+      rtx_insn *seq = get_insns ();
       end_sequence ();
 
       push_topmost_sequence ();
@@ -5298,18 +5523,17 @@ get_arg_pointer_save_area (void)
    for the first time.  */
 
 static void
-record_insns (rtx_insn *insns, rtx end, htab_t *hashp)
+record_insns (rtx_insn *insns, rtx end, hash_table<insn_cache_hasher> **hashp)
 {
   rtx_insn *tmp;
-  htab_t hash = *hashp;
+  hash_table<insn_cache_hasher> *hash = *hashp;
 
   if (hash == NULL)
-    *hashp = hash
-      = htab_create_ggc (17, htab_hash_pointer, htab_eq_pointer, NULL);
+    *hashp = hash = hash_table<insn_cache_hasher>::create_ggc (17);
 
   for (tmp = insns; tmp != end; tmp = NEXT_INSN (tmp))
     {
-      void **slot = htab_find_slot (hash, tmp, INSERT);
+      rtx *slot = hash->find_slot (tmp, INSERT);
       gcc_assert (*slot == NULL);
       *slot = tmp;
     }
@@ -5322,18 +5546,18 @@ record_insns (rtx_insn *insns, rtx end, htab_t *hashp)
 void
 maybe_copy_prologue_epilogue_insn (rtx insn, rtx copy)
 {
-  htab_t hash;
-  void **slot;
+  hash_table<insn_cache_hasher> *hash;
+  rtx *slot;
 
   hash = epilogue_insn_hash;
-  if (!hash || !htab_find (hash, insn))
+  if (!hash || !hash->find (insn))
     {
       hash = prologue_insn_hash;
-      if (!hash || !htab_find (hash, insn))
+      if (!hash || !hash->find (insn))
        return;
     }
 
-  slot = htab_find_slot (hash, copy, INSERT);
+  slot = hash->find_slot (copy, INSERT);
   gcc_assert (*slot == NULL);
   *slot = copy;
 }
@@ -5342,7 +5566,7 @@ maybe_copy_prologue_epilogue_insn (rtx insn, rtx copy)
    we can be running after reorg, SEQUENCE rtl is possible.  */
 
 static bool
-contains (const_rtx insn, htab_t hash)
+contains (const_rtx insn, hash_table<insn_cache_hasher> *hash)
 {
   if (hash == NULL)
     return false;
@@ -5352,12 +5576,12 @@ contains (const_rtx insn, htab_t hash)
       rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (insn));
       int i;
       for (i = seq->len () - 1; i >= 0; i--)
-       if (htab_find (hash, seq->element (i)))
+       if (hash->find (seq->element (i)))
          return true;
       return false;
     }
 
-  return htab_find (hash, insn) != NULL;
+  return hash->find (const_cast<rtx> (insn)) != NULL;
 }
 
 int
@@ -5370,22 +5594,19 @@ prologue_epilogue_contains (const_rtx insn)
   return 0;
 }
 
-#ifdef HAVE_return
 /* Insert use of return register before the end of BB.  */
 
 static void
 emit_use_return_register_into_block (basic_block bb)
 {
-  rtx seq, insn;
   start_sequence ();
   use_return_register ();
-  seq = get_insns ();
+  rtx_insn *seq = get_insns ();
   end_sequence ();
-  insn = BB_END (bb);
-#ifdef HAVE_cc0
-  if (reg_mentioned_p (cc0_rtx, PATTERN (insn)))
+  rtx_insn *insn = BB_END (bb);
+  if (HAVE_cc0 && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
     insn = prev_cc0_setter (insn);
-#endif
+
   emit_insn_before (seq, insn);
 }
 
@@ -5393,15 +5614,12 @@ emit_use_return_register_into_block (basic_block bb)
 /* Create a return pattern, either simple_return or return, depending on
    simple_p.  */
 
-static rtx
+static rtx_insn *
 gen_return_pattern (bool simple_p)
 {
-#ifdef HAVE_simple_return
-  return simple_p ? gen_simple_return () : gen_return ();
-#else
-  gcc_assert (!simple_p);
-  return gen_return ();
-#endif
+  return (simple_p
+         ? targetm.gen_simple_return ()
+         : targetm.gen_return ());
 }
 
 /* Insert an appropriate return pattern at the end of block BB.  This
@@ -5411,20 +5629,19 @@ gen_return_pattern (bool simple_p)
 void
 emit_return_into_block (bool simple_p, basic_block bb)
 {
-  rtx jump, pat;
-  jump = emit_jump_insn_after (gen_return_pattern (simple_p), BB_END (bb));
-  pat = PATTERN (jump);
+  rtx_jump_insn *jump = emit_jump_insn_after (gen_return_pattern (simple_p),
+                                             BB_END (bb));
+  rtx pat = PATTERN (jump);
   if (GET_CODE (pat) == PARALLEL)
     pat = XVECEXP (pat, 0, 0);
   gcc_assert (ANY_RETURN_P (pat));
   JUMP_LABEL (jump) = pat;
 }
-#endif
 
 /* Set JUMP_LABEL for a return insn.  */
 
 void
-set_return_jump_label (rtx returnjump)
+set_return_jump_label (rtx_insn *returnjump)
 {
   rtx pat = PATTERN (returnjump);
   if (GET_CODE (pat) == PARALLEL)
@@ -5435,7 +5652,6 @@ set_return_jump_label (rtx returnjump)
     JUMP_LABEL (returnjump) = ret_rtx;
 }
 
-#if defined (HAVE_return) || defined (HAVE_simple_return)
 /* Return true if there are any active insns between HEAD and TAIL.  */
 bool
 active_insn_between (rtx_insn *head, rtx_insn *tail)
@@ -5460,7 +5676,6 @@ convert_jumps_to_returns (basic_block last_bb, bool simple_p,
 {
   int i;
   basic_block bb;
-  rtx label;
   edge_iterator ei;
   edge e;
   auto_vec<basic_block> src_bbs (EDGE_COUNT (last_bb->preds));
@@ -5469,7 +5684,7 @@ convert_jumps_to_returns (basic_block last_bb, bool simple_p,
     if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
       src_bbs.quick_push (e->src);
 
-  label = BB_HEAD (last_bb);
+  rtx_insn *label = BB_HEAD (last_bb);
 
   FOR_EACH_VEC_ELT (src_bbs, i, bb)
     {
@@ -5508,17 +5723,15 @@ convert_jumps_to_returns (basic_block last_bb, bool simple_p,
            dest = simple_return_rtx;
          else
            dest = ret_rtx;
-         if (!redirect_jump (jump, dest, 0))
+         if (!redirect_jump (as_a <rtx_jump_insn *> (jump), dest, 0))
            {
-#ifdef HAVE_simple_return
-             if (simple_p)
+             if (targetm.have_simple_return () && simple_p)
                {
                  if (dump_file)
                    fprintf (dump_file,
                             "Failed to redirect bb %d branch.\n", bb->index);
                  unconverted.safe_push (e);
                }
-#endif
              continue;
            }
 
@@ -5533,15 +5746,13 @@ convert_jumps_to_returns (basic_block last_bb, bool simple_p,
        }
       else
        {
-#ifdef HAVE_simple_return
-         if (simple_p)
+         if (targetm.have_simple_return () && simple_p)
            {
              if (dump_file)
                fprintf (dump_file,
                         "Failed to redirect bb %d branch.\n", bb->index);
              unconverted.safe_push (e);
            }
-#endif
          continue;
        }
 
@@ -5569,7 +5780,6 @@ emit_return_for_exit (edge exit_fallthru_edge, bool simple_p)
   exit_fallthru_edge->flags &= ~EDGE_FALLTHRU;
   return last_bb;
 }
-#endif
 
 
 /* Generate the prologue and epilogue RTL if the machine supports it.  Thread
@@ -5620,14 +5830,12 @@ emit_return_for_exit (edge exit_fallthru_edge, bool simple_p)
    in a sibcall omit the sibcall_epilogue if the block is not in
    ANTIC.  */
 
-static void
+void
 thread_prologue_and_epilogue_insns (void)
 {
   bool inserted;
-#ifdef HAVE_simple_return
   vec<edge> unconverted_simple_returns = vNULL;
   bitmap_head bb_flags;
-#endif
   rtx_insn *returnjump;
   rtx_insn *epilogue_end ATTRIBUTE_UNUSED;
   rtx_insn *prologue_seq ATTRIBUTE_UNUSED, *split_prologue_seq ATTRIBUTE_UNUSED;
@@ -5698,7 +5906,6 @@ thread_prologue_and_epilogue_insns (void)
     }
 #endif
 
-#ifdef HAVE_simple_return
   bitmap_initialize (&bb_flags, &bitmap_default_obstack);
 
   /* Try to perform a kind of shrink-wrapping, making sure the
@@ -5706,7 +5913,6 @@ thread_prologue_and_epilogue_insns (void)
      function that require it.  */
 
   try_shrink_wrapping (&entry_edge, orig_entry_edge, &bb_flags, prologue_seq);
-#endif
 
   if (split_prologue_seq != NULL_RTX)
     {
@@ -5731,15 +5937,12 @@ thread_prologue_and_epilogue_insns (void)
 
   exit_fallthru_edge = find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
 
-#ifdef HAVE_simple_return
-  if (entry_edge != orig_entry_edge)
+  if (targetm.have_simple_return () && entry_edge != orig_entry_edge)
     exit_fallthru_edge
        = get_unconverted_simple_return (exit_fallthru_edge, bb_flags,
                                         &unconverted_simple_returns,
                                         &returnjump);
-#endif
-#ifdef HAVE_return
-  if (HAVE_return)
+  if (targetm.have_return ())
     {
       if (exit_fallthru_edge == NULL)
        goto epilogue_done;
@@ -5757,17 +5960,17 @@ thread_prologue_and_epilogue_insns (void)
            {
              last_bb = emit_return_for_exit (exit_fallthru_edge, false);
              epilogue_end = returnjump = BB_END (last_bb);
-#ifdef HAVE_simple_return
+
              /* Emitting the return may add a basic block.
                 Fix bb_flags for the added block.  */
-             if (last_bb != exit_fallthru_edge->src)
+             if (targetm.have_simple_return ()
+                 && last_bb != exit_fallthru_edge->src)
                bitmap_set_bit (&bb_flags, last_bb->index);
-#endif
+
              goto epilogue_done;
            }
        }
     }
-#endif
 
   /* A small fib -- epilogue is not yet completed, but we wish to re-use
      this marker for the splits of EH_RETURN patterns, and nothing else
@@ -5806,7 +6009,6 @@ thread_prologue_and_epilogue_insns (void)
   if (exit_fallthru_edge == NULL)
     goto epilogue_done;
 
-#ifdef HAVE_epilogue
   if (HAVE_epilogue)
     {
       start_sequence ();
@@ -5830,7 +6032,6 @@ thread_prologue_and_epilogue_insns (void)
        set_return_jump_label (returnjump);
     }
   else
-#endif
     {
       basic_block cur_bb;
 
@@ -5879,10 +6080,9 @@ epilogue_done:
        }
     }
 
-#ifdef HAVE_simple_return
-  convert_to_simple_return (entry_edge, orig_entry_edge, bb_flags, returnjump,
-                           unconverted_simple_returns);
-#endif
+  if (targetm.have_simple_return ())
+    convert_to_simple_return (entry_edge, orig_entry_edge, bb_flags,
+                             returnjump, unconverted_simple_returns);
 
 #ifdef HAVE_sibcall_epilogue
   /* Emit sibling epilogues before any sibling call sites.  */
@@ -5896,11 +6096,9 @@ epilogue_done:
 
       if (!CALL_P (insn)
          || ! SIBLING_CALL_P (insn)
-#ifdef HAVE_simple_return
-         || (entry_edge != orig_entry_edge
-             && !bitmap_bit_p (&bb_flags, bb->index))
-#endif
-         )
+         || (targetm.have_simple_return ()
+             && entry_edge != orig_entry_edge
+             && !bitmap_bit_p (&bb_flags, bb->index)))
        {
          ei_next (&ei);
          continue;
@@ -5927,7 +6125,6 @@ epilogue_done:
     }
 #endif
 
-#ifdef HAVE_epilogue
   if (epilogue_end)
     {
       rtx_insn *insn, *next;
@@ -5945,11 +6142,8 @@ epilogue_done:
            reorder_insns (insn, insn, PREV_INSN (epilogue_end));
        }
     }
-#endif
 
-#ifdef HAVE_simple_return
   bitmap_clear (&bb_flags);
-#endif
 
   /* Threading the prologue and epilogue changes the artificial refs
      in the entry and exit blocks.  */
@@ -5963,13 +6157,16 @@ epilogue_done:
 void
 reposition_prologue_and_epilogue_notes (void)
 {
-#if defined (HAVE_prologue) || defined (HAVE_epilogue) \
-    || defined (HAVE_sibcall_epilogue)
+#if ! defined (HAVE_prologue) && ! defined (HAVE_sibcall_epilogue)
+  if (!HAVE_epilogue)
+    return;
+#endif
+
   /* Since the hash table is created on demand, the fact that it is
      non-null is a signal that it is non-empty.  */
   if (prologue_insn_hash != NULL)
     {
-      size_t len = htab_elements (prologue_insn_hash);
+      size_t len = prologue_insn_hash->elements ();
       rtx_insn *insn, *last = NULL, *note = NULL;
 
       /* Scan from the beginning until we reach the last prologue insn.  */
@@ -6061,7 +6258,6 @@ reposition_prologue_and_epilogue_notes (void)
            }
        }
     }
-#endif /* HAVE_prologue or HAVE_epilogue */
 }
 
 /* Returns the name of function declared by FNDECL.  */