PR c++/68795: fix uninitialized close_paren_loc in cp_parser_postfix_expression
[gcc.git] / gcc / calls.c
index 9c19f38302a3e7b9fb59a3a2f2153ec9a4cae6af..a1549348b520ab57d2d1cd97756a5295166674fe 100644 (file)
@@ -1,5 +1,5 @@
 /* Convert function calls to rtl insns, for GNU C compiler.
-   Copyright (C) 1989-2014 Free Software Foundation, Inc.
+   Copyright (C) 1989-2016 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -20,36 +20,35 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "gimple.h"
+#include "predict.h"
+#include "tm_p.h"
+#include "stringpool.h"
+#include "expmed.h"
+#include "optabs.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "diagnostic-core.h"
+#include "fold-const.h"
 #include "stor-layout.h"
 #include "varasm.h"
-#include "stringpool.h"
-#include "attribs.h"
-#include "basic-block.h"
-#include "tree-ssa-alias.h"
 #include "internal-fn.h"
-#include "gimple-expr.h"
-#include "is-a.h"
-#include "gimple.h"
-#include "flags.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
 #include "expr.h"
-#include "optabs.h"
-#include "libfuncs.h"
-#include "function.h"
-#include "regs.h"
-#include "diagnostic-core.h"
 #include "output.h"
-#include "tm_p.h"
-#include "timevar.h"
-#include "sbitmap.h"
 #include "langhooks.h"
-#include "target.h"
-#include "cgraph.h"
 #include "except.h"
 #include "dbgcnt.h"
 #include "rtl-iter.h"
+#include "tree-chkp.h"
+#include "rtl-chkp.h"
+
 
 /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits.  */
 #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
@@ -61,7 +60,7 @@ struct arg_data
   /* Tree node for this argument.  */
   tree tree_value;
   /* Mode for value; TYPE_MODE unless promoted.  */
-  enum machine_mode mode;
+  machine_mode mode;
   /* Current RTL value for argument, or 0 if it isn't precomputed.  */
   rtx value;
   /* Initially-compute RTL value for argument; only for const functions.  */
@@ -77,6 +76,15 @@ struct arg_data
   /* If REG is a PARALLEL, this is a copy of VALUE pulled into the correct
      form for emit_group_move.  */
   rtx parallel_value;
+  /* If value is passed in neither reg nor stack, this field holds a number
+     of a special slot to be used.  */
+  rtx special_slot;
+  /* For pointer bounds hold an index of parm bounds are bound to.  -1 if
+     there is no such pointer.  */
+  int pointer_arg;
+  /* If pointer_arg refers a structure, then pointer_offset holds an offset
+     of a pointer in this structure.  */
+  int pointer_offset;
   /* If REG was promoted from the actual mode of the argument expression,
      indicates whether the promotion is sign- or zero-extended.  */
   int unsignedp;
@@ -134,6 +142,7 @@ static void emit_call_1 (rtx, tree, tree, tree, HOST_WIDE_INT, HOST_WIDE_INT,
                         HOST_WIDE_INT, rtx, rtx, int, rtx, int,
                         cumulative_args_t);
 static void precompute_register_parameters (int, struct arg_data *, int *);
+static void store_bounds (struct arg_data *, struct arg_data *);
 static int store_one_arg (struct arg_data *, rtx, int, int, int);
 static void store_unaligned_arguments_into_pseudos (struct arg_data *, int);
 static int finalize_must_preallocate (int, int, struct arg_data *,
@@ -151,7 +160,7 @@ static rtx rtx_for_function_call (tree, tree);
 static void load_register_parameters (struct arg_data *, int, rtx *, int,
                                      int, int *);
 static rtx emit_library_call_value_1 (int, rtx, rtx, enum libcall_type,
-                                     enum machine_mode, int, va_list);
+                                     machine_mode, int, va_list);
 static int special_function_p (const_tree, int);
 static int check_sibcall_argument_overlap_1 (rtx);
 static int check_sibcall_argument_overlap (rtx_insn *, struct arg_data *, int);
@@ -173,7 +182,7 @@ static void restore_fixed_argument_area (rtx, rtx, int, int);
    CALL_INSN_FUNCTION_USAGE information.  */
 
 rtx
-prepare_call_address (tree fndecl, rtx funexp, rtx static_chain_value,
+prepare_call_address (tree fndecl_or_type, rtx funexp, rtx static_chain_value,
                      rtx *call_fusage, int reg_parm_seen, int sibcallp)
 {
   /* Make a valid memory address and copy constants through pseudo-regs,
@@ -187,18 +196,17 @@ prepare_call_address (tree fndecl, rtx funexp, rtx static_chain_value,
              : memory_address (FUNCTION_MODE, funexp));
   else if (! sibcallp)
     {
-#ifndef NO_FUNCTION_CSE
-      if (optimize && ! flag_no_function_cse)
+      if (!NO_FUNCTION_CSE && optimize && ! flag_no_function_cse)
        funexp = force_reg (Pmode, funexp);
-#endif
     }
 
-  if (static_chain_value != 0)
+  if (static_chain_value != 0
+      && (TREE_CODE (fndecl_or_type) != FUNCTION_DECL
+         || DECL_STATIC_CHAIN (fndecl_or_type)))
     {
       rtx chain;
 
-      gcc_assert (fndecl);
-      chain = targetm.calls.static_chain (fndecl, false);
+      chain = targetm.calls.static_chain (fndecl_or_type, false);
       static_chain_value = convert_memory_address (Pmode, static_chain_value);
 
       emit_move_insn (chain, static_chain_value);
@@ -262,8 +270,7 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU
             cumulative_args_t args_so_far ATTRIBUTE_UNUSED)
 {
   rtx rounded_stack_size_rtx = GEN_INT (rounded_stack_size);
-  rtx_insn *call_insn;
-  rtx call, funmem;
+  rtx call, funmem, pat;
   int already_popped = 0;
   HOST_WIDE_INT n_popped
     = targetm.calls.return_pops_args (fndecl, funtype, stack_size);
@@ -302,93 +309,53 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU
   else if (fntree)
     set_mem_expr (funmem, build_simple_mem_ref (CALL_EXPR_FN (fntree)));
 
-#if defined (HAVE_sibcall_pop) && defined (HAVE_sibcall_value_pop)
-  if ((ecf_flags & ECF_SIBCALL)
-      && HAVE_sibcall_pop && HAVE_sibcall_value_pop
-      && (n_popped > 0 || stack_size == 0))
+  if (ecf_flags & ECF_SIBCALL)
     {
-      rtx n_pop = GEN_INT (n_popped);
-      rtx pat;
-
-      /* If this subroutine pops its own args, record that in the call insn
-        if possible, for the sake of frame pointer elimination.  */
-
       if (valreg)
-       pat = GEN_SIBCALL_VALUE_POP (valreg, funmem, rounded_stack_size_rtx,
-                                    next_arg_reg, n_pop);
+       pat = targetm.gen_sibcall_value (valreg, funmem,
+                                        rounded_stack_size_rtx,
+                                        next_arg_reg, NULL_RTX);
       else
-       pat = GEN_SIBCALL_POP (funmem, rounded_stack_size_rtx, next_arg_reg,
-                              n_pop);
-
-      emit_call_insn (pat);
-      already_popped = 1;
+       pat = targetm.gen_sibcall (funmem, rounded_stack_size_rtx,
+                                  next_arg_reg, GEN_INT (struct_value_size));
     }
-  else
-#endif
-
-#if defined (HAVE_call_pop) && defined (HAVE_call_value_pop)
   /* If the target has "call" or "call_value" insns, then prefer them
      if no arguments are actually popped.  If the target does not have
      "call" or "call_value" insns, then we must use the popping versions
      even if the call has no arguments to pop.  */
-#if defined (HAVE_call) && defined (HAVE_call_value)
-  if (HAVE_call && HAVE_call_value && HAVE_call_pop && HAVE_call_value_pop
-      && n_popped > 0)
-#else
-  if (HAVE_call_pop && HAVE_call_value_pop)
-#endif
+  else if (n_popped > 0
+          || !(valreg
+               ? targetm.have_call_value ()
+               : targetm.have_call ()))
     {
       rtx n_pop = GEN_INT (n_popped);
-      rtx pat;
 
       /* If this subroutine pops its own args, record that in the call insn
         if possible, for the sake of frame pointer elimination.  */
 
       if (valreg)
-       pat = GEN_CALL_VALUE_POP (valreg, funmem, rounded_stack_size_rtx,
-                                 next_arg_reg, n_pop);
+       pat = targetm.gen_call_value_pop (valreg, funmem,
+                                         rounded_stack_size_rtx,
+                                         next_arg_reg, n_pop);
       else
-       pat = GEN_CALL_POP (funmem, rounded_stack_size_rtx, next_arg_reg,
-                           n_pop);
+       pat = targetm.gen_call_pop (funmem, rounded_stack_size_rtx,
+                                   next_arg_reg, n_pop);
 
-      emit_call_insn (pat);
       already_popped = 1;
     }
   else
-#endif
-
-#if defined (HAVE_sibcall) && defined (HAVE_sibcall_value)
-  if ((ecf_flags & ECF_SIBCALL)
-      && HAVE_sibcall && HAVE_sibcall_value)
-    {
-      if (valreg)
-       emit_call_insn (GEN_SIBCALL_VALUE (valreg, funmem,
-                                          rounded_stack_size_rtx,
-                                          next_arg_reg, NULL_RTX));
-      else
-       emit_call_insn (GEN_SIBCALL (funmem, rounded_stack_size_rtx,
-                                    next_arg_reg,
-                                    GEN_INT (struct_value_size)));
-    }
-  else
-#endif
-
-#if defined (HAVE_call) && defined (HAVE_call_value)
-  if (HAVE_call && HAVE_call_value)
     {
       if (valreg)
-       emit_call_insn (GEN_CALL_VALUE (valreg, funmem, rounded_stack_size_rtx,
-                                       next_arg_reg, NULL_RTX));
+       pat = targetm.gen_call_value (valreg, funmem, rounded_stack_size_rtx,
+                                     next_arg_reg, NULL_RTX);
       else
-       emit_call_insn (GEN_CALL (funmem, rounded_stack_size_rtx, next_arg_reg,
-                                 GEN_INT (struct_value_size)));
+       pat = targetm.gen_call (funmem, rounded_stack_size_rtx, next_arg_reg,
+                               GEN_INT (struct_value_size));
     }
-  else
-#endif
-    gcc_unreachable ();
+  emit_insn (pat);
 
   /* Find the call we just emitted.  */
-  call_insn = last_call_insn ();
+  rtx_call_insn *call_insn = last_call_insn ();
 
   /* Some target create a fresh MEM instead of reusing the one provided
      above.  Set its MEM_EXPR.  */
@@ -398,6 +365,10 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU
       && MEM_EXPR (funmem) != NULL_TREE)
     set_mem_expr (XEXP (call, 0), MEM_EXPR (funmem));
 
+  /* Mark instrumented calls.  */
+  if (call && fntree)
+    CALL_EXPR_WITH_BOUNDS_P (call) = CALL_WITH_BOUNDS_P (fntree);
+
   /* Put the register usage information there.  */
   add_function_usage_to (call_insn, call_fusage);
 
@@ -504,8 +475,16 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU
 static int
 special_function_p (const_tree fndecl, int flags)
 {
-  if (fndecl && DECL_NAME (fndecl)
-      && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 17
+  tree name_decl = DECL_NAME (fndecl);
+
+  /* For instrumentation clones we want to derive flags
+     from the original name.  */
+  if (cgraph_node::get (fndecl)
+      && cgraph_node::get (fndecl)->instrumentation_clone)
+    name_decl = DECL_NAME (cgraph_node::get (fndecl)->orig_decl);
+
+  if (fndecl && name_decl
+      && IDENTIFIER_LENGTH (name_decl) <= 17
       /* Exclude functions not at the file scope, or not `extern',
         since they are not the magic functions we would otherwise
         think they are.
@@ -517,18 +496,15 @@ special_function_p (const_tree fndecl, int flags)
          || TREE_CODE (DECL_CONTEXT (fndecl)) == TRANSLATION_UNIT_DECL)
       && TREE_PUBLIC (fndecl))
     {
-      const char *name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
+      const char *name = IDENTIFIER_POINTER (name_decl);
       const char *tname = name;
 
       /* We assume that alloca will always be called by name.  It
         makes no sense to pass it as a pointer-to-function to
         anything that does not understand its behavior.  */
-      if (((IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 6
-           && name[0] == 'a'
-           && ! strcmp (name, "alloca"))
-          || (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 16
-              && name[0] == '_'
-              && ! strcmp (name, "__builtin_alloca"))))
+      if (IDENTIFIER_LENGTH (name_decl) == 6
+         && name[0] == 'a'
+         && ! strcmp (name, "alloca"))
        flags |= ECF_MAY_BE_ALLOCA;
 
       /* Disregard prefix _, __, __x or __builtin_.  */
@@ -574,6 +550,17 @@ special_function_p (const_tree fndecl, int flags)
        flags |= ECF_NORETURN;
     }
 
+  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+    switch (DECL_FUNCTION_CODE (fndecl))
+      {
+      case BUILT_IN_ALLOCA:
+      case BUILT_IN_ALLOCA_WITH_ALIGN:
+       flags |= ECF_MAY_BE_ALLOCA;
+       break;
+      default:
+       break;
+      }
+
   return flags;
 }
 
@@ -626,7 +613,7 @@ setjmp_call_p (const_tree fndecl)
 /* Return true if STMT is an alloca call.  */
 
 bool
-gimple_alloca_call_p (const_gimple stmt)
+gimple_alloca_call_p (const gimple *stmt)
 {
   tree fndecl;
 
@@ -794,6 +781,8 @@ call_expr_flags (const_tree t)
 
   if (decl)
     flags = flags_from_decl_or_type (decl);
+  else if (CALL_EXPR_FN (t) == NULL_TREE)
+    flags = internal_fn_flags (CALL_EXPR_IFN (t));
   else
     {
       t = TREE_TYPE (CALL_EXPR_FN (t));
@@ -806,6 +795,50 @@ call_expr_flags (const_tree t)
   return flags;
 }
 
+/* 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);
+}
+
+
 /* Precompute all register parameters as described by ARGS, storing values
    into fields within the ARGS array.
 
@@ -872,8 +905,9 @@ precompute_register_parameters (int num_actuals, struct arg_data *args,
                     || (GET_CODE (args[i].value) == SUBREG
                         && REG_P (SUBREG_REG (args[i].value)))))
                 && args[i].mode != BLKmode
-                && set_src_cost (args[i].value, optimize_insn_for_speed_p ())
-                   > COSTS_N_INSNS (1)
+                && (set_src_cost (args[i].value, args[i].mode,
+                                  optimize_insn_for_speed_p ())
+                    > COSTS_N_INSNS (1))
                 && ((*reg_parm_seen
                      && targetm.small_register_classes_for_mode_p (args[i].mode))
                     || optimize))
@@ -895,9 +929,9 @@ save_fixed_argument_area (int reg_parm_stack_space, rtx argblock, int *low_to_sa
 
   /* Compute the boundary of the area that needs to be saved, if any.  */
   high = reg_parm_stack_space;
-#ifdef ARGS_GROW_DOWNWARD
-  high += 1;
-#endif
+  if (ARGS_GROW_DOWNWARD)
+    high += 1;
+
   if (high > highest_outgoing_arg_in_use)
     high = highest_outgoing_arg_in_use;
 
@@ -905,7 +939,7 @@ save_fixed_argument_area (int reg_parm_stack_space, rtx argblock, int *low_to_sa
     if (stack_usage_map[low] != 0)
       {
        int num_to_save;
-       enum machine_mode save_mode;
+       machine_mode save_mode;
        int delta;
        rtx addr;
        rtx stack_area;
@@ -926,11 +960,11 @@ save_fixed_argument_area (int reg_parm_stack_space, rtx argblock, int *low_to_sa
                         BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1)))
          save_mode = BLKmode;
 
-#ifdef ARGS_GROW_DOWNWARD
-       delta = -high;
-#else
-       delta = low;
-#endif
+       if (ARGS_GROW_DOWNWARD)
+         delta = -high;
+       else
+         delta = low;
+
        addr = plus_constant (Pmode, argblock, delta);
        stack_area = gen_rtx_MEM (save_mode, memory_address (save_mode, addr));
 
@@ -956,15 +990,15 @@ save_fixed_argument_area (int reg_parm_stack_space, rtx argblock, int *low_to_sa
 static void
 restore_fixed_argument_area (rtx save_area, rtx argblock, int high_to_save, int low_to_save)
 {
-  enum machine_mode save_mode = GET_MODE (save_area);
+  machine_mode save_mode = GET_MODE (save_area);
   int delta;
   rtx addr, stack_area;
 
-#ifdef ARGS_GROW_DOWNWARD
-  delta = -high_to_save;
-#else
-  delta = low_to_save;
-#endif
+  if (ARGS_GROW_DOWNWARD)
+    delta = -high_to_save;
+  else
+    delta = low_to_save;
+
   addr = plus_constant (Pmode, argblock, delta);
   stack_area = gen_rtx_MEM (save_mode, memory_address (save_mode, addr));
   set_mem_align (stack_area, PARM_BOUNDARY);
@@ -1039,7 +1073,7 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
 
            args[i].aligned_regs[j] = reg;
            word = extract_bit_field (word, bitsize, 0, 1, NULL_RTX,
-                                     word_mode, word_mode);
+                                     word_mode, word_mode, false);
 
            /* There is no need to restrict this code to loading items
               in TYPE_ALIGN sized hunks.  The bitfield instructions can
@@ -1056,7 +1090,7 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
 
            bytes -= bitsize / BITS_PER_UNIT;
            store_bit_field (reg, bitsize, endian_correction, 0, 0,
-                            word_mode, word);
+                            word_mode, word, false);
          }
       }
 }
@@ -1083,7 +1117,7 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals)
    and may be modified by this routine.
 
    OLD_PENDING_ADJ, MUST_PREALLOCATE and FLAGS are pointers to integer
-   flags which may may be modified by this routine.
+   flags which may be modified by this routine.
 
    MAY_TAILCALL is cleared if we encounter an invisible pass-by-reference
    that requires allocation of stack space.
@@ -1115,23 +1149,86 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
   args_size->constant = 0;
   args_size->var = 0;
 
+  bitmap_obstack_initialize (NULL);
+
   /* In this loop, we consider args in the order they are written.
      We fill up ARGS from the back.  */
 
   i = num_actuals - 1;
   {
-    int j = i;
+    int j = i, ptr_arg = -1;
     call_expr_arg_iterator iter;
     tree arg;
+    bitmap slots = NULL;
 
     if (struct_value_addr_value)
       {
        args[j].tree_value = struct_value_addr_value;
        j--;
+
+       /* If we pass structure address then we need to
+          create bounds for it.  Since created bounds is
+          a call statement, we expand it right here to avoid
+          fixing all other places where it may be expanded.  */
+       if (CALL_WITH_BOUNDS_P (exp))
+         {
+           args[j].value = gen_reg_rtx (targetm.chkp_bound_mode ());
+           args[j].tree_value
+             = chkp_make_bounds_for_struct_addr (struct_value_addr_value);
+           expand_expr_real (args[j].tree_value, args[j].value, VOIDmode,
+                             EXPAND_NORMAL, 0, false);
+           args[j].pointer_arg = j + 1;
+           j--;
+         }
       }
     FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
       {
        tree argtype = TREE_TYPE (arg);
+
+       /* Remember last param with pointer and associate it
+          with following pointer bounds.  */
+       if (CALL_WITH_BOUNDS_P (exp)
+           && chkp_type_has_pointer (argtype))
+         {
+           if (slots)
+             BITMAP_FREE (slots);
+           ptr_arg = j;
+           if (!BOUNDED_TYPE_P (argtype))
+             {
+               slots = BITMAP_ALLOC (NULL);
+               chkp_find_bound_slots (argtype, slots);
+             }
+         }
+       else if (POINTER_BOUNDS_TYPE_P (argtype))
+         {
+           /* We expect bounds in instrumented calls only.
+              Otherwise it is a sign we lost flag due to some optimization
+              and may emit call args incorrectly.  */
+           gcc_assert (CALL_WITH_BOUNDS_P (exp));
+
+           /* For structures look for the next available pointer.  */
+           if (ptr_arg != -1 && slots)
+             {
+               unsigned bnd_no = bitmap_first_set_bit (slots);
+               args[j].pointer_offset =
+                 bnd_no * POINTER_SIZE / BITS_PER_UNIT;
+
+               bitmap_clear_bit (slots, bnd_no);
+
+               /* Check we have no more pointers in the structure.  */
+               if (bitmap_empty_p (slots))
+                 BITMAP_FREE (slots);
+             }
+           args[j].pointer_arg = ptr_arg;
+
+           /* Check we covered all pointers in the previous
+              non bounds arg.  */
+           if (!slots)
+             ptr_arg = -1;
+         }
+       else
+         ptr_arg = -1;
+
        if (targetm.calls.split_complex_arg
            && argtype
            && TREE_CODE (argtype) == COMPLEX_TYPE
@@ -1146,14 +1243,19 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
          args[j].tree_value = arg;
        j--;
       }
+
+    if (slots)
+      BITMAP_FREE (slots);
   }
 
+  bitmap_obstack_release (NULL);
+
   /* I counts args in order (to be) pushed; ARGPOS counts in order written.  */
   for (argpos = 0; argpos < num_actuals; i--, argpos++)
     {
       tree type = TREE_TYPE (args[i].tree_value);
       int unsignedp;
-      enum machine_mode mode;
+      machine_mode mode;
 
       /* Replace erroneous argument with constant zero.  */
       if (type == error_mark_node || !COMPLETE_TYPE_P (type))
@@ -1200,6 +1302,25 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
                  && TREE_CODE (base) != SSA_NAME
                  && (!DECL_P (base) || MEM_P (DECL_RTL (base)))))
            {
+             /* We may have turned the parameter value into an SSA name.
+                Go back to the original parameter so we can take the
+                address.  */
+             if (TREE_CODE (args[i].tree_value) == SSA_NAME)
+               {
+                 gcc_assert (SSA_NAME_IS_DEFAULT_DEF (args[i].tree_value));
+                 args[i].tree_value = SSA_NAME_VAR (args[i].tree_value);
+                 gcc_assert (TREE_CODE (args[i].tree_value) == PARM_DECL);
+               }
+             /* Argument setup code may have copied the value to register.  We
+                revert that optimization now because the tail call code must
+                use the original location.  */
+             if (TREE_CODE (args[i].tree_value) == PARM_DECL
+                 && !MEM_P (DECL_RTL (args[i].tree_value))
+                 && DECL_INCOMING_RTL (args[i].tree_value)
+                 && MEM_P (DECL_INCOMING_RTL (args[i].tree_value)))
+               set_decl_rtl (args[i].tree_value,
+                             DECL_INCOMING_RTL (args[i].tree_value));
+
              mark_addressable (args[i].tree_value);
 
              /* We can't use sibcalls if a callee-copied argument is
@@ -1250,7 +1371,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
              else
                copy = assign_temp (type, 1, 0);
 
-             store_expr (args[i].tree_value, copy, 0, false);
+             store_expr (args[i].tree_value, copy, 0, false, false);
 
              /* Just change the const function to pure and then let
                 the next test clear the pure based on
@@ -1281,6 +1402,12 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
       args[i].reg = targetm.calls.function_arg (args_so_far, mode, type,
                                                argpos < n_named_args);
 
+      if (args[i].reg && CONST_INT_P (args[i].reg))
+       {
+         args[i].special_slot = args[i].reg;
+         args[i].reg = NULL;
+       }
+
       /* If this is a sibling call and the machine has register windows, the
         register window has to be unwinded before calling the routine, so
         arguments have to go into the incoming registers.  */
@@ -1314,10 +1441,13 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
          || (args[i].pass_on_stack && args[i].reg != 0))
        *must_preallocate = 1;
 
+      /* No stack allocation and padding for bounds.  */
+      if (POINTER_BOUNDS_P (args[i].tree_value))
+       ;
       /* Compute the stack-size of this argument.  */
-      if (args[i].reg == 0 || args[i].partial != 0
-         || reg_parm_stack_space > 0
-         || args[i].pass_on_stack)
+      else if (args[i].reg == 0 || args[i].partial != 0
+              || reg_parm_stack_space > 0
+              || args[i].pass_on_stack)
        locate_and_pad_parm (mode, type,
 #ifdef STACK_PARMS_IN_REG_PARM_AREA
                             1,
@@ -1456,7 +1586,7 @@ precompute_arguments (int num_actuals, struct arg_data *args)
   for (i = 0; i < num_actuals; i++)
     {
       tree type;
-      enum machine_mode mode;
+      machine_mode mode;
 
       if (TREE_CODE (args[i].tree_value) != CALL_EXPR)
        continue;
@@ -1531,6 +1661,12 @@ finalize_must_preallocate (int must_preallocate, int num_actuals,
            partial_seen = 1;
          else if (partial_seen && args[i].reg == 0)
            must_preallocate = 1;
+         /* We preallocate in case there are bounds passed
+            in the bounds table to have precomputed address
+            for bounds association.  */
+         else if (POINTER_BOUNDS_P (args[i].tree_value)
+                  && !args[i].reg)
+           must_preallocate = 1;
 
          if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode
              && (TREE_CODE (args[i].tree_value) == CALL_EXPR
@@ -1574,7 +1710,7 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals
          rtx addr;
          unsigned int align, boundary;
          unsigned int units_on_stack = 0;
-         enum machine_mode partial_mode = VOIDmode;
+         machine_mode partial_mode = VOIDmode;
 
          /* Skip this parm if it will not be passed on the stack.  */
          if (! args[i].pass_on_stack
@@ -1582,6 +1718,10 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals
              && args[i].partial == 0)
            continue;
 
+         /* Pointer Bounds are never passed on the stack.  */
+         if (POINTER_BOUNDS_P (args[i].tree_value))
+           continue;
+
          if (CONST_INT_P (offset))
            addr = plus_constant (Pmode, arg_reg, INTVAL (offset));
          else
@@ -1815,15 +1955,16 @@ mem_overlaps_already_clobbered_arg_p (rtx addr, unsigned HOST_WIDE_INT size)
     return true;
   else
     i = INTVAL (val);
-#ifdef STACK_GROWS_DOWNWARD
-  i -= crtl->args.pretend_args_size;
-#else
-  i += crtl->args.pretend_args_size;
-#endif
 
-#ifdef ARGS_GROW_DOWNWARD
-  i = -i - size;
-#endif
+  if (STACK_GROWS_DOWNWARD)
+    i -= crtl->args.pretend_args_size;
+  else
+    i += crtl->args.pretend_args_size;
+
+
+  if (ARGS_GROW_DOWNWARD)
+    i = -i - size;
+
   if (size > 0)
     {
       unsigned HOST_WIDE_INT k;
@@ -1940,6 +2081,26 @@ load_register_parameters (struct arg_data *args, int num_actuals,
                                           (XEXP (args[i].value, 0), size)))
                *sibcall_failure = 1;
 
+             if (size % UNITS_PER_WORD == 0
+                 || MEM_ALIGN (mem) % BITS_PER_WORD == 0)
+               move_block_to_reg (REGNO (reg), mem, nregs, args[i].mode);
+             else
+               {
+                 if (nregs > 1)
+                   move_block_to_reg (REGNO (reg), mem, nregs - 1,
+                                      args[i].mode);
+                 rtx dest = gen_rtx_REG (word_mode, REGNO (reg) + nregs - 1);
+                 unsigned int bitoff = (nregs - 1) * BITS_PER_WORD;
+                 unsigned int bitsize = size * BITS_PER_UNIT - bitoff;
+                 rtx x = extract_bit_field (mem, bitsize, bitoff, 1, dest,
+                                            word_mode, word_mode, false);
+                 if (BYTES_BIG_ENDIAN)
+                   x = expand_shift (LSHIFT_EXPR, word_mode, x,
+                                     BITS_PER_WORD - bitsize, dest, 1);
+                 if (x != dest)
+                   emit_move_insn (dest, x);
+               }
+
              /* Handle a BLKmode that needs shifting.  */
              if (nregs == 1 && size < UNITS_PER_WORD
 #ifdef BLOCK_REG_PADDING
@@ -1947,22 +2108,18 @@ load_register_parameters (struct arg_data *args, int num_actuals,
 #else
                  && BYTES_BIG_ENDIAN
 #endif
-                )
+                 )
                {
-                 rtx tem = operand_subword_force (mem, 0, args[i].mode);
-                 rtx ri = gen_rtx_REG (word_mode, REGNO (reg));
-                 rtx x = gen_reg_rtx (word_mode);
+                 rtx dest = gen_rtx_REG (word_mode, REGNO (reg));
                  int shift = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
-                 enum tree_code dir = BYTES_BIG_ENDIAN ? RSHIFT_EXPR
-                                                       : LSHIFT_EXPR;
+                 enum tree_code dir = (BYTES_BIG_ENDIAN
+                                       ? RSHIFT_EXPR : LSHIFT_EXPR);
+                 rtx x;
 
-                 emit_move_insn (x, tem);
-                 x = expand_shift (dir, word_mode, x, shift, ri, 1);
-                 if (x != ri)
-                   emit_move_insn (ri, x);
+                 x = expand_shift (dir, word_mode, dest, shift, dest, 1);
+                 if (x != dest)
+                   emit_move_insn (dest, x);
                }
-             else
-               move_block_to_reg (REGNO (reg), mem, nregs, args[i].mode);
            }
 
          /* When a parameter is a block, and perhaps in other cases, it is
@@ -2111,11 +2268,10 @@ check_sibcall_argument_overlap (rtx_insn *insn, struct arg_data *arg,
 
   if (mark_stored_args_map)
     {
-#ifdef ARGS_GROW_DOWNWARD
-      low = -arg->locate.slot_offset.constant - arg->locate.size.constant;
-#else
-      low = arg->locate.slot_offset.constant;
-#endif
+      if (ARGS_GROW_DOWNWARD)
+       low = -arg->locate.slot_offset.constant - arg->locate.size.constant;
+      else
+       low = arg->locate.slot_offset.constant;
 
       for (high = low + arg->locate.size.constant; low < high; low++)
        bitmap_set_bit (stored_args_map, low);
@@ -2128,7 +2284,7 @@ check_sibcall_argument_overlap (rtx_insn *insn, struct arg_data *arg,
    as specified by LEFT_P.  Return true if some action was needed.  */
 
 bool
-shift_return_value (enum machine_mode mode, bool left_p, rtx value)
+shift_return_value (machine_mode mode, bool left_p, rtx value)
 {
   HOST_WIDE_INT shift;
 
@@ -2204,6 +2360,8 @@ expand_call (tree exp, rtx target, int ignore)
   /* Register in which non-BLKmode value will be returned,
      or 0 if no value or if value is BLKmode.  */
   rtx valreg;
+  /* Register(s) in which bounds are returned.  */
+  rtx valbnd = NULL;
   /* Address where we should return a BLKmode value;
      0 if value not BLKmode.  */
   rtx structure_value_addr = 0;
@@ -2462,7 +2620,7 @@ expand_call (tree exp, rtx target, int ignore)
 
       structure_value_addr_value =
        make_tree (build_pointer_type (TREE_TYPE (funtype)), temp);
-      structure_value_addr_parm = 1;
+      structure_value_addr_parm = CALL_WITH_BOUNDS_P (exp) ? 2 : 1;
     }
 
   /* Count the arguments and set NUM_ACTUALS.  */
@@ -2565,13 +2723,8 @@ expand_call (tree exp, rtx target, int ignore)
     try_tail_call = 0;
 
   /*  Rest of purposes for tail call optimizations to fail.  */
-  if (
-#ifdef HAVE_sibcall_epilogue
-      !HAVE_sibcall_epilogue
-#else
-      1
-#endif
-      || !try_tail_call
+  if (!try_tail_call
+      || !targetm.have_sibcall_epilogue ()
       /* Doing sibling call optimization needs some work, since
         structure_value_addr can be allocated on the stack.
         It does not seem worth the effort since few optimizable
@@ -2613,8 +2766,8 @@ expand_call (tree exp, rtx target, int ignore)
      return value.  */
   if (try_tail_call)
     {
-      enum machine_mode caller_mode, caller_promoted_mode;
-      enum machine_mode callee_mode, callee_promoted_mode;
+      machine_mode caller_mode, caller_promoted_mode;
+      machine_mode callee_mode, callee_promoted_mode;
       int caller_unsignedp, callee_unsignedp;
       tree caller_res = DECL_RESULT (current_function_decl);
 
@@ -2732,12 +2885,13 @@ expand_call (tree exp, rtx target, int ignore)
       if (pass == 0)
        {
          argblock = crtl->args.internal_arg_pointer;
-         argblock
-#ifdef STACK_GROWS_DOWNWARD
-           = plus_constant (Pmode, argblock, crtl->args.pretend_args_size);
-#else
-           = plus_constant (Pmode, argblock, -crtl->args.pretend_args_size);
-#endif
+         if (STACK_GROWS_DOWNWARD)
+           argblock
+             = plus_constant (Pmode, argblock, crtl->args.pretend_args_size);
+         else
+           argblock
+             = plus_constant (Pmode, argblock, -crtl->args.pretend_args_size);
+
          stored_args_map = sbitmap_alloc (args_size.constant);
          bitmap_clear (stored_args_map);
        }
@@ -2802,13 +2956,13 @@ expand_call (tree exp, rtx target, int ignore)
                  if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl))))
                    needed += reg_parm_stack_space;
 
-#ifdef ARGS_GROW_DOWNWARD
-                 highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
-                                                    needed + 1);
-#else
-                 highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
-                                                    needed);
-#endif
+                 if (ARGS_GROW_DOWNWARD)
+                   highest_outgoing_arg_in_use
+                     = MAX (initial_highest_arg_in_use, needed + 1);
+                 else
+                   highest_outgoing_arg_in_use
+                     = MAX (initial_highest_arg_in_use, needed);
+
                  free (stack_usage_map_buf);
                  stack_usage_map_buf = XNEWVEC (char, highest_outgoing_arg_in_use);
                  stack_usage_map = stack_usage_map_buf;
@@ -2870,9 +3024,8 @@ expand_call (tree exp, rtx target, int ignore)
                  else
                    {
                      argblock = push_block (GEN_INT (needed), 0, 0);
-#ifdef ARGS_GROW_DOWNWARD
-                     argblock = plus_constant (Pmode, argblock, needed);
-#endif
+                     if (ARGS_GROW_DOWNWARD)
+                       argblock = plus_constant (Pmode, argblock, needed);
                    }
 
                  /* We only really need to call `copy_to_reg' in the case
@@ -2938,6 +3091,19 @@ expand_call (tree exp, rtx target, int ignore)
 
       compute_argument_addresses (args, argblock, num_actuals);
 
+      /* Stack is properly aligned, pops can't safely be deferred during
+        the evaluation of the arguments.  */
+      NO_DEFER_POP;
+
+      /* Precompute all register parameters.  It isn't safe to compute
+        anything once we have started filling any specific hard regs.
+        TLS symbols sometimes need a call to resolve.  Precompute
+        register parameters before any stack pointer manipulation
+        to avoid unaligned stack in the called function.  */
+      precompute_register_parameters (num_actuals, args, &reg_parm_seen);
+
+      OK_DEFER_POP;
+
       /* Perform stack alignment before the first push (the last arg).  */
       if (argblock == 0
           && adjusted_args_size.constant > reg_parm_stack_space
@@ -2978,36 +3144,6 @@ expand_call (tree exp, rtx target, int ignore)
 
       funexp = rtx_for_function_call (fndecl, addr);
 
-      /* Figure out the register where the value, if any, will come back.  */
-      valreg = 0;
-      if (TYPE_MODE (rettype) != VOIDmode
-         && ! structure_value_addr)
-       {
-         if (pcc_struct_value)
-           valreg = hard_function_value (build_pointer_type (rettype),
-                                         fndecl, NULL, (pass == 0));
-         else
-           valreg = hard_function_value (rettype, fndecl, fntype,
-                                         (pass == 0));
-
-         /* If VALREG is a PARALLEL whose first member has a zero
-            offset, use that.  This is for targets such as m68k that
-            return the same value in multiple places.  */
-         if (GET_CODE (valreg) == PARALLEL)
-           {
-             rtx elem = XVECEXP (valreg, 0, 0);
-             rtx where = XEXP (elem, 0);
-             rtx offset = XEXP (elem, 1);
-             if (offset == const0_rtx
-                 && GET_MODE (where) == GET_MODE (valreg))
-               valreg = where;
-           }
-       }
-
-      /* Precompute all register parameters.  It isn't safe to compute anything
-        once we have started filling any specific hard regs.  */
-      precompute_register_parameters (num_actuals, args, &reg_parm_seen);
-
       if (CALL_EXPR_STATIC_CHAIN (exp))
        static_chain_value = expand_normal (CALL_EXPR_STATIC_CHAIN (exp));
       else
@@ -3029,7 +3165,10 @@ expand_call (tree exp, rtx target, int ignore)
 
       for (i = 0; i < num_actuals; i++)
        {
-         if (args[i].reg == 0 || args[i].pass_on_stack)
+         /* Delay bounds until all other args are stored.  */
+         if (POINTER_BOUNDS_P (args[i].tree_value))
+           continue;
+         else if (args[i].reg == 0 || args[i].pass_on_stack)
            {
              rtx_insn *before_arg = get_last_insn ();
 
@@ -3073,6 +3212,15 @@ expand_call (tree exp, rtx target, int ignore)
            {
              rtx_insn *before_arg = get_last_insn ();
 
+            /* On targets with weird calling conventions (e.g. PA) it's
+               hard to ensure that all cases of argument overlap between
+               stack and registers work.  Play it safe and bail out.  */
+             if (ARGS_GROW_DOWNWARD && !STACK_GROWS_DOWNWARD)
+               {
+                 sibcall_failure = 1;
+                 break;
+               }
+
              if (store_one_arg (&args[i], argblock, flags,
                                 adjusted_args_size.var != 0,
                                 reg_parm_stack_space)
@@ -3082,6 +3230,66 @@ expand_call (tree exp, rtx target, int ignore)
                sibcall_failure = 1;
            }
 
+      bool any_regs = false;
+      for (i = 0; i < num_actuals; i++)
+       if (args[i].reg != NULL_RTX)
+         {
+           any_regs = true;
+           targetm.calls.call_args (args[i].reg, funtype);
+         }
+      if (!any_regs)
+       targetm.calls.call_args (pc_rtx, funtype);
+
+      /* Figure out the register where the value, if any, will come back.  */
+      valreg = 0;
+      valbnd = 0;
+      if (TYPE_MODE (rettype) != VOIDmode
+         && ! structure_value_addr)
+       {
+         if (pcc_struct_value)
+           {
+             valreg = hard_function_value (build_pointer_type (rettype),
+                                           fndecl, NULL, (pass == 0));
+             if (CALL_WITH_BOUNDS_P (exp))
+               valbnd = targetm.calls.
+                 chkp_function_value_bounds (build_pointer_type (rettype),
+                                             fndecl, (pass == 0));
+           }
+         else
+           {
+             valreg = hard_function_value (rettype, fndecl, fntype,
+                                           (pass == 0));
+             if (CALL_WITH_BOUNDS_P (exp))
+               valbnd = targetm.calls.chkp_function_value_bounds (rettype,
+                                                                  fndecl,
+                                                                  (pass == 0));
+           }
+
+         /* If VALREG is a PARALLEL whose first member has a zero
+            offset, use that.  This is for targets such as m68k that
+            return the same value in multiple places.  */
+         if (GET_CODE (valreg) == PARALLEL)
+           {
+             rtx elem = XVECEXP (valreg, 0, 0);
+             rtx where = XEXP (elem, 0);
+             rtx offset = XEXP (elem, 1);
+             if (offset == const0_rtx
+                 && GET_MODE (where) == GET_MODE (valreg))
+               valreg = where;
+           }
+       }
+
+      /* Store all bounds not passed in registers.  */
+      for (i = 0; i < num_actuals; i++)
+       {
+         if (POINTER_BOUNDS_P (args[i].tree_value)
+             && !args[i].reg)
+           store_bounds (&args[i],
+                         args[i].pointer_arg == -1
+                         ? NULL
+                         : &args[args[i].pointer_arg]);
+       }
+
       /* If register arguments require space on the stack and stack space
         was not preallocated, allocate stack space here for arguments
         passed in registers.  */
@@ -3106,8 +3314,9 @@ expand_call (tree exp, rtx target, int ignore)
        }
 
       after_args = get_last_insn ();
-      funexp = prepare_call_address (fndecl, funexp, static_chain_value,
-                                    &call_fusage, reg_parm_seen, pass == 0);
+      funexp = prepare_call_address (fndecl ? fndecl : fntype, funexp,
+                                    static_chain_value, &call_fusage,
+                                    reg_parm_seen, pass == 0);
 
       load_register_parameters (args, num_actuals, &call_fusage, flags,
                                pass == 0, &sibcall_failure);
@@ -3140,7 +3349,7 @@ expand_call (tree exp, rtx target, int ignore)
              && GET_MODE (args[arg_nr].reg) == GET_MODE (valreg))
          call_fusage
            = gen_rtx_EXPR_LIST (TYPE_MODE (TREE_TYPE (args[arg_nr].tree_value)),
-                                gen_rtx_SET (VOIDmode, valreg, args[arg_nr].reg),
+                                gen_rtx_SET (valreg, args[arg_nr].reg),
                                 call_fusage);
        }
       /* All arguments and registers used for the call must be set up by
@@ -3156,7 +3365,7 @@ expand_call (tree exp, rtx target, int ignore)
                   next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
                   flags, args_so_far);
 
-      if (flag_use_caller_save)
+      if (flag_ipa_ra)
        {
          rtx_call_insn *last;
          rtx datum = NULL_RTX;
@@ -3346,7 +3555,7 @@ expand_call (tree exp, rtx target, int ignore)
          tree type = rettype;
          int unsignedp = TYPE_UNSIGNED (type);
          int offset = 0;
-         enum machine_mode pmode;
+         machine_mode pmode;
 
          /* Ensure we promote as expected, and get the new unsignedness.  */
          pmode = promote_function_mode (type, TYPE_MODE (type), &unsignedp,
@@ -3401,7 +3610,7 @@ expand_call (tree exp, rtx target, int ignore)
          for (i = 0; i < num_actuals; i++)
            if (args[i].save_area)
              {
-               enum machine_mode save_mode = GET_MODE (args[i].save_area);
+               machine_mode save_mode = GET_MODE (args[i].save_area);
                rtx stack_area
                  = gen_rtx_MEM (save_mode,
                                 memory_address (save_mode,
@@ -3419,17 +3628,16 @@ expand_call (tree exp, rtx target, int ignore)
          stack_usage_map = initial_stack_usage_map;
        }
 
-      /* If this was alloca, record the new stack level for nonlocal gotos.
-        Check for the handler slots since we might not have a save area
-        for non-local gotos.  */
-
-      if ((flags & ECF_MAY_BE_ALLOCA) && cfun->nonlocal_goto_save_area != 0)
-       update_nonlocal_goto_save_area ();
+      /* If this was alloca, record the new stack level.  */
+      if (flags & ECF_MAY_BE_ALLOCA)
+       record_new_stack_level ();
 
       /* Free up storage we no longer need.  */
       for (i = 0; i < num_actuals; ++i)
        free (args[i].aligned_regs);
 
+      targetm.calls.end_call_args ();
+
       insns = get_insns ();
       end_sequence ();
 
@@ -3486,6 +3694,9 @@ expand_call (tree exp, rtx target, int ignore)
 
   free (stack_usage_map_buf);
 
+  /* Join result with returned bounds so caller may use them if needed.  */
+  target = chkp_join_splitted_slot (target, valbnd);
+
   return target;
 }
 
@@ -3577,7 +3788,7 @@ split_complex_types (tree types)
 static rtx
 emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
                           enum libcall_type fn_type,
-                          enum machine_mode outmode, int nargs, va_list p)
+                          machine_mode outmode, int nargs, va_list p)
 {
   /* Total size in bytes of all the stack-parms scanned so far.  */
   struct args_size args_size;
@@ -3596,7 +3807,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
   struct arg
   {
     rtx value;
-    enum machine_mode mode;
+    machine_mode mode;
     rtx reg;
     int partial;
     struct locate_and_pad_arg_data locate;
@@ -3613,6 +3824,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
   int reg_parm_stack_space = 0;
   int needed;
   rtx_insn *before_call;
+  bool have_push_fusage;
   tree tfom;                   /* type_for_mode (outmode, 0) */
 
 #ifdef REG_PARM_STACK_SPACE
@@ -3761,7 +3973,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
   for (; count < nargs; count++)
     {
       rtx val = va_arg (p, rtx);
-      enum machine_mode mode = (enum machine_mode) va_arg (p, int);
+      machine_mode mode = (machine_mode) va_arg (p, int);
       int unsigned_p = 0;
 
       /* We cannot convert the arg value to the mode the library wants here;
@@ -3901,13 +4113,12 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl))))
        needed += reg_parm_stack_space;
 
-#ifdef ARGS_GROW_DOWNWARD
-      highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
-                                        needed + 1);
-#else
-      highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
-                                        needed);
-#endif
+      if (ARGS_GROW_DOWNWARD)
+       highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
+                                          needed + 1);
+      else
+       highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, needed);
+
       stack_usage_map_buf = XNEWVEC (char, highest_outgoing_arg_in_use);
       stack_usage_map = stack_usage_map_buf;
 
@@ -3956,13 +4167,27 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
     }
 #endif
 
+  /* When expanding a normal call, args are stored in push order,
+     which is the reverse of what we have here.  */
+  bool any_regs = false;
+  for (int i = nargs; i-- > 0; )
+    if (argvec[i].reg != NULL_RTX)
+      {
+       targetm.calls.call_args (argvec[i].reg, NULL_TREE);
+       any_regs = true;
+      }
+  if (!any_regs)
+    targetm.calls.call_args (pc_rtx, NULL_TREE);
+
   /* Push the args that need to be pushed.  */
 
+  have_push_fusage = false;
+
   /* ARGNUM indexes the ARGVEC array in the order in which the arguments
      are to be pushed.  */
   for (count = 0; count < nargs; count++, argnum--)
     {
-      enum machine_mode mode = argvec[argnum].mode;
+      machine_mode mode = argvec[argnum].mode;
       rtx val = argvec[argnum].value;
       rtx reg = argvec[argnum].reg;
       int partial = argvec[argnum].partial;
@@ -3978,15 +4203,18 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
              /* If this is being stored into a pre-allocated, fixed-size,
                 stack area, save any previous data at that location.  */
 
-#ifdef ARGS_GROW_DOWNWARD
-             /* stack_slot is negative, but we want to index stack_usage_map
-                with positive values.  */
-             upper_bound = -argvec[argnum].locate.slot_offset.constant + 1;
-             lower_bound = upper_bound - argvec[argnum].locate.size.constant;
-#else
-             lower_bound = argvec[argnum].locate.slot_offset.constant;
-             upper_bound = lower_bound + argvec[argnum].locate.size.constant;
-#endif
+             if (ARGS_GROW_DOWNWARD)
+               {
+                 /* stack_slot is negative, but we want to index stack_usage_map
+                    with positive values.  */
+                 upper_bound = -argvec[argnum].locate.slot_offset.constant + 1;
+                 lower_bound = upper_bound - argvec[argnum].locate.size.constant;
+               }
+             else
+               {
+                 lower_bound = argvec[argnum].locate.slot_offset.constant;
+                 upper_bound = lower_bound + argvec[argnum].locate.size.constant;
+               }
 
              i = lower_bound;
              /* Don't worry about things in the fixed argument area;
@@ -4001,7 +4229,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
                  /* We need to make a save area.  */
                  unsigned int size
                    = argvec[argnum].locate.size.constant * BITS_PER_UNIT;
-                 enum machine_mode save_mode
+                 machine_mode save_mode
                    = mode_for_size (size, MODE_INT, 1);
                  rtx adr
                    = plus_constant (Pmode, argblock,
@@ -4035,7 +4263,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
                          partial, reg, 0, argblock,
                          GEN_INT (argvec[argnum].locate.offset.constant),
                          reg_parm_stack_space,
-                         ARGS_SIZE_RTX (argvec[argnum].locate.alignment_pad));
+                         ARGS_SIZE_RTX (argvec[argnum].locate.alignment_pad), false);
 
          /* Now mark the segment we just used.  */
          if (ACCUMULATE_OUTGOING_ARGS)
@@ -4049,14 +4277,19 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
          if (argblock)
            use = plus_constant (Pmode, argblock,
                                 argvec[argnum].locate.offset.constant);
+         else if (have_push_fusage)
+           continue;
          else
-           /* When arguments are pushed, trying to tell alias.c where
-              exactly this argument is won't work, because the
-              auto-increment causes confusion.  So we merely indicate
-              that we access something with a known mode somewhere on
-              the stack.  */
-           use = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
-                               gen_rtx_SCRATCH (Pmode));
+           {
+             /* When arguments are pushed, trying to tell alias.c where
+                exactly this argument is won't work, because the
+                auto-increment causes confusion.  So we merely indicate
+                that we access something with a known mode somewhere on
+                the stack.  */
+             use = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+                                 gen_rtx_SCRATCH (Pmode));
+             have_push_fusage = true;
+           }
          use = gen_rtx_MEM (argvec[argnum].mode, use);
          use = gen_rtx_USE (VOIDmode, use);
          call_fusage = gen_rtx_EXPR_LIST (VOIDmode, use, call_fusage);
@@ -4073,7 +4306,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
      are to be pushed.  */
   for (count = 0; count < nargs; count++, argnum--)
     {
-      enum machine_mode mode = argvec[argnum].mode;
+      machine_mode mode = argvec[argnum].mode;
       rtx val = argvec[argnum].value;
       rtx reg = argvec[argnum].reg;
       int partial = argvec[argnum].partial;
@@ -4179,11 +4412,11 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
               valreg,
               old_inhibit_defer_pop + 1, call_fusage, flags, args_so_far);
 
-  if (flag_use_caller_save)
+  if (flag_ipa_ra)
     {
-      rtx last, datum = orgfun;
+      rtx datum = orgfun;
       gcc_assert (GET_CODE (datum) == SYMBOL_REF);
-      last = last_call_insn ();
+      rtx_call_insn *last = last_call_insn ();
       add_reg_note (last, REG_CALL_DECL, datum);
     }
 
@@ -4196,6 +4429,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       valreg = gen_rtx_REG (TYPE_MODE (tfom), REGNO (valreg));
     }
 
+  targetm.calls.end_call_args ();
+
   /* For calls to `setjmp', etc., inform function.c:setjmp_warnings
      that it should complain if nonvolatile values are live.  For
      functions that cannot return, inform flow that control does not
@@ -4284,7 +4519,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       for (count = 0; count < nargs; count++)
        if (argvec[count].save_area)
          {
-           enum machine_mode save_mode = GET_MODE (argvec[count].save_area);
+           machine_mode save_mode = GET_MODE (argvec[count].save_area);
            rtx adr = plus_constant (Pmode, argblock,
                                     argvec[count].locate.offset.constant);
            rtx stack_area = gen_rtx_MEM (save_mode,
@@ -4322,7 +4557,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
 void
 emit_library_call (rtx orgfun, enum libcall_type fn_type,
-                  enum machine_mode outmode, int nargs, ...)
+                  machine_mode outmode, int nargs, ...)
 {
   va_list p;
 
@@ -4342,7 +4577,7 @@ emit_library_call (rtx orgfun, enum libcall_type fn_type,
 rtx
 emit_library_call_value (rtx orgfun, rtx value,
                         enum libcall_type fn_type,
-                        enum machine_mode outmode, int nargs, ...)
+                        machine_mode outmode, int nargs, ...)
 {
   rtx result;
   va_list p;
@@ -4355,6 +4590,68 @@ emit_library_call_value (rtx orgfun, rtx value,
   return result;
 }
 \f
+
+/* Store pointer bounds argument ARG  into Bounds Table entry
+   associated with PARM.  */
+static void
+store_bounds (struct arg_data *arg, struct arg_data *parm)
+{
+  rtx slot = NULL, ptr = NULL, addr = NULL;
+
+  /* We may pass bounds not associated with any pointer.  */
+  if (!parm)
+    {
+      gcc_assert (arg->special_slot);
+      slot = arg->special_slot;
+      ptr = const0_rtx;
+    }
+  /* Find pointer associated with bounds and where it is
+     passed.  */
+  else
+    {
+      if (!parm->reg)
+       {
+         gcc_assert (!arg->special_slot);
+
+         addr = adjust_address (parm->stack, Pmode, arg->pointer_offset);
+       }
+      else if (REG_P (parm->reg))
+       {
+         gcc_assert (arg->special_slot);
+         slot = arg->special_slot;
+
+         if (MEM_P (parm->value))
+           addr = adjust_address (parm->value, Pmode, arg->pointer_offset);
+         else if (REG_P (parm->value))
+           ptr = gen_rtx_SUBREG (Pmode, parm->value, arg->pointer_offset);
+         else
+           {
+             gcc_assert (!arg->pointer_offset);
+             ptr = parm->value;
+           }
+       }
+      else
+       {
+         gcc_assert (GET_CODE (parm->reg) == PARALLEL);
+
+         gcc_assert (arg->special_slot);
+         slot = arg->special_slot;
+
+         if (parm->parallel_value)
+           ptr = chkp_get_value_with_offs (parm->parallel_value,
+                                           GEN_INT (arg->pointer_offset));
+         else
+           gcc_unreachable ();
+       }
+    }
+
+  /* Expand bounds.  */
+  if (!arg->value)
+    arg->value = expand_normal (arg->tree_value);
+
+  targetm.calls.store_bounds_for_arg (ptr, addr, arg->value, slot);
+}
+
 /* Store a single argument for a function call
    into the register or memory area where it must be passed.
    *ARG describes the argument value and where to pass it.
@@ -4398,23 +4695,26 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
         save any previous data at that location.  */
       if (argblock && ! variable_size && arg->stack)
        {
-#ifdef ARGS_GROW_DOWNWARD
-         /* stack_slot is negative, but we want to index stack_usage_map
-            with positive values.  */
-         if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS)
-           upper_bound = -INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)) + 1;
-         else
-           upper_bound = 0;
+         if (ARGS_GROW_DOWNWARD)
+           {
+             /* stack_slot is negative, but we want to index stack_usage_map
+                with positive values.  */
+             if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS)
+               upper_bound = -INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)) + 1;
+             else
+               upper_bound = 0;
 
-         lower_bound = upper_bound - arg->locate.size.constant;
-#else
-         if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS)
-           lower_bound = INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1));
+             lower_bound = upper_bound - arg->locate.size.constant;
+           }
          else
-           lower_bound = 0;
+           {
+             if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS)
+               lower_bound = INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1));
+             else
+               lower_bound = 0;
 
-         upper_bound = lower_bound + arg->locate.size.constant;
-#endif
+             upper_bound = lower_bound + arg->locate.size.constant;
+           }
 
          i = lower_bound;
          /* Don't worry about things in the fixed argument area;
@@ -4428,7 +4728,7 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
            {
              /* We need to make a save area.  */
              unsigned int size = arg->locate.size.constant * BITS_PER_UNIT;
-             enum machine_mode save_mode = mode_for_size (size, MODE_INT, 1);
+             machine_mode save_mode = mode_for_size (size, MODE_INT, 1);
              rtx adr = memory_address (save_mode, XEXP (arg->stack_slot, 0));
              rtx stack_area = gen_rtx_MEM (save_mode, adr);
 
@@ -4573,10 +4873,11 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
 
       /* This isn't already where we want it on the stack, so put it there.
         This can either be done with push or copy insns.  */
-      emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX,
+      if (!emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX,
                      parm_align, partial, reg, used - size, argblock,
                      ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space,
-                     ARGS_SIZE_RTX (arg->locate.alignment_pad));
+                     ARGS_SIZE_RTX (arg->locate.alignment_pad), true))
+       sibcall_failure = 1;
 
       /* Unless this is a partially-in-register argument, the argument is now
         in the stack.  */
@@ -4646,6 +4947,13 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
              if (XEXP (x, 0) != crtl->args.internal_arg_pointer)
                i = INTVAL (XEXP (XEXP (x, 0), 1));
 
+             /* arg.locate doesn't contain the pretend_args_size offset,
+                it's part of argblock.  Ensure we don't count it in I.  */
+             if (STACK_GROWS_DOWNWARD)
+               i -= crtl->args.pretend_args_size;
+             else
+               i += crtl->args.pretend_args_size;
+
              /* expand_call should ensure this.  */
              gcc_assert (!arg->locate.offset.var
                          && arg->locate.size.var == 0
@@ -4681,7 +4989,7 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
       emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
                      parm_align, partial, reg, excess, argblock,
                      ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space,
-                     ARGS_SIZE_RTX (arg->locate.alignment_pad));
+                     ARGS_SIZE_RTX (arg->locate.alignment_pad), false);
 
       /* Unless this is a partially-in-register argument, the argument is now
         in the stack.
@@ -4722,7 +5030,7 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags,
 /* Nonzero if we do not know how to pass TYPE solely in registers.  */
 
 bool
-must_pass_in_stack_var_size (enum machine_mode mode ATTRIBUTE_UNUSED,
+must_pass_in_stack_var_size (machine_mode mode ATTRIBUTE_UNUSED,
                             const_tree type)
 {
   if (!type)
@@ -4745,7 +5053,7 @@ must_pass_in_stack_var_size (enum machine_mode mode ATTRIBUTE_UNUSED,
 /* ??? Should be able to merge these two by examining BLOCK_REG_PADDING.  */
 
 bool
-must_pass_in_stack_var_size_or_pad (enum machine_mode mode, const_tree type)
+must_pass_in_stack_var_size_or_pad (machine_mode mode, const_tree type)
 {
   if (!type)
     return false;