]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/function.c
Update copyright years.
[thirdparty/gcc.git] / gcc / function.c
index 10bcefb2cfe617ae8012b0f1a70bceec7aeca53d..d8008f60422e5b433ab63cc3cef0c00b537dd0b9 100644 (file)
@@ -1,5 +1,5 @@
 /* Expands front end tree to back end RTL for GCC.
-   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+   Copyright (C) 1987-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -73,12 +73,13 @@ 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"
 #include "tree-dfa.h"
 #include "tree-ssa.h"
 #include "stringpool.h"
 #include "attribs.h"
+#include "gimple.h"
+#include "options.h"
+#include "function-abi.h"
 
 /* So we can assign to cfun in this file.  */
 #undef cfun
@@ -133,7 +134,7 @@ vec<tree, va_gc> *types_used_by_cur_var_decl;
 
 /* Forward declarations.  */
 
-static struct temp_slot *find_temp_slot_from_address (rtx);
+static class temp_slot *find_temp_slot_from_address (rtx);
 static void pad_to_arg_alignment (struct args_size *, int, struct args_size *);
 static void pad_below (struct args_size *, machine_mode, tree);
 static void reorder_blocks_1 (rtx_insn *, tree, vec<tree> *);
@@ -218,7 +219,7 @@ free_after_compilation (struct function *f)
    This size counts from zero.  It is not rounded to PREFERRED_STACK_BOUNDARY;
    the caller may have to do that.  */
 
-HOST_WIDE_INT
+poly_int64
 get_frame_size (void)
 {
   if (FRAME_GROWS_DOWNWARD)
@@ -232,20 +233,29 @@ get_frame_size (void)
    return FALSE.  */
 
 bool
-frame_offset_overflow (HOST_WIDE_INT offset, tree func)
+frame_offset_overflow (poly_int64 offset, tree func)
 {
-  unsigned HOST_WIDE_INT size = FRAME_GROWS_DOWNWARD ? -offset : offset;
+  poly_uint64 size = FRAME_GROWS_DOWNWARD ? -offset : offset;
+  unsigned HOST_WIDE_INT limit
+    = ((HOST_WIDE_INT_1U << (GET_MODE_BITSIZE (Pmode) - 1))
+       /* Leave room for the fixed part of the frame.  */
+       - 64 * UNITS_PER_WORD);
 
-  if (size > (HOST_WIDE_INT_1U << (GET_MODE_BITSIZE (Pmode) - 1))
-              /* Leave room for the fixed part of the frame.  */
-              - 64 * UNITS_PER_WORD)
+  if (!coeffs_in_range_p (size, 0U, limit))
     {
-      error_at (DECL_SOURCE_LOCATION (func),
-               "total size of local objects too large");
-      return TRUE;
+      unsigned HOST_WIDE_INT hwisize;
+      if (size.is_constant (&hwisize))
+       error_at (DECL_SOURCE_LOCATION (func),
+                 "total size of local objects %wu exceeds maximum %wu",
+                 hwisize, limit);
+      else
+       error_at (DECL_SOURCE_LOCATION (func),
+                 "total size of local objects exceeds maximum %wu",
+                 limit);
+      return true;
     }
 
-  return FALSE;
+  return false;
 }
 
 /* Return the minimum spill slot alignment for a register of mode MODE.  */
@@ -284,48 +294,46 @@ get_stack_local_alignment (tree type, machine_mode mode)
    given a start/length pair that lies at the end of the frame.  */
 
 static bool
-try_fit_stack_local (HOST_WIDE_INT start, HOST_WIDE_INT length,
-                    HOST_WIDE_INT size, unsigned int alignment,
-                    HOST_WIDE_INT *poffset)
+try_fit_stack_local (poly_int64 start, poly_int64 length,
+                    poly_int64 size, unsigned int alignment,
+                    poly_int64_pod *poffset)
 {
-  HOST_WIDE_INT this_frame_offset;
+  poly_int64 this_frame_offset;
   int frame_off, frame_alignment, frame_phase;
 
   /* Calculate how many bytes the start of local variables is off from
      stack alignment.  */
   frame_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
-  frame_off = STARTING_FRAME_OFFSET % frame_alignment;
+  frame_off = targetm.starting_frame_offset () % frame_alignment;
   frame_phase = frame_off ? frame_alignment - frame_off : 0;
 
   /* Round the frame offset to the specified alignment.  */
 
-  /*  We must be careful here, since FRAME_OFFSET might be negative and
-      division with a negative dividend isn't as well defined as we might
-      like.  So we instead assume that ALIGNMENT is a power of two and
-      use logical operations which are unambiguous.  */
   if (FRAME_GROWS_DOWNWARD)
     this_frame_offset
-      = (FLOOR_ROUND (start + length - size - frame_phase,
-                     (unsigned HOST_WIDE_INT) alignment)
+      = (aligned_lower_bound (start + length - size - frame_phase, alignment)
         + frame_phase);
   else
     this_frame_offset
-      = (CEIL_ROUND (start - frame_phase,
-                    (unsigned HOST_WIDE_INT) alignment)
-        + frame_phase);
+      = aligned_upper_bound (start - frame_phase, alignment) + frame_phase;
 
   /* See if it fits.  If this space is at the edge of the frame,
      consider extending the frame to make it fit.  Our caller relies on
      this when allocating a new slot.  */
-  if (frame_offset == start && this_frame_offset < frame_offset)
-    frame_offset = this_frame_offset;
-  else if (this_frame_offset < start)
-    return false;
-  else if (start + length == frame_offset
-          && this_frame_offset + size > start + length)
-    frame_offset = this_frame_offset + size;
-  else if (this_frame_offset + size > start + length)
-    return false;
+  if (maybe_lt (this_frame_offset, start))
+    {
+      if (known_eq (frame_offset, start))
+       frame_offset = this_frame_offset;
+      else
+       return false;
+    }
+  else if (maybe_gt (this_frame_offset + size, start + length))
+    {
+      if (known_eq (frame_offset, start + length))
+       frame_offset = this_frame_offset + size;
+      else
+       return false;
+    }
 
   *poffset = this_frame_offset;
   return true;
@@ -336,9 +344,9 @@ try_fit_stack_local (HOST_WIDE_INT start, HOST_WIDE_INT length,
    function's frame_space_list.  */
 
 static void
-add_frame_space (HOST_WIDE_INT start, HOST_WIDE_INT end)
+add_frame_space (poly_int64 start, poly_int64 end)
 {
-  struct frame_space *space = ggc_alloc<frame_space> ();
+  class frame_space *space = ggc_alloc<frame_space> ();
   space->next = crtl->frame_space_list;
   crtl->frame_space_list = space;
   space->start = start;
@@ -363,12 +371,12 @@ add_frame_space (HOST_WIDE_INT start, HOST_WIDE_INT end)
    We do not round to stack_boundary here.  */
 
 rtx
-assign_stack_local_1 (machine_mode mode, HOST_WIDE_INT size,
+assign_stack_local_1 (machine_mode mode, poly_int64 size,
                      int align, int kind)
 {
   rtx x, addr;
-  int bigend_correction = 0;
-  HOST_WIDE_INT slot_offset = 0, old_frame_offset;
+  poly_int64 bigend_correction = 0;
+  poly_int64 slot_offset = 0, old_frame_offset;
   unsigned int alignment, alignment_in_bits;
 
   if (align == 0)
@@ -379,7 +387,7 @@ assign_stack_local_1 (machine_mode mode, HOST_WIDE_INT size,
   else if (align == -1)
     {
       alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
-      size = CEIL_ROUND (size, alignment);
+      size = aligned_upper_bound (size, alignment);
     }
   else if (align == -2)
     alignment = 1; /* BITS_PER_UNIT / BITS_PER_UNIT */
@@ -392,7 +400,7 @@ assign_stack_local_1 (machine_mode mode, HOST_WIDE_INT size,
   if (alignment_in_bits > MAX_SUPPORTED_STACK_ALIGNMENT)
     {
       alignment_in_bits = MAX_SUPPORTED_STACK_ALIGNMENT;
-      alignment = alignment_in_bits / BITS_PER_UNIT;
+      alignment = MAX_SUPPORTED_STACK_ALIGNMENT / BITS_PER_UNIT;
     }
 
   if (SUPPORTS_STACK_ALIGNMENT)
@@ -415,7 +423,7 @@ assign_stack_local_1 (machine_mode mode, HOST_WIDE_INT size,
                     requested size is 0 or the estimated stack
                     alignment >= mode alignment.  */
                  gcc_assert ((kind & ASLK_REDUCE_ALIGN)
-                             || size == 0
+                             || known_eq (size, 0)
                              || (crtl->stack_alignment_estimated
                                  >= GET_MODE_ALIGNMENT (mode)));
                  alignment_in_bits = crtl->stack_alignment_estimated;
@@ -430,22 +438,22 @@ assign_stack_local_1 (machine_mode mode, HOST_WIDE_INT size,
   if (crtl->max_used_stack_slot_alignment < alignment_in_bits)
     crtl->max_used_stack_slot_alignment = alignment_in_bits;
 
-  if (mode != BLKmode || size != 0)
+  if (mode != BLKmode || maybe_ne (size, 0))
     {
       if (kind & ASLK_RECORD_PAD)
        {
-         struct frame_space **psp;
+         class frame_space **psp;
 
          for (psp = &crtl->frame_space_list; *psp; psp = &(*psp)->next)
            {
-             struct frame_space *space = *psp;
+             class frame_space *space = *psp;
              if (!try_fit_stack_local (space->start, space->length, size,
                                        alignment, &slot_offset))
                continue;
              *psp = space->next;
-             if (slot_offset > space->start)
+             if (known_gt (slot_offset, space->start))
                add_frame_space (space->start, slot_offset);
-             if (slot_offset + size < space->start + space->length)
+             if (known_lt (slot_offset + size, space->start + space->length))
                add_frame_space (slot_offset + size,
                                 space->start + space->length);
              goto found_space;
@@ -467,9 +475,9 @@ assign_stack_local_1 (machine_mode mode, HOST_WIDE_INT size,
 
       if (kind & ASLK_RECORD_PAD)
        {
-         if (slot_offset > frame_offset)
+         if (known_gt (slot_offset, frame_offset))
            add_frame_space (frame_offset, slot_offset);
-         if (slot_offset + size < old_frame_offset)
+         if (known_lt (slot_offset + size, old_frame_offset))
            add_frame_space (slot_offset + size, old_frame_offset);
        }
     }
@@ -480,9 +488,9 @@ assign_stack_local_1 (machine_mode mode, HOST_WIDE_INT size,
 
       if (kind & ASLK_RECORD_PAD)
        {
-         if (slot_offset > old_frame_offset)
+         if (known_gt (slot_offset, old_frame_offset))
            add_frame_space (old_frame_offset, slot_offset);
-         if (slot_offset + size < frame_offset)
+         if (known_lt (slot_offset + size, frame_offset))
            add_frame_space (slot_offset + size, frame_offset);
        }
     }
@@ -490,8 +498,17 @@ assign_stack_local_1 (machine_mode mode, HOST_WIDE_INT size,
  found_space:
   /* On a big-endian machine, if we are allocating more space than we will use,
      use the least significant bytes of those that are allocated.  */
-  if (BYTES_BIG_ENDIAN && mode != BLKmode && GET_MODE_SIZE (mode) < size)
-    bigend_correction = size - GET_MODE_SIZE (mode);
+  if (mode != BLKmode)
+    {
+      /* The slot size can sometimes be smaller than the mode size;
+        e.g. the rs6000 port allocates slots with a vector mode
+        that have the size of only one element.  However, the slot
+        size must always be ordered wrt to the mode size, in the
+        same way as for a subreg.  */
+      gcc_checking_assert (ordered_p (GET_MODE_SIZE (mode), size));
+      if (BYTES_BIG_ENDIAN && maybe_lt (GET_MODE_SIZE (mode), size))
+       bigend_correction = size - GET_MODE_SIZE (mode);
+    }
 
   /* If we have already instantiated virtual registers, return the actual
      address relative to the frame pointer.  */
@@ -499,7 +516,7 @@ assign_stack_local_1 (machine_mode mode, HOST_WIDE_INT size,
     addr = plus_constant (Pmode, frame_pointer_rtx,
                          trunc_int_for_mode
                          (slot_offset + bigend_correction
-                          + STARTING_FRAME_OFFSET, Pmode));
+                          + targetm.starting_frame_offset (), Pmode));
   else
     addr = plus_constant (Pmode, virtual_stack_vars_rtx,
                          trunc_int_for_mode
@@ -521,7 +538,7 @@ assign_stack_local_1 (machine_mode mode, HOST_WIDE_INT size,
 /* Wrap up assign_stack_local_1 with last parameter as false.  */
 
 rtx
-assign_stack_local (machine_mode mode, HOST_WIDE_INT size, int align)
+assign_stack_local (machine_mode mode, poly_int64 size, int align)
 {
   return assign_stack_local_1 (mode, size, align, ASLK_RECORD_PAD);
 }
@@ -540,15 +557,16 @@ assign_stack_local (machine_mode mode, HOST_WIDE_INT size, int align)
    result, all temporaries are preserved.  A temporary is preserved by
    pretending it was allocated at the previous nesting level.  */
 
-struct GTY(()) temp_slot {
+class GTY(()) temp_slot {
+public:
   /* Points to next temporary slot.  */
-  struct temp_slot *next;
+  class temp_slot *next;
   /* Points to previous temporary slot.  */
-  struct temp_slot *prev;
+  class temp_slot *prev;
   /* The rtx to used to reference the slot.  */
   rtx slot;
   /* The size, in units, of the slot.  */
-  HOST_WIDE_INT size;
+  poly_int64 size;
   /* The type of the object in the slot, or zero if it doesn't correspond
      to a type.  We use this to determine whether a slot can be reused.
      It can be reused if objects of the type of the new slot will always
@@ -562,17 +580,17 @@ struct GTY(()) temp_slot {
   int level;
   /* The offset of the slot from the frame_pointer, including extra space
      for alignment.  This info is for combine_temp_slots.  */
-  HOST_WIDE_INT base_offset;
+  poly_int64 base_offset;
   /* The size of the slot, including extra space for alignment.  This
      info is for combine_temp_slots.  */
-  HOST_WIDE_INT full_size;
+  poly_int64 full_size;
 };
 
 /* Entry for the below hash table.  */
 struct GTY((for_user)) temp_slot_address_entry {
   hashval_t hash;
   rtx address;
-  struct temp_slot *temp_slot;
+  class temp_slot *temp_slot;
 };
 
 struct temp_address_hasher : ggc_ptr_hash<temp_slot_address_entry>
@@ -589,7 +607,7 @@ static size_t n_temp_slots_in_use;
 /* Removes temporary slot TEMP from LIST.  */
 
 static void
-cut_slot_from_list (struct temp_slot *temp, struct temp_slot **list)
+cut_slot_from_list (class temp_slot *temp, class temp_slot **list)
 {
   if (temp->next)
     temp->next->prev = temp->prev;
@@ -604,7 +622,7 @@ cut_slot_from_list (struct temp_slot *temp, struct temp_slot **list)
 /* Inserts temporary slot TEMP to LIST.  */
 
 static void
-insert_slot_to_list (struct temp_slot *temp, struct temp_slot **list)
+insert_slot_to_list (class temp_slot *temp, class temp_slot **list)
 {
   temp->next = *list;
   if (*list)
@@ -615,7 +633,7 @@ insert_slot_to_list (struct temp_slot *temp, struct temp_slot **list)
 
 /* Returns the list of used temp slots at LEVEL.  */
 
-static struct temp_slot **
+static class temp_slot **
 temp_slots_at_level (int level)
 {
   if (level >= (int) vec_safe_length (used_temp_slots))
@@ -638,7 +656,7 @@ max_slot_level (void)
 /* Moves temporary slot TEMP to LEVEL.  */
 
 static void
-move_slot_to_level (struct temp_slot *temp, int level)
+move_slot_to_level (class temp_slot *temp, int level)
 {
   cut_slot_from_list (temp, temp_slots_at_level (temp->level));
   insert_slot_to_list (temp, temp_slots_at_level (level));
@@ -648,7 +666,7 @@ move_slot_to_level (struct temp_slot *temp, int level)
 /* Make temporary slot TEMP available.  */
 
 static void
-make_slot_available (struct temp_slot *temp)
+make_slot_available (class temp_slot *temp)
 {
   cut_slot_from_list (temp, temp_slots_at_level (temp->level));
   insert_slot_to_list (temp, &avail_temp_slots);
@@ -684,10 +702,10 @@ temp_address_hasher::equal (temp_slot_address_entry *t1,
 
 /* Add ADDRESS as an alias of TEMP_SLOT to the addess -> temp slot mapping.  */
 static void
-insert_temp_slot_address (rtx address, struct temp_slot *temp_slot)
+insert_temp_slot_address (rtx address, class temp_slot *temp_slot)
 {
   struct temp_slot_address_entry *t = ggc_alloc<temp_slot_address_entry> ();
-  t->address = address;
+  t->address = copy_rtx (address);
   t->temp_slot = temp_slot;
   t->hash = temp_slot_address_compute_hash (t);
   *temp_slot_address_table->find_slot_with_hash (t, t->hash, INSERT) = t;
@@ -718,10 +736,10 @@ remove_unused_temp_slot_addresses (void)
 
 /* Find the temp slot corresponding to the object at address X.  */
 
-static struct temp_slot *
+static class temp_slot *
 find_temp_slot_from_address (rtx x)
 {
-  struct temp_slot *p;
+  class temp_slot *p;
   struct temp_slot_address_entry tmp, *t;
 
   /* First try the easy way:
@@ -743,18 +761,14 @@ find_temp_slot_from_address (rtx x)
     return p;
 
   /* Last resort: Address is a virtual stack var address.  */
-  if (GET_CODE (x) == PLUS
-      && XEXP (x, 0) == virtual_stack_vars_rtx
-      && CONST_INT_P (XEXP (x, 1)))
+  poly_int64 offset;
+  if (strip_offset (x, &offset) == virtual_stack_vars_rtx)
     {
       int i;
       for (i = max_slot_level (); i >= 0; i--)
        for (p = *temp_slots_at_level (i); p; p = p->next)
-         {
-           if (INTVAL (XEXP (x, 1)) >= p->base_offset
-               && INTVAL (XEXP (x, 1)) < p->base_offset + p->full_size)
-             return p;
-         }
+         if (known_in_range_p (offset, p->base_offset, p->full_size))
+           return p;
     }
 
   return NULL;
@@ -771,16 +785,13 @@ find_temp_slot_from_address (rtx x)
    TYPE is the type that will be used for the stack slot.  */
 
 rtx
-assign_stack_temp_for_type (machine_mode mode, HOST_WIDE_INT size,
-                           tree type)
+assign_stack_temp_for_type (machine_mode mode, poly_int64 size, tree type)
 {
   unsigned int align;
-  struct temp_slot *p, *best_p = 0, *selected = NULL, **pp;
+  class temp_slot *p, *best_p = 0, *selected = NULL, **pp;
   rtx slot;
 
-  /* If SIZE is -1 it means that somebody tried to allocate a temporary
-     of a variable size.  */
-  gcc_assert (size != -1);
+  gcc_assert (known_size_p (size));
 
   align = get_stack_local_alignment (type, mode);
 
@@ -795,13 +806,16 @@ assign_stack_temp_for_type (machine_mode mode, HOST_WIDE_INT size,
     {
       for (p = avail_temp_slots; p; p = p->next)
        {
-         if (p->align >= align && p->size >= size
+         if (p->align >= align
+             && known_ge (p->size, size)
              && GET_MODE (p->slot) == mode
              && objects_must_conflict_p (p->type, type)
-             && (best_p == 0 || best_p->size > p->size
-                 || (best_p->size == p->size && best_p->align > p->align)))
+             && (best_p == 0
+                 || (known_eq (best_p->size, p->size)
+                     ? best_p->align > p->align
+                     : known_ge (best_p->size, p->size))))
            {
-             if (p->align == align && p->size == size)
+             if (p->align == align && known_eq (p->size, size))
                {
                  selected = p;
                  cut_slot_from_list (selected, &avail_temp_slots);
@@ -825,9 +839,9 @@ assign_stack_temp_for_type (machine_mode mode, HOST_WIDE_INT size,
       if (GET_MODE (best_p->slot) == BLKmode)
        {
          int alignment = best_p->align / BITS_PER_UNIT;
-         HOST_WIDE_INT rounded_size = CEIL_ROUND (size, alignment);
+         poly_int64 rounded_size = aligned_upper_bound (size, alignment);
 
-         if (best_p->size - rounded_size >= alignment)
+         if (known_ge (best_p->size - rounded_size, alignment))
            {
              p = ggc_alloc<temp_slot> ();
              p->in_use = 0;
@@ -850,7 +864,7 @@ assign_stack_temp_for_type (machine_mode mode, HOST_WIDE_INT size,
   /* If we still didn't find one, make a new temporary.  */
   if (selected == 0)
     {
-      HOST_WIDE_INT frame_offset_old = frame_offset;
+      poly_int64 frame_offset_old = frame_offset;
 
       p = ggc_alloc<temp_slot> ();
 
@@ -864,9 +878,9 @@ assign_stack_temp_for_type (machine_mode mode, HOST_WIDE_INT size,
       gcc_assert (mode != BLKmode || align == BIGGEST_ALIGNMENT);
       p->slot = assign_stack_local_1 (mode,
                                      (mode == BLKmode
-                                      ? CEIL_ROUND (size,
-                                                    (int) align
-                                                    / BITS_PER_UNIT)
+                                      ? aligned_upper_bound (size,
+                                                             (int) align
+                                                             / BITS_PER_UNIT)
                                       : size),
                                      align, 0);
 
@@ -931,7 +945,7 @@ assign_stack_temp_for_type (machine_mode mode, HOST_WIDE_INT size,
    reuse.  First two arguments are same as in preceding function.  */
 
 rtx
-assign_stack_temp (machine_mode mode, HOST_WIDE_INT size)
+assign_stack_temp (machine_mode mode, poly_int64 size)
 {
   return assign_stack_temp_for_type (mode, size, NULL_TREE);
 }
@@ -971,25 +985,26 @@ assign_temp (tree type_or_decl, int memory_required,
 
   if (mode == BLKmode || memory_required)
     {
-      HOST_WIDE_INT size = int_size_in_bytes (type);
+      poly_int64 size;
       rtx tmp;
 
-      /* Zero sized arrays are GNU C extension.  Set size to 1 to avoid
-        problems with allocating the stack space.  */
-      if (size == 0)
-       size = 1;
-
       /* Unfortunately, we don't yet know how to allocate variable-sized
         temporaries.  However, sometimes we can find a fixed upper limit on
         the size, so try that instead.  */
-      else if (size == -1)
+      if (!poly_int_tree_p (TYPE_SIZE_UNIT (type), &size))
        size = max_int_size_in_bytes (type);
 
+      /* Zero sized arrays are a GNU C extension.  Set size to 1 to avoid
+        problems with allocating the stack space.  */
+      if (known_eq (size, 0))
+       size = 1;
+
       /* The size of the temporary may be too large to fit into an integer.  */
       /* ??? Not sure this should happen except for user silliness, so limit
         this to things that aren't compiler-generated temporaries.  The
         rest of the time we'll die in assign_stack_temp_for_type.  */
-      if (decl && size == -1
+      if (decl
+         && !known_size_p (size)
          && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST)
        {
          error ("size of variable %q+D is too large", decl);
@@ -1017,7 +1032,7 @@ assign_temp (tree type_or_decl, int memory_required,
 static void
 combine_temp_slots (void)
 {
-  struct temp_slot *p, *q, *next, *next_q;
+  class temp_slot *p, *q, *next, *next_q;
   int num_slots;
 
   /* We can't combine slots, because the information about which slot
@@ -1050,14 +1065,14 @@ combine_temp_slots (void)
          if (GET_MODE (q->slot) != BLKmode)
            continue;
 
-         if (p->base_offset + p->full_size == q->base_offset)
+         if (known_eq (p->base_offset + p->full_size, q->base_offset))
            {
              /* Q comes after P; combine Q into P.  */
              p->size += q->size;
              p->full_size += q->full_size;
              delete_q = 1;
            }
-         else if (q->base_offset + q->full_size == p->base_offset)
+         else if (known_eq (q->base_offset + q->full_size, p->base_offset))
            {
              /* P comes after Q; combine P into Q.  */
              q->size += p->size;
@@ -1081,7 +1096,7 @@ combine_temp_slots (void)
 void
 update_temp_slot_address (rtx old_rtx, rtx new_rtx)
 {
-  struct temp_slot *p;
+  class temp_slot *p;
 
   if (rtx_equal_p (old_rtx, new_rtx))
     return;
@@ -1135,7 +1150,7 @@ update_temp_slot_address (rtx old_rtx, rtx new_rtx)
 void
 preserve_temp_slots (rtx x)
 {
-  struct temp_slot *p = 0, *next;
+  class temp_slot *p = 0, *next;
 
   if (x == 0)
     return;
@@ -1175,7 +1190,7 @@ preserve_temp_slots (rtx x)
 void
 free_temp_slots (void)
 {
-  struct temp_slot *p, *next;
+  class temp_slot *p, *next;
   bool some_available = false;
 
   for (p = *temp_slots_at_level (temp_slot_level); p; p = next)
@@ -1362,11 +1377,11 @@ initial_value_entry (int i, rtx *hreg, rtx *preg)
    routines.  They contain the offsets of the virtual registers from their
    respective hard registers.  */
 
-static int in_arg_offset;
-static int var_offset;
-static int dynamic_offset;
-static int out_arg_offset;
-static int cfa_offset;
+static poly_int64 in_arg_offset;
+static poly_int64 var_offset;
+static poly_int64 dynamic_offset;
+static poly_int64 out_arg_offset;
+static poly_int64 cfa_offset;
 
 /* In most machines, the stack pointer register is equivalent to the bottom
    of the stack.  */
@@ -1402,7 +1417,7 @@ static int cfa_offset;
   : 0) + (STACK_POINTER_OFFSET))
 #else
 #define STACK_DYNAMIC_OFFSET(FNDECL)   \
-((ACCUMULATE_OUTGOING_ARGS ? crtl->outgoing_args_size : 0)           \
+  ((ACCUMULATE_OUTGOING_ARGS ? crtl->outgoing_args_size : poly_int64 (0)) \
  + (STACK_POINTER_OFFSET))
 #endif
 #endif
@@ -1413,10 +1428,10 @@ static int cfa_offset;
    offset indirectly through the pointer.  Otherwise, return 0.  */
 
 static rtx
-instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset)
+instantiate_new_reg (rtx x, poly_int64_pod *poffset)
 {
   rtx new_rtx;
-  HOST_WIDE_INT offset;
+  poly_int64 offset;
 
   if (x == virtual_incoming_args_rtx)
     {
@@ -1475,7 +1490,7 @@ instantiate_virtual_regs_in_rtx (rtx *loc)
       if (rtx x = *loc)
        {
          rtx new_rtx;
-         HOST_WIDE_INT offset;
+         poly_int64 offset;
          switch (GET_CODE (x))
            {
            case REG:
@@ -1528,7 +1543,7 @@ safe_insn_predicate (int code, int operand, rtx x)
 static void
 instantiate_virtual_regs_in_insn (rtx_insn *insn)
 {
-  HOST_WIDE_INT offset;
+  poly_int64 offset;
   int insn_code, i;
   bool any_change = false;
   rtx set, new_rtx, x;
@@ -1567,7 +1582,8 @@ instantiate_virtual_regs_in_insn (rtx_insn *insn)
         to the generic case is avoiding a new pseudo and eliminating a
         move insn in the initial rtl stream.  */
       new_rtx = instantiate_new_reg (SET_SRC (set), &offset);
-      if (new_rtx && offset != 0
+      if (new_rtx
+         && maybe_ne (offset, 0)
          && REG_P (SET_DEST (set))
          && REGNO (SET_DEST (set)) > LAST_VIRTUAL_REGISTER)
        {
@@ -1593,17 +1609,18 @@ instantiate_virtual_regs_in_insn (rtx_insn *insn)
 
       /* Handle a plus involving a virtual register by determining if the
         operands remain valid if they're modified in place.  */
+      poly_int64 delta;
       if (GET_CODE (SET_SRC (set)) == PLUS
          && recog_data.n_operands >= 3
          && recog_data.operand_loc[1] == &XEXP (SET_SRC (set), 0)
          && recog_data.operand_loc[2] == &XEXP (SET_SRC (set), 1)
-         && CONST_INT_P (recog_data.operand[2])
+         && poly_int_rtx_p (recog_data.operand[2], &delta)
          && (new_rtx = instantiate_new_reg (recog_data.operand[1], &offset)))
        {
-         offset += INTVAL (recog_data.operand[2]);
+         offset += delta;
 
          /* If the sum is zero, then replace with a plain move.  */
-         if (offset == 0
+         if (known_eq (offset, 0)
              && REG_P (SET_DEST (set))
              && REGNO (SET_DEST (set)) > LAST_VIRTUAL_REGISTER)
            {
@@ -1681,7 +1698,7 @@ instantiate_virtual_regs_in_insn (rtx_insn *insn)
          new_rtx = instantiate_new_reg (x, &offset);
          if (new_rtx == NULL)
            continue;
-         if (offset == 0)
+         if (known_eq (offset, 0))
            x = new_rtx;
          else
            {
@@ -1706,7 +1723,7 @@ instantiate_virtual_regs_in_insn (rtx_insn *insn)
          new_rtx = instantiate_new_reg (SUBREG_REG (x), &offset);
          if (new_rtx == NULL)
            continue;
-         if (offset != 0)
+         if (maybe_ne (offset, 0))
            {
              start_sequence ();
              new_rtx = expand_simple_binop
@@ -1930,7 +1947,7 @@ instantiate_virtual_regs (void)
 
   /* Compute the offsets to use for this function.  */
   in_arg_offset = FIRST_PARM_OFFSET (current_function_decl);
-  var_offset = STARTING_FRAME_OFFSET;
+  var_offset = targetm.starting_frame_offset ();
   dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl);
   out_arg_offset = STACK_POINTER_OFFSET;
 #ifdef FRAME_POINTER_CFA_OFFSET
@@ -1951,10 +1968,11 @@ instantiate_virtual_regs (void)
           Fortunately, they shouldn't contain virtual registers either.  */
         if (GET_CODE (PATTERN (insn)) == USE
            || GET_CODE (PATTERN (insn)) == CLOBBER
-           || GET_CODE (PATTERN (insn)) == ASM_INPUT)
+           || GET_CODE (PATTERN (insn)) == ASM_INPUT
+           || DEBUG_MARKER_INSN_P (insn))
          continue;
-       else if (DEBUG_INSN_P (insn))
-         instantiate_virtual_regs_in_rtx (&INSN_VAR_LOCATION (insn));
+       else if (DEBUG_BIND_INSN_P (insn))
+         instantiate_virtual_regs_in_rtx (INSN_VAR_LOCATION_PTR (insn));
        else
          instantiate_virtual_regs_in_insn (insn);
 
@@ -2084,6 +2102,9 @@ aggregate_value_p (const_tree exp, const_tree fntype)
   if (TREE_ADDRESSABLE (type))
     return 1;
 
+  if (TYPE_EMPTY_P (type))
+    return 0;
+
   if (flag_pcc_struct_return && AGGREGATE_TYPE_P (type))
     return 1;
 
@@ -2099,10 +2120,17 @@ aggregate_value_p (const_tree exp, const_tree fntype)
   if (!REG_P (reg))
     return 0;
 
+  /* Use the default ABI if the type of the function isn't known.
+     The scheme for handling interoperability between different ABIs
+     requires us to be able to tell when we're calling a function with
+     a nondefault ABI.  */
+  const predefined_function_abi &abi = (fntype
+                                       ? fntype_abi (fntype)
+                                       : default_function_abi);
   regno = REGNO (reg);
   nregs = hard_regno_nregs (regno, TYPE_MODE (type));
   for (i = 0; i < nregs; i++)
-    if (! call_used_regs[regno + i])
+    if (!fixed_regs[regno + i] && !abi.clobbers_full_reg_p (regno + i))
       return 1;
 
   return 0;
@@ -2187,14 +2215,6 @@ use_register_for_decl (const_tree 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;
@@ -2252,27 +2272,13 @@ struct assign_parm_data_all
 struct assign_parm_data_one
 {
   tree nominal_type;
-  tree passed_type;
+  function_arg_info arg;
   rtx entry_parm;
   rtx stack_parm;
   machine_mode nominal_mode;
   machine_mode passed_mode;
-  machine_mode promoted_mode;
   struct locate_and_pad_arg_data locate;
   int partial;
-  BOOL_BITFIELD named_arg : 1;
-  BOOL_BITFIELD passed_pointer : 1;
-  BOOL_BITFIELD on_stack : 1;
-  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.  */
@@ -2389,23 +2395,6 @@ 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.  */
@@ -2423,24 +2412,22 @@ static void
 assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm,
                             struct assign_parm_data_one *data)
 {
-  tree nominal_type, passed_type;
-  machine_mode nominal_mode, passed_mode, promoted_mode;
   int unsignedp;
 
-  memset (data, 0, sizeof (*data));
+  *data = assign_parm_data_one ();
 
   /* NAMED_ARG is a misnomer.  We really mean 'non-variadic'. */
   if (!cfun->stdarg)
-    data->named_arg = 1;  /* No variadic parms.  */
+    data->arg.named = 1;  /* No variadic parms.  */
   else if (DECL_CHAIN (parm))
-    data->named_arg = 1;  /* Not the last non-variadic parm. */
+    data->arg.named = 1;  /* Not the last non-variadic parm. */
   else if (targetm.calls.strict_argument_naming (all->args_so_far))
-    data->named_arg = 1;  /* Only variadic ones are unnamed.  */
+    data->arg.named = 1;  /* Only variadic ones are unnamed.  */
   else
-    data->named_arg = 0;  /* Treat as variadic.  */
+    data->arg.named = 0;  /* Treat as variadic.  */
 
-  nominal_type = TREE_TYPE (parm);
-  passed_type = DECL_ARG_TYPE (parm);
+  data->nominal_type = TREE_TYPE (parm);
+  data->arg.type = DECL_ARG_TYPE (parm);
 
   /* Look out for errors propagating this far.  Also, if the parameter's
      type is void then its value doesn't matter.  */
@@ -2448,47 +2435,38 @@ assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm,
       /* This can happen after weird syntax errors
         or if an enum type is defined among the parms.  */
       || TREE_CODE (parm) != PARM_DECL
-      || passed_type == NULL
-      || VOID_TYPE_P (nominal_type))
+      || data->arg.type == NULL
+      || VOID_TYPE_P (data->nominal_type))
     {
-      nominal_type = passed_type = void_type_node;
-      nominal_mode = passed_mode = promoted_mode = VOIDmode;
-      goto egress;
+      data->nominal_type = data->arg.type = void_type_node;
+      data->nominal_mode = data->passed_mode = data->arg.mode = VOIDmode;
+      return;
     }
 
   /* Find mode of arg as it is passed, and mode of arg as it should be
      during execution of this function.  */
-  passed_mode = TYPE_MODE (passed_type);
-  nominal_mode = TYPE_MODE (nominal_type);
+  data->passed_mode = data->arg.mode = TYPE_MODE (data->arg.type);
+  data->nominal_mode = TYPE_MODE (data->nominal_type);
 
   /* If the parm is to be passed as a transparent union or record, use the
      type of the first field for the tests below.  We have already verified
      that the modes are the same.  */
-  if ((TREE_CODE (passed_type) == UNION_TYPE
-       || TREE_CODE (passed_type) == RECORD_TYPE)
-      && TYPE_TRANSPARENT_AGGR (passed_type))
-    passed_type = TREE_TYPE (first_field (passed_type));
+  if (RECORD_OR_UNION_TYPE_P (data->arg.type)
+      && TYPE_TRANSPARENT_AGGR (data->arg.type))
+    data->arg.type = TREE_TYPE (first_field (data->arg.type));
 
   /* See if this arg was passed by invisible reference.  */
-  if (pass_by_reference (&all->args_so_far_v, passed_mode,
-                        passed_type, data->named_arg))
+  if (apply_pass_by_reference_rules (&all->args_so_far_v, data->arg))
     {
-      passed_type = nominal_type = build_pointer_type (passed_type);
-      data->passed_pointer = true;
-      passed_mode = nominal_mode = TYPE_MODE (nominal_type);
+      data->nominal_type = data->arg.type;
+      data->passed_mode = data->nominal_mode = data->arg.mode;
     }
 
   /* Find mode as it is passed by the ABI.  */
-  unsignedp = TYPE_UNSIGNED (passed_type);
-  promoted_mode = promote_function_mode (passed_type, passed_mode, &unsignedp,
-                                        TREE_TYPE (current_function_decl), 0);
-
- egress:
-  data->nominal_type = nominal_type;
-  data->passed_type = passed_type;
-  data->nominal_mode = nominal_mode;
-  data->passed_mode = passed_mode;
-  data->promoted_mode = promoted_mode;
+  unsignedp = TYPE_UNSIGNED (data->arg.type);
+  data->arg.mode
+    = promote_function_mode (data->arg.type, data->arg.mode, &unsignedp,
+                            TREE_TYPE (current_function_decl), 0);
 }
 
 /* A subroutine of assign_parms.  Invoke setup_incoming_varargs.  */
@@ -2499,9 +2477,9 @@ assign_parms_setup_varargs (struct assign_parm_data_all *all,
 {
   int varargs_pretend_bytes = 0;
 
-  targetm.calls.setup_incoming_varargs (all->args_so_far,
-                                       data->promoted_mode,
-                                       data->passed_type,
+  function_arg_info last_named_arg = data->arg;
+  last_named_arg.named = true;
+  targetm.calls.setup_incoming_varargs (all->args_so_far, last_named_arg,
                                        &varargs_pretend_bytes, no_rtl);
 
   /* If the back-end has requested extra stack space, record how much is
@@ -2522,19 +2500,19 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all,
   rtx entry_parm;
   bool in_regs;
 
-  if (data->promoted_mode == VOIDmode)
+  if (data->arg.mode == VOIDmode)
     {
       data->entry_parm = data->stack_parm = const0_rtx;
       return;
     }
 
-  entry_parm = targetm.calls.function_incoming_arg (all->args_so_far,
-                                                   data->promoted_mode,
-                                                   data->passed_type,
-                                                   data->named_arg);
+  targetm.calls.warn_parameter_passing_abi (all->args_so_far,
+                                           data->arg.type);
 
+  entry_parm = targetm.calls.function_incoming_arg (all->args_so_far,
+                                                   data->arg);
   if (entry_parm == 0)
-    data->promoted_mode = data->passed_mode;
+    data->arg.mode = data->passed_mode;
 
   /* Determine parm's home in the stack, in case it arrives in the stack
      or we should pretend it did.  Compute the stack position and rtx where
@@ -2546,36 +2524,33 @@ 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) || POINTER_BOUNDS_TYPE_P (data->passed_type);
+  in_regs = (entry_parm != 0);
 #ifdef STACK_PARMS_IN_REG_PARM_AREA
   in_regs = true;
 #endif
-  if (!in_regs && !data->named_arg)
+  if (!in_regs && !data->arg.named)
     {
       if (targetm.calls.pretend_outgoing_varargs_named (all->args_so_far))
        {
          rtx tem;
+         function_arg_info named_arg = data->arg;
+         named_arg.named = true;
          tem = targetm.calls.function_incoming_arg (all->args_so_far,
-                                                    data->promoted_mode,
-                                                    data->passed_type, true);
+                                                    named_arg);
          in_regs = tem != NULL;
        }
     }
 
   /* If this parameter was passed both in registers and in the stack, use
      the copy on the stack.  */
-  if (targetm.calls.must_pass_in_stack (data->promoted_mode,
-                                       data->passed_type))
+  if (targetm.calls.must_pass_in_stack (data->arg))
     entry_parm = 0;
 
   if (entry_parm)
     {
       int partial;
 
-      partial = targetm.calls.arg_partial_bytes (all->args_so_far,
-                                                data->promoted_mode,
-                                                data->passed_type,
-                                                data->named_arg);
+      partial = targetm.calls.arg_partial_bytes (all->args_so_far, data->arg);
       data->partial = partial;
 
       /* The caller might already have allocated stack space for the
@@ -2610,7 +2585,7 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all,
        }
     }
 
-  locate_and_pad_parm (data->promoted_mode, data->passed_type, in_regs,
+  locate_and_pad_parm (data->arg.mode, data->arg.type, in_regs,
                       all->reg_parm_stack_space,
                       entry_parm ? data->partial : 0, current_function_decl,
                       &all->stack_args_size, &data->locate);
@@ -2635,12 +2610,8 @@ 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.  */
-  else if (data->entry_parm == NULL)
+  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.  */
@@ -2685,22 +2656,22 @@ assign_parm_find_stack_rtl (tree parm, struct assign_parm_data_one *data)
   stack_parm = crtl->args.internal_arg_pointer;
   if (offset_rtx != const0_rtx)
     stack_parm = gen_rtx_PLUS (Pmode, stack_parm, offset_rtx);
-  stack_parm = gen_rtx_MEM (data->promoted_mode, stack_parm);
+  stack_parm = gen_rtx_MEM (data->arg.mode, stack_parm);
 
-  if (!data->passed_pointer)
+  if (!data->arg.pass_by_reference)
     {
       set_mem_attributes (stack_parm, parm, 1);
       /* set_mem_attributes could set MEM_SIZE to the passed mode's size,
         while promoted mode's size is needed.  */
-      if (data->promoted_mode != BLKmode
-         && data->promoted_mode != DECL_MODE (parm))
+      if (data->arg.mode != BLKmode
+         && data->arg.mode != DECL_MODE (parm))
        {
-         set_mem_size (stack_parm, GET_MODE_SIZE (data->promoted_mode));
+         set_mem_size (stack_parm, GET_MODE_SIZE (data->arg.mode));
          if (MEM_EXPR (stack_parm) && MEM_OFFSET_KNOWN_P (stack_parm))
            {
-             int offset = subreg_lowpart_offset (DECL_MODE (parm),
-                                                 data->promoted_mode);
-             if (offset)
+             poly_int64 offset = subreg_lowpart_offset (DECL_MODE (parm),
+                                                        data->arg.mode);
+             if (maybe_ne (offset, 0))
                set_mem_offset (stack_parm, MEM_OFFSET (stack_parm) - offset);
            }
        }
@@ -2713,12 +2684,30 @@ assign_parm_find_stack_rtl (tree parm, struct assign_parm_data_one *data)
      is TARGET_FUNCTION_ARG_BOUNDARY.  If we're using slot_offset, we're
      intentionally forcing upward padding.  Otherwise we have to come
      up with a guess at the alignment based on OFFSET_RTX.  */
-  if (data->locate.where_pad != PAD_DOWNWARD || data->entry_parm)
+  poly_int64 offset;
+  if (data->locate.where_pad == PAD_NONE || data->entry_parm)
     align = boundary;
-  else if (CONST_INT_P (offset_rtx))
+  else if (data->locate.where_pad == PAD_UPWARD)
+    {
+      align = boundary;
+      /* If the argument offset is actually more aligned than the nominal
+        stack slot boundary, take advantage of that excess alignment.
+        Don't make any assumptions if STACK_POINTER_OFFSET is in use.  */
+      if (poly_int_rtx_p (offset_rtx, &offset)
+         && known_eq (STACK_POINTER_OFFSET, 0))
+       {
+         unsigned int offset_align = known_alignment (offset) * BITS_PER_UNIT;
+         if (offset_align == 0 || offset_align > STACK_BOUNDARY)
+           offset_align = STACK_BOUNDARY;
+         align = MAX (align, offset_align);
+       }
+    }
+  else if (poly_int_rtx_p (offset_rtx, &offset))
     {
-      align = INTVAL (offset_rtx) * BITS_PER_UNIT | boundary;
-      align = least_bit_hwi (align);
+      align = least_bit_hwi (boundary);
+      unsigned int offset_align = known_alignment (offset) * BITS_PER_UNIT;
+      if (offset_align != 0)
+       align = MIN (align, offset_align);
     }
   set_mem_align (stack_parm, align);
 
@@ -2748,8 +2737,7 @@ assign_parm_adjust_entry_rtl (struct assign_parm_data_one *data)
         locations.  The Irix 6 ABI has examples of this.  */
       if (GET_CODE (entry_parm) == PARALLEL)
        emit_group_store (validize_mem (copy_rtx (stack_parm)), entry_parm,
-                         data->passed_type,
-                         int_size_in_bytes (data->passed_type));
+                         data->arg.type, int_size_in_bytes (data->arg.type));
       else
        {
          gcc_assert (data->partial % UNITS_PER_WORD == 0);
@@ -2805,7 +2793,7 @@ assign_parm_remove_parallels (struct assign_parm_data_one *data)
   if (GET_CODE (entry_parm) == PARALLEL && GET_MODE (entry_parm) != BLKmode)
     {
       rtx parmreg = gen_reg_rtx (GET_MODE (entry_parm));
-      emit_group_store (parmreg, entry_parm, data->passed_type,
+      emit_group_store (parmreg, entry_parm, data->arg.type,
                        GET_MODE_SIZE (GET_MODE (entry_parm)));
       entry_parm = parmreg;
     }
@@ -2825,8 +2813,11 @@ assign_parm_adjust_stack_rtl (struct assign_parm_data_one *data)
      ultimate type, don't use that slot after entry.  We'll make another
      stack slot, if we need one.  */
   if (stack_parm
-      && ((STRICT_ALIGNMENT
-          && GET_MODE_ALIGNMENT (data->nominal_mode) > MEM_ALIGN (stack_parm))
+      && ((GET_MODE_ALIGNMENT (data->nominal_mode) > MEM_ALIGN (stack_parm)
+          && ((optab_handler (movmisalign_optab, data->nominal_mode)
+               != CODE_FOR_nothing)
+              || targetm.slow_unaligned_access (data->nominal_mode,
+                                                MEM_ALIGN (stack_parm))))
          || (data->nominal_type
              && TYPE_ALIGN (data->nominal_type) > MEM_ALIGN (stack_parm)
              && MEM_ALIGN (stack_parm) < PREFERRED_STACK_BOUNDARY)))
@@ -2843,7 +2834,7 @@ assign_parm_adjust_stack_rtl (struct assign_parm_data_one *data)
      pointers in their passed stack slots.  */
   else if (crtl->stack_protect_guard
           && (flag_stack_protect == 2
-              || data->passed_pointer
+              || data->arg.pass_by_reference
               || POINTER_TYPE_P (data->nominal_type)))
     stack_parm = NULL;
 
@@ -2865,8 +2856,8 @@ assign_parm_setup_block_p (struct assign_parm_data_one *data)
   /* Only assign_parm_setup_block knows how to deal with register arguments
      that are padded at the least significant end.  */
   if (REG_P (data->entry_parm)
-      && GET_MODE_SIZE (data->promoted_mode) < UNITS_PER_WORD
-      && (BLOCK_REG_PADDING (data->passed_mode, data->passed_type, 1)
+      && known_lt (GET_MODE_SIZE (data->arg.mode), UNITS_PER_WORD)
+      && (BLOCK_REG_PADDING (data->passed_mode, data->arg.type, 1)
          == (BYTES_BIG_ENDIAN ? PAD_UPWARD : PAD_DOWNWARD)))
     return true;
 #endif
@@ -2921,14 +2912,31 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
       data->stack_parm = NULL;
     }
 
-  size = int_size_in_bytes (data->passed_type);
+  size = int_size_in_bytes (data->arg.type);
   size_stored = CEIL_ROUND (size, UNITS_PER_WORD);
   if (stack_parm == 0)
     {
-      SET_DECL_ALIGN (parm, MAX (DECL_ALIGN (parm), BITS_PER_WORD));
-      stack_parm = assign_stack_local (BLKmode, size_stored,
-                                      DECL_ALIGN (parm));
-      if (GET_MODE_SIZE (GET_MODE (entry_parm)) == size)
+      HOST_WIDE_INT parm_align
+       = (STRICT_ALIGNMENT
+          ? MAX (DECL_ALIGN (parm), BITS_PER_WORD) : DECL_ALIGN (parm));
+
+      SET_DECL_ALIGN (parm, parm_align);
+      if (DECL_ALIGN (parm) > MAX_SUPPORTED_STACK_ALIGNMENT)
+       {
+         rtx allocsize = gen_int_mode (size_stored, Pmode);
+         get_dynamic_stack_size (&allocsize, 0, DECL_ALIGN (parm), NULL);
+         stack_parm = assign_stack_local (BLKmode, UINTVAL (allocsize),
+                                          MAX_SUPPORTED_STACK_ALIGNMENT);
+         rtx addr = align_dynamic_address (XEXP (stack_parm, 0),
+                                           DECL_ALIGN (parm));
+         mark_reg_pointer (addr, DECL_ALIGN (parm));
+         stack_parm = gen_rtx_MEM (GET_MODE (stack_parm), addr);
+         MEM_NOTRAP_P (stack_parm) = 1;
+       }
+      else
+       stack_parm = assign_stack_local (BLKmode, size_stored,
+                                        DECL_ALIGN (parm));
+      if (known_eq (GET_MODE_SIZE (GET_MODE (entry_parm)), size))
        PUT_MODE (stack_parm, GET_MODE (entry_parm));
       set_mem_attributes (stack_parm, parm, 1);
     }
@@ -2959,12 +2967,12 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
 
       /* Handle values in multiple non-contiguous locations.  */
       if (GET_CODE (entry_parm) == PARALLEL && !MEM_P (mem))
-       emit_group_store (mem, entry_parm, data->passed_type, size);
+       emit_group_store (mem, entry_parm, data->arg.type, size);
       else if (GET_CODE (entry_parm) == PARALLEL)
        {
          push_to_sequence2 (all->first_conversion_insn,
                             all->last_conversion_insn);
-         emit_group_store (mem, entry_parm, data->passed_type, size);
+         emit_group_store (mem, entry_parm, data->arg.type, size);
          all->first_conversion_insn = get_insns ();
          all->last_conversion_insn = get_last_insn ();
          end_sequence ();
@@ -2984,7 +2992,7 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
          if (mode != BLKmode
 #ifdef BLOCK_REG_PADDING
              && (size == UNITS_PER_WORD
-                 || (BLOCK_REG_PADDING (mode, data->passed_type, 1)
+                 || (BLOCK_REG_PADDING (mode, data->arg.type, 1)
                      != (BYTES_BIG_ENDIAN ? PAD_UPWARD : PAD_DOWNWARD)))
 #endif
              )
@@ -3025,7 +3033,7 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
                 additional changes to work correctly.  */
              gcc_checking_assert (BYTES_BIG_ENDIAN
                                   && (BLOCK_REG_PADDING (mode,
-                                                         data->passed_type, 1)
+                                                         data->arg.type, 1)
                                       == PAD_UPWARD));
 
              int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
@@ -3046,7 +3054,7 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
             handle all cases (e.g. SIZE == 3).  */
          else if (size != UNITS_PER_WORD
 #ifdef BLOCK_REG_PADDING
-                  && (BLOCK_REG_PADDING (mode, data->passed_type, 1)
+                  && (BLOCK_REG_PADDING (mode, data->arg.type, 1)
                       == PAD_DOWNWARD)
 #else
                   && BYTES_BIG_ENDIAN
@@ -3070,7 +3078,7 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
          gcc_checking_assert (size > UNITS_PER_WORD);
 #ifdef BLOCK_REG_PADDING
          gcc_checking_assert (BLOCK_REG_PADDING (GET_MODE (mem),
-                                                 data->passed_type, 0)
+                                                 data->arg.type, 0)
                               == PAD_UPWARD);
 #endif
          emit_move_insn (mem, entry_parm);
@@ -3079,7 +3087,7 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
        move_block_from_reg (REGNO (entry_parm), mem,
                             size_stored / UNITS_PER_WORD);
     }
-  else if (data->stack_parm == 0)
+  else if (data->stack_parm == 0 && !TYPE_EMPTY_P (data->arg.type))
     {
       push_to_sequence2 (all->first_conversion_insn, all->last_conversion_insn);
       emit_block_move (stack_parm, data->entry_parm, GEN_INT (size),
@@ -3123,6 +3131,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
   int unsignedp = TYPE_UNSIGNED (TREE_TYPE (parm));
   bool did_conversion = false;
   bool need_conversion, moved;
+  enum insn_code icode;
   rtx rtl;
 
   /* Store the parm in a pseudoregister during the function, but we may
@@ -3138,9 +3147,9 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
 
   /* If this was an item that we received a pointer to,
      set rtl appropriately.  */
-  if (data->passed_pointer)
+  if (data->arg.pass_by_reference)
     {
-      rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (data->passed_type)), parmreg);
+      rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (data->arg.type)), parmreg);
       set_mem_attributes (rtl, parm, 1);
     }
   else
@@ -3155,7 +3164,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
   validated_mem = validize_mem (copy_rtx (data->entry_parm));
 
   need_conversion = (data->nominal_mode != data->passed_mode
-                    || promoted_nominal_mode != data->promoted_mode);
+                    || promoted_nominal_mode != data->arg.mode);
   moved = false;
 
   if (need_conversion
@@ -3184,7 +3193,6 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
         conversion.  We verify that this insn does not clobber any
         hard registers.  */
 
-      enum insn_code icode;
       rtx op0, op1;
 
       icode = can_extend_p (promoted_nominal_mode, data->passed_mode,
@@ -3227,8 +3235,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
          for (insn = insns; insn && moved; insn = NEXT_INSN (insn))
            {
              if (INSN_P (insn))
-               note_stores (PATTERN (insn), record_hard_reg_sets,
-                            &hardregs);
+               note_stores (insn, record_hard_reg_sets, &hardregs);
              if (!hard_reg_set_empty_p (hardregs))
                moved = false;
            }
@@ -3287,12 +3294,29 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
 
       did_conversion = true;
     }
+  else if (MEM_P (data->entry_parm)
+          && GET_MODE_ALIGNMENT (promoted_nominal_mode)
+             > MEM_ALIGN (data->entry_parm)
+          && (((icode = optab_handler (movmisalign_optab,
+                                       promoted_nominal_mode))
+               != CODE_FOR_nothing)
+              || targetm.slow_unaligned_access (promoted_nominal_mode,
+                                                MEM_ALIGN (data->entry_parm))))
+    {
+      if (icode != CODE_FOR_nothing)
+       emit_insn (GEN_FCN (icode) (parmreg, validated_mem));
+      else
+       rtl = parmreg = extract_bit_field (validated_mem,
+                       GET_MODE_BITSIZE (promoted_nominal_mode), 0,
+                       unsignedp, parmreg,
+                       promoted_nominal_mode, VOIDmode, false, NULL);
+    }
   else
     emit_move_insn (parmreg, validated_mem);
 
   /* If we were passed a pointer but the actual value can safely live
      in a register, retrieve it and use it directly.  */
-  if (data->passed_pointer && TYPE_MODE (TREE_TYPE (parm)) != BLKmode)
+  if (data->arg.pass_by_reference && TYPE_MODE (TREE_TYPE (parm)) != BLKmode)
     {
       /* We can't use nominal_mode, because it will have been set to
         Pmode above.  We must use the actual mode of the parm.  */
@@ -3409,7 +3433,7 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
 
   assign_parm_remove_parallels (data);
 
-  if (data->promoted_mode != data->nominal_mode)
+  if (data->arg.mode != data->nominal_mode)
     {
       /* Conversion is required.  */
       rtx tempreg = gen_reg_rtx (GET_MODE (data->entry_parm));
@@ -3424,12 +3448,13 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
 
       if (data->stack_parm)
        {
-         int offset = subreg_lowpart_offset (data->nominal_mode,
-                                             GET_MODE (data->stack_parm));
+         poly_int64 offset
+           = subreg_lowpart_offset (data->nominal_mode,
+                                    GET_MODE (data->stack_parm));
          /* ??? This may need a big-endian conversion on sparc64.  */
          data->stack_parm
            = adjust_address (data->stack_parm, data->nominal_mode, 0);
-         if (offset && MEM_OFFSET_KNOWN_P (data->stack_parm))
+         if (maybe_ne (offset, 0) && MEM_OFFSET_KNOWN_P (data->stack_parm))
            set_mem_offset (data->stack_parm,
                            MEM_OFFSET (data->stack_parm) + offset);
        }
@@ -3441,20 +3466,31 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
 
       if (data->stack_parm == 0)
        {
-         int align = STACK_SLOT_ALIGNMENT (data->passed_type,
+         int align = STACK_SLOT_ALIGNMENT (data->arg.type,
                                            GET_MODE (data->entry_parm),
-                                           TYPE_ALIGN (data->passed_type));
+                                           TYPE_ALIGN (data->arg.type));
+         if (align < (int)GET_MODE_ALIGNMENT (GET_MODE (data->entry_parm))
+             && ((optab_handler (movmisalign_optab,
+                                 GET_MODE (data->entry_parm))
+                  != CODE_FOR_nothing)
+                 || targetm.slow_unaligned_access (GET_MODE (data->entry_parm),
+                                                   align)))
+           align = GET_MODE_ALIGNMENT (GET_MODE (data->entry_parm));
          data->stack_parm
            = assign_stack_local (GET_MODE (data->entry_parm),
                                  GET_MODE_SIZE (GET_MODE (data->entry_parm)),
                                  align);
+         align = MEM_ALIGN (data->stack_parm);
          set_mem_attributes (data->stack_parm, parm, 1);
+         set_mem_align (data->stack_parm, align);
        }
 
       dest = validize_mem (copy_rtx (data->stack_parm));
       src = validize_mem (copy_rtx (data->entry_parm));
 
-      if (MEM_P (src))
+      if (TYPE_EMPTY_P (data->arg.type))
+       /* Empty types don't really need to be copied.  */;
+      else if (MEM_P (src))
        {
          /* Use a block move to handle potentially misaligned entry_parm.  */
          if (!to_conversion)
@@ -3463,7 +3499,7 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
          to_conversion = true;
 
          emit_block_move (dest, src,
-                          GEN_INT (int_size_in_bytes (data->passed_type)),
+                          GEN_INT (int_size_in_bytes (data->arg.type)),
                           BLOCK_OP_NORMAL);
        }
       else
@@ -3551,121 +3587,6 @@ 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.  */
 
@@ -3675,11 +3596,7 @@ assign_parms (tree fndecl)
   struct assign_parm_data_all all;
   tree parm;
   vec<tree> fnargs;
-  unsigned i, bound_no = 0;
-  tree last_arg = NULL;
-  rtx last_arg_entry = NULL;
-  vec<bounds_parm_data> bndargs = vNULL;
-  bounds_parm_data bdata;
+  unsigned i;
 
   crtl->args.internal_arg_pointer
     = targetm.calls.internal_arg_pointer ();
@@ -3706,10 +3623,9 @@ assign_parms (tree fndecl)
       if (SUPPORTS_STACK_ALIGNMENT)
         {
           unsigned int align
-           = targetm.calls.function_arg_boundary (data.promoted_mode,
-                                                  data.passed_type);
-         align = MINIMUM_ALIGNMENT (data.passed_type, data.promoted_mode,
-                                    align);
+           = targetm.calls.function_arg_boundary (data.arg.mode,
+                                                  data.arg.type);
+         align = MINIMUM_ALIGNMENT (data.arg.type, data.arg.mode, align);
          if (TYPE_ALIGN (data.nominal_type) > align)
            align = MINIMUM_ALIGNMENT (data.nominal_type,
                                       TYPE_MODE (data.nominal_type),
@@ -3729,21 +3645,22 @@ 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;
+         /* For arguments that occupy no space in the parameter
+            passing area, have non-zero size and have address taken,
+            force creation of a stack slot so that they have distinct
+            address from other parameters.  */
+         if (TYPE_EMPTY_P (data.arg.type)
+             && TREE_ADDRESSABLE (parm)
+             && data.entry_parm == data.stack_parm
+             && MEM_P (data.entry_parm)
+             && int_size_in_bytes (data.arg.type))
+           data.stack_parm = NULL_RTX;
        }
       /* Record permanently how this parm was passed.  */
-      if (data.passed_pointer)
+      if (data.arg.pass_by_reference)
        {
          rtx incoming_rtl
-           = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (data.passed_type)),
+           = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (data.arg.type)),
                           data.entry_parm);
          set_decl_incoming_rtl (parm, incoming_rtl, true);
        }
@@ -3752,64 +3669,20 @@ assign_parms (tree fndecl)
 
       assign_parm_adjust_stack_rtl (&data);
 
-      /* Bounds 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);
-       }
+      if (assign_parm_setup_block_p (&data))
+       assign_parm_setup_block (&all, parm, &data);
+      else if (data.arg.pass_by_reference || use_register_for_decl (parm))
+       assign_parm_setup_reg (&all, parm, &data);
       else
-       {
-         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);
-       }
+       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 ();
-           }
-       }
+       assign_parms_setup_varargs (&all, &data, false);
 
       /* 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);
-
-      if (POINTER_BOUNDS_TYPE_P (data.passed_type))
-       bound_no++;
+      targetm.calls.function_arg_advance (all.args_so_far, data.arg);
     }
 
-  assign_bounds (bndargs, all, true, true, true);
-  bndargs.release ();
-
   if (targetm.calls.split_complex_arg)
     assign_parms_unsplit_complex (&all, fnargs);
 
@@ -3879,14 +3752,15 @@ assign_parms (tree fndecl)
   /* Adjust function incoming argument size for alignment and
      minimum length.  */
 
-  crtl->args.size = MAX (crtl->args.size, all.reg_parm_stack_space);
-  crtl->args.size = CEIL_ROUND (crtl->args.size,
-                                          PARM_BOUNDARY / BITS_PER_UNIT);
+  crtl->args.size = upper_bound (crtl->args.size, all.reg_parm_stack_space);
+  crtl->args.size = aligned_upper_bound (crtl->args.size,
+                                        PARM_BOUNDARY / BITS_PER_UNIT);
 
   if (ARGS_GROW_DOWNWARD)
     {
       crtl->args.arg_offset_rtx
-       = (all.stack_args_size.var == 0 ? GEN_INT (-all.stack_args_size.constant)
+       = (all.stack_args_size.var == 0
+          ? gen_int_mode (-all.stack_args_size.constant, Pmode)
           : expand_expr (size_diffop (all.stack_args_size.var,
                                       size_int (-all.stack_args_size.constant)),
                          NULL_RTX, VOIDmode, EXPAND_NORMAL));
@@ -3931,10 +3805,6 @@ 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
@@ -3974,7 +3844,7 @@ gimplify_parm_type (tree *tp, int *walk_subtrees, void *data)
    statements to add to the beginning of the function.  */
 
 gimple_seq
-gimplify_parameters (void)
+gimplify_parameters (gimple_seq *cleanup)
 {
   struct assign_parm_data_all all;
   tree parm;
@@ -3997,14 +3867,13 @@ gimplify_parameters (void)
        continue;
 
       /* 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);
+      targetm.calls.function_arg_advance (all.args_so_far, data.arg);
 
       /* ??? Once upon a time variable_size stuffed parameter list
         SAVE_EXPRs (amongst others) onto a pending sizes list.  This
         turned out to be less than manageable in the gimple world.
         Now we have to hunt them down ourselves.  */
-      walk_tree_without_duplicates (&data.passed_type,
+      walk_tree_without_duplicates (&data.arg.type,
                                    gimplify_parm_type, &stmts);
 
       if (TREE_CODE (DECL_SIZE_UNIT (parm)) != INTEGER_CST)
@@ -4013,11 +3882,11 @@ gimplify_parameters (void)
          gimplify_one_sizepos (&DECL_SIZE_UNIT (parm), &stmts);
        }
 
-      if (data.passed_pointer)
+      if (data.arg.pass_by_reference)
        {
-          tree type = TREE_TYPE (data.passed_type);
-         if (reference_callee_copied (&all.args_so_far_v, TYPE_MODE (type),
-                                      type, data.named_arg))
+         tree type = TREE_TYPE (data.arg.type);
+         function_arg_info orig_arg (type, data.arg.named);
+         if (reference_callee_copied (&all.args_so_far_v, orig_arg))
            {
              tree local, t;
 
@@ -4039,6 +3908,15 @@ gimplify_parameters (void)
                  else if (TREE_CODE (type) == COMPLEX_TYPE
                           || TREE_CODE (type) == VECTOR_TYPE)
                    DECL_GIMPLE_REG_P (local) = 1;
+
+                 if (!is_gimple_reg (local)
+                     && flag_stack_reuse != SR_NONE)
+                   {
+                     tree clobber = build_clobber (type);
+                     gimple *clobber_stmt;
+                     clobber_stmt = gimple_build_assign (local, clobber);
+                     gimple_seq_add_stmt (cleanup, clobber_stmt);
+                   }
                }
              else
                {
@@ -4126,22 +4004,27 @@ locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs,
     {
       if (reg_parm_stack_space > 0)
        {
-         if (initial_offset_ptr->var)
+         if (initial_offset_ptr->var
+             || !ordered_p (initial_offset_ptr->constant,
+                            reg_parm_stack_space))
            {
              initial_offset_ptr->var
                = size_binop (MAX_EXPR, ARGS_SIZE_TREE (*initial_offset_ptr),
                              ssize_int (reg_parm_stack_space));
              initial_offset_ptr->constant = 0;
            }
-         else if (initial_offset_ptr->constant < reg_parm_stack_space)
-           initial_offset_ptr->constant = reg_parm_stack_space;
+         else
+           initial_offset_ptr->constant
+             = ordered_max (initial_offset_ptr->constant,
+                            reg_parm_stack_space);
        }
     }
 
   part_size_in_regs = (reg_parm_stack_space == 0 ? partial : 0);
 
-  sizetree
-    = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
+  sizetree = (type
+             ? arg_size_in_bytes (type)
+             : size_int (GET_MODE_SIZE (passed_mode)));
   where_pad = targetm.calls.function_arg_padding (passed_mode, type);
   boundary = targetm.calls.function_arg_boundary (passed_mode, type);
   round_boundary = targetm.calls.function_arg_round_boundary (passed_mode,
@@ -4175,13 +4058,6 @@ locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs,
        }
     }
 
-  /* Remember if the outgoing parameter requires extra alignment on the
-     calling function side.  */
-  if (crtl->stack_alignment_needed < boundary)
-    crtl->stack_alignment_needed = boundary;
-  if (crtl->preferred_stack_boundary < boundary)
-    crtl->preferred_stack_boundary = boundary;
-
   if (ARGS_GROW_DOWNWARD)
     {
       locate->slot_offset.constant = -initial_offset_ptr->constant;
@@ -4260,9 +4136,9 @@ pad_to_arg_alignment (struct args_size *offset_ptr, int boundary,
                      struct args_size *alignment_pad)
 {
   tree save_var = NULL_TREE;
-  HOST_WIDE_INT save_constant = 0;
+  poly_int64 save_constant = 0;
   int boundary_in_bytes = boundary / BITS_PER_UNIT;
-  HOST_WIDE_INT sp_offset = STACK_POINTER_OFFSET;
+  poly_int64 sp_offset = STACK_POINTER_OFFSET;
 
 #ifdef SPARC_STACK_BOUNDARY_HACK
   /* ??? The SPARC port may claim a STACK_BOUNDARY higher than
@@ -4283,7 +4159,10 @@ pad_to_arg_alignment (struct args_size *offset_ptr, int boundary,
 
   if (boundary > BITS_PER_UNIT)
     {
-      if (offset_ptr->var)
+      int misalign;
+      if (offset_ptr->var
+         || !known_misalignment (offset_ptr->constant + sp_offset,
+                                 boundary_in_bytes, &misalign))
        {
          tree sp_offset_tree = ssize_int (sp_offset);
          tree offset = size_binop (PLUS_EXPR,
@@ -4304,13 +4183,13 @@ pad_to_arg_alignment (struct args_size *offset_ptr, int boundary,
        }
       else
        {
-         offset_ptr->constant = -sp_offset +
-           (ARGS_GROW_DOWNWARD
-           ? FLOOR_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes)
-           : CEIL_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes));
+         if (ARGS_GROW_DOWNWARD)
+           offset_ptr->constant -= misalign;
+         else
+           offset_ptr->constant += -misalign & (boundary_in_bytes - 1);
 
-           if (boundary > PARM_BOUNDARY)
-             alignment_pad->constant = offset_ptr->constant - save_constant;
+         if (boundary > PARM_BOUNDARY)
+           alignment_pad->constant = offset_ptr->constant - save_constant;
        }
     }
 }
@@ -4319,8 +4198,10 @@ static void
 pad_below (struct args_size *offset_ptr, machine_mode passed_mode, tree sizetree)
 {
   unsigned int align = PARM_BOUNDARY / BITS_PER_UNIT;
-  if (passed_mode != BLKmode)
-    offset_ptr->constant += -GET_MODE_SIZE (passed_mode) & (align - 1);
+  int misalign;
+  if (passed_mode != BLKmode
+      && known_misalignment (GET_MODE_SIZE (passed_mode), align, &misalign))
+    offset_ptr->constant += -misalign & (align - 1);
   else
     {
       if (TREE_CODE (sizetree) != INTEGER_CST
@@ -4709,11 +4590,11 @@ number_blocks (tree fn)
   int n_blocks;
   tree *block_vector;
 
-  /* For SDB and XCOFF debugging output, we start numbering the blocks
+  /* For XCOFF debugging output, we start numbering the blocks
      from 1 within each function, rather than keeping a running
      count.  */
-#if SDB_DEBUGGING_INFO || defined (XCOFF_DEBUGGING_INFO)
-  if (write_symbols == SDB_DEBUG || write_symbols == XCOFF_DEBUG)
+#if defined (XCOFF_DEBUGGING_INFO)
+  if (write_symbols == XCOFF_DEBUG)
     next_block_index = 1;
 #endif
 
@@ -4782,6 +4663,9 @@ invoke_set_current_function_hook (tree fndecl)
       targetm.set_current_function (fndecl);
       this_fn_optabs = this_target_optabs;
 
+      /* Initialize global alignment variables after op.  */
+      parse_alignment_opts ();
+
       if (opts != optimization_default_node)
        {
          init_tree_optimization_optabs (opts);
@@ -4853,6 +4737,16 @@ get_last_funcdef_no (void)
   return funcdef_no;
 }
 
+/* Allocate and initialize the stack usage info data structure for the
+   current function.  */
+static void
+allocate_stack_usage_info (void)
+{
+  gcc_assert (!cfun->su);
+  cfun->su = ggc_cleared_alloc<stack_usage> ();
+  cfun->su->static_stack_size = -1;
+}
+
 /* Allocate a function structure for FNDECL and set its contents
    to the defaults.  Set cfun to the newly-allocated object.
    Some of the helper functions invoked during initialization assume
@@ -4930,7 +4824,16 @@ allocate_struct_function (tree fndecl, bool abstract_p)
 
       if (!profile_flag && !flag_instrument_function_entry_exit)
        DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
+
+      if (flag_callgraph_info)
+       allocate_stack_usage_info ();
     }
+
+  /* Don't enable begin stmt markers if var-tracking at assignments is
+     disabled.  The markers make little sense without the variable
+     binding annotations among them.  */
+  cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
+    && MAY_HAVE_DEBUG_MARKER_STMTS;
 }
 
 /* This is like allocate_struct_function, but pushes a new cfun for FNDECL
@@ -4956,17 +4859,20 @@ static void
 prepare_function_start (void)
 {
   gcc_assert (!get_last_insn ());
+
+  if (in_dummy_function)
+    crtl->abi = &default_function_abi;
+  else
+    crtl->abi = &fndecl_abi (cfun->decl).base_abi ();
+
   init_temp_slots ();
   init_emit ();
   init_varasm_status ();
   init_expr ();
   default_rtl_profile ();
 
-  if (flag_stack_usage_info)
-    {
-      cfun->su = ggc_cleared_alloc<stack_usage> ();
-      cfun->su->static_stack_size = -1;
-    }
+  if (flag_stack_usage_info && !flag_callgraph_info)
+    allocate_stack_usage_info ();
 
   cse_not_expected = ! optimize;
 
@@ -5046,21 +4952,37 @@ init_function_start (tree subr)
 void
 stack_protect_epilogue (void)
 {
-  tree guard_decl = targetm.stack_protect_guard ();
+  tree guard_decl = crtl->stack_protect_guard_decl;
   rtx_code_label *label = gen_label_rtx ();
   rtx x, y;
-  rtx_insn *seq;
+  rtx_insn *seq = NULL;
 
   x = expand_normal (crtl->stack_protect_guard);
-  if (guard_decl)
-    y = expand_normal (guard_decl);
+
+  if (targetm.have_stack_protect_combined_test () && guard_decl)
+    {
+      gcc_assert (DECL_P (guard_decl));
+      y = DECL_RTL (guard_decl);
+      /* Allow the target to compute address of Y and compare it with X without
+        leaking Y into a register.  This combined address + compare pattern
+        allows the target to prevent spilling of any intermediate results by
+        splitting it after register allocator.  */
+      seq = targetm.gen_stack_protect_combined_test (x, y, label);
+    }
   else
-    y = const0_rtx;
+    {
+      if (guard_decl)
+       y = expand_normal (guard_decl);
+      else
+       y = const0_rtx;
+
+      /* Allow the target to compare Y with X without leaking either into
+        a register.  */
+      if (targetm.have_stack_protect_test ())
+       seq = targetm.gen_stack_protect_test (x, y, label);
+    }
 
-  /* Allow the target to compare Y with X without leaking either into
-     a register.  */
-  if (targetm.have_stack_protect_test ()
-      && ((seq = targetm.gen_stack_protect_test (x, y, label)) != NULL_RTX))
+  if (seq)
     emit_insn (seq);
   else
     emit_cmp_and_jump_insns (x, y, EQ, NULL_RTX, ptr_mode, 1, label);
@@ -5190,14 +5112,6 @@ 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 (res) = 1;
-
-      if (chkp_function_instrumented_p (current_function_decl))
-       {
-         tree return_type = TREE_TYPE (res);
-         rtx bounds = targetm.calls.chkp_function_value_bounds (return_type,
-                                                                subr, 1);
-         SET_DECL_BOUNDS_RTL (res, bounds);
-       }
     }
 
   /* Initialize rtx for parameters and local variables.
@@ -5248,7 +5162,7 @@ expand_function_start (tree subr)
     }
 
   /* The following was moved from init_function_start.
-     The move is supposed to make sdb output more accurate.  */
+     The move was supposed to make sdb output more accurate.  */
   /* Indicate the beginning of the function body,
      as opposed to parm setup.  */
   emit_note (NOTE_INSN_FUNCTION_BEG);
@@ -5274,7 +5188,7 @@ expand_function_start (tree subr)
       r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE);
       gcc_assert (GET_MODE (r_save) == Pmode);
 
-      emit_move_insn (r_save, targetm.builtin_setjmp_frame_value ());
+      emit_move_insn (r_save, hard_frame_pointer_rtx);
       update_nonlocal_goto_save_area ();
     }
 
@@ -5345,7 +5259,6 @@ diddle_return_value_1 (void (*doit) (rtx, void *), void *arg, rtx outgoing)
 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);
 }
 
@@ -5384,19 +5297,6 @@ use_return_register (void)
   diddle_return_value (do_use_return_reg, NULL);
 }
 
-/* Set the location of the insn chain starting at INSN to LOC.  */
-
-static void
-set_insn_locations (rtx_insn *insn, int loc)
-{
-  while (insn != NULL)
-    {
-      if (INSN_P (insn))
-       INSN_LOCATION (insn) = loc;
-      insn = NEXT_INSN (insn);
-    }
-}
-
 /* Generate RTL for the end of the current function.  */
 
 void
@@ -5439,7 +5339,7 @@ expand_function_end (void)
   do_pending_stack_adjust ();
 
   /* Output a linenumber for the end of the function.
-     SDB depends on this.  */
+     SDB depended on this.  */
   set_curr_insn_location (input_location);
 
   /* Before the return label (if any), clobber the return
@@ -5462,19 +5362,17 @@ expand_function_end (void)
       if (flag_exceptions)
        sjlj_emit_function_exit_after (get_last_insn ());
     }
-  else
-    {
-      /* We want to ensure that instructions that may trap are not
-        moved into the epilogue by scheduling, because we don't
-        always emit unwind information for the epilogue.  */
-      if (cfun->can_throw_non_call_exceptions)
-       emit_insn (gen_blockage ());
-    }
 
   /* If this is an implementation of throw, do what's necessary to
      communicate between __builtin_eh_return and the epilogue.  */
   expand_eh_return ();
 
+  /* If stack protection is enabled for this function, check the guard.  */
+  if (crtl->stack_protect_guard
+      && targetm.stack_protect_runtime_enabled_p ()
+      && naked_return_label == NULL_RTX)
+    stack_protect_epilogue ();
+
   /* If scalar return value was computed in a pseudo-reg, or was a named
      return value that got dumped to the stack, copy that to the hard
      return register.  */
@@ -5621,7 +5519,9 @@ expand_function_end (void)
     emit_insn (gen_blockage ());
 
   /* If stack protection is enabled for this function, check the guard.  */
-  if (crtl->stack_protect_guard && targetm.stack_protect_runtime_enabled_p ())
+  if (crtl->stack_protect_guard
+      && targetm.stack_protect_runtime_enabled_p ()
+      && naked_return_label)
     stack_protect_epilogue ();
 
   /* If we had calls to alloca, and this machine needs
@@ -6495,12 +6395,46 @@ rest_of_handle_thread_prologue_and_epilogue (void)
   cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
 
   /* The stack usage info is finalized during prologue expansion.  */
-  if (flag_stack_usage_info)
+  if (flag_stack_usage_info || flag_callgraph_info)
     output_stack_usage ();
 
   return 0;
 }
 
+/* Record a final call to CALLEE at LOCATION.  */
+
+void
+record_final_call (tree callee, location_t location)
+{
+  struct callinfo_callee datum = { location, callee };
+  vec_safe_push (cfun->su->callees, datum);
+}
+
+/* Record a dynamic allocation made for DECL_OR_EXP.  */
+
+void
+record_dynamic_alloc (tree decl_or_exp)
+{
+  struct callinfo_dalloc datum;
+
+  if (DECL_P (decl_or_exp))
+    {
+      datum.location = DECL_SOURCE_LOCATION (decl_or_exp);
+      const char *name = lang_hooks.decl_printable_name (decl_or_exp, 2);
+      const char *dot = strrchr (name, '.');
+      if (dot)
+       name = dot + 1;
+      datum.name = ggc_strdup (name);
+    }
+  else
+    {
+      datum.location = EXPR_LOCATION (decl_or_exp);
+      datum.name = NULL;
+    }
+
+  vec_safe_push (cfun->su->dallocs, datum);
+}
+
 namespace {
 
 const pass_data pass_data_thread_prologue_and_epilogue =
@@ -6540,6 +6474,21 @@ make_pass_thread_prologue_and_epilogue (gcc::context *ctxt)
 }
 \f
 
+/* If CONSTRAINT is a matching constraint, then return its number.
+   Otherwise, return -1.  */
+
+static int
+matching_constraint_num (const char *constraint)
+{
+  if (*constraint == '%')
+    constraint++;
+
+  if (IN_RANGE (*constraint, '0', '9'))
+    return strtoul (constraint, NULL, 10);
+
+  return -1;
+}
+
 /* This mini-pass fixes fall-out from SSA in asm statements that have
    in-out constraints.  Say you start with
 
@@ -6598,14 +6547,10 @@ match_asm_constraints_1 (rtx_insn *insn, rtx *p_sets, int noutputs)
       rtx input, output;
       rtx_insn *insns;
       const char *constraint = ASM_OPERANDS_INPUT_CONSTRAINT (op, i);
-      char *end;
       int match, j;
 
-      if (*constraint == '%')
-       constraint++;
-
-      match = strtoul (constraint, &end, 10);
-      if (end == constraint)
+      match = matching_constraint_num (constraint);
+      if (match < 0)
        continue;
 
       gcc_assert (match < noutputs);
@@ -6614,21 +6559,22 @@ match_asm_constraints_1 (rtx_insn *insn, rtx *p_sets, int noutputs)
       /* Only do the transformation for pseudos.  */
       if (! REG_P (output)
          || rtx_equal_p (output, input)
-         || (GET_MODE (input) != VOIDmode
-             && GET_MODE (input) != GET_MODE (output)))
+         || !(REG_P (input) || SUBREG_P (input)
+              || MEM_P (input) || CONSTANT_P (input))
+         || !general_operand (input, GET_MODE (output)))
        continue;
 
       /* We can't do anything if the output is also used as input,
         as we're going to overwrite it.  */
       for (j = 0; j < ninputs; j++)
-        if (reg_overlap_mentioned_p (output, RTVEC_ELT (inputs, j)))
+       if (reg_overlap_mentioned_p (output, RTVEC_ELT (inputs, j)))
          break;
       if (j != ninputs)
        continue;
 
       /* Avoid changing the same input several times.  For
         asm ("" : "=mr" (out1), "=mr" (out2) : "0" (in), "1" (in));
-        only change in once (to out1), rather than changing it
+        only change it once (to out1), rather than changing it
         first to out1 and afterwards to out2.  */
       if (i > 0)
        {
@@ -6641,11 +6587,14 @@ match_asm_constraints_1 (rtx_insn *insn, rtx *p_sets, int noutputs)
       output_matched[match] = true;
 
       start_sequence ();
-      emit_move_insn (output, input);
+      emit_move_insn (output, copy_rtx (input));
       insns = get_insns ();
       end_sequence ();
       emit_insn_before (insns, insn);
 
+      constraint = ASM_OPERANDS_OUTPUT_CONSTRAINT(SET_SRC(p_sets[match]));
+      bool early_clobber_p = strchr (constraint, '&') != NULL;
+
       /* Now replace all mentions of the input with output.  We can't
         just replace the occurrence in inputs[i], as the register might
         also be used in some other input (or even in an address of an
@@ -6667,7 +6616,14 @@ match_asm_constraints_1 (rtx_insn *insn, rtx *p_sets, int noutputs)
         value, but different pseudos) where we formerly had only one.
         With more complicated asms this might lead to reload failures
         which wouldn't have happen without this pass.  So, iterate over
-        all operands and replace all occurrences of the register used.  */
+        all operands and replace all occurrences of the register used.
+
+        However, if one or more of the 'input' uses have a non-matching
+        constraint and the matched output operand is an early clobber
+        operand, then do not replace the input operand, since by definition
+        it conflicts with the output operand and cannot share the same
+        register.  See PR89313 for details.  */
+
       for (j = 0; j < noutputs; j++)
        if (!rtx_equal_p (SET_DEST (p_sets[j]), input)
            && reg_overlap_mentioned_p (input, SET_DEST (p_sets[j])))
@@ -6675,8 +6631,13 @@ match_asm_constraints_1 (rtx_insn *insn, rtx *p_sets, int noutputs)
                                              input, output);
       for (j = 0; j < ninputs; j++)
        if (reg_overlap_mentioned_p (input, RTVEC_ELT (inputs, j)))
-         RTVEC_ELT (inputs, j) = replace_rtx (RTVEC_ELT (inputs, j),
-                                              input, output);
+         {
+           if (!early_clobber_p
+               || match == matching_constraint_num
+                             (ASM_OPERANDS_INPUT_CONSTRAINT (op, j)))
+             RTVEC_ELT (inputs, j) = replace_rtx (RTVEC_ELT (inputs, j),
+                                                  input, output);
+         }
 
       changed = true;
     }