diff --git a/gcc/calls.cc b/gcc/calls.cc
index 51b664f1b4d..d3287bcc277 100644
--- a/gcc/calls.cc
+++ b/gcc/calls.cc
@@ -3542,15 +3542,26 @@ expand_call (tree exp, rtx target, int ignore)
 		sibcall_failure = 1;
 	    }
 
+      /* Set up the next argument register.  For sibling calls on machines
+	 with register windows this should be the incoming register.  */
+      if (pass == 0)
+	next_arg_reg = targetm.calls.function_incoming_arg
+	  (args_so_far, function_arg_info::end_marker ());
+      else
+	next_arg_reg = targetm.calls.function_arg
+	  (args_so_far, function_arg_info::end_marker ());
+
+      targetm.calls.start_call_args (args_so_far);
+
       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);
+	    targetm.calls.call_args (args_so_far, args[i].reg, funtype);
 	  }
       if (!any_regs)
-	targetm.calls.call_args (pc_rtx, funtype);
+	targetm.calls.call_args (args_so_far, pc_rtx, funtype);
 
       /* Figure out the register where the value, if any, will come back.  */
       valreg = 0;
@@ -3613,15 +3624,6 @@ expand_call (tree exp, rtx target, int ignore)
 	 later safely search backwards to find the CALL_INSN.  */
       before_call = get_last_insn ();
 
-      /* Set up next argument register.  For sibling calls on machines
-	 with register windows this should be the incoming register.  */
-      if (pass == 0)
-	next_arg_reg = targetm.calls.function_incoming_arg
-	  (args_so_far, function_arg_info::end_marker ());
-      else
-	next_arg_reg = targetm.calls.function_arg
-	  (args_so_far, function_arg_info::end_marker ());
-
       if (pass == 1 && (return_flags & ERF_RETURNS_ARG))
 	{
 	  int arg_nr = return_flags & ERF_RETURN_ARG_MASK;
@@ -3920,7 +3922,7 @@ expand_call (tree exp, rtx target, int ignore)
       for (i = 0; i < num_actuals; ++i)
 	free (args[i].aligned_regs);
 
-      targetm.calls.end_call_args ();
+      targetm.calls.end_call_args (args_so_far);
 
       insns = get_insns ();
       end_sequence ();
@@ -4478,17 +4480,9 @@ 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);
+  rtx call_cookie
+    = targetm.calls.function_arg (args_so_far,
+				  function_arg_info::end_marker ());
 
   /* Push the args that need to be pushed.  */
 
@@ -4606,6 +4600,20 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
   fun = prepare_call_address (NULL, fun, NULL, &call_fusage, 0, 0);
 
+  targetm.calls.start_call_args (args_so_far);
+
+  /* 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 (args_so_far, argvec[i].reg, NULL_TREE);
+	any_regs = true;
+      }
+  if (!any_regs)
+    targetm.calls.call_args (args_so_far, pc_rtx, NULL_TREE);
+
   /* Now load any reg parms into their regs.  */
 
   /* ARGNUM indexes the ARGVEC array in the order in which the arguments
@@ -4712,10 +4720,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 	       get_identifier (XSTR (orgfun, 0)),
 	       build_function_type (tfom, NULL_TREE),
 	       original_args_size.constant, args_size.constant,
-	       struct_value_size,
-	       targetm.calls.function_arg (args_so_far,
-					   function_arg_info::end_marker ()),
-	       valreg,
+	       struct_value_size, call_cookie, valreg,
 	       old_inhibit_defer_pop + 1, call_fusage, flags, args_so_far);
 
   if (flag_ipa_ra)
@@ -4735,7 +4740,7 @@ 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 ();
+  targetm.calls.end_call_args (args_so_far);
 
   /* For calls to `setjmp', etc., inform function.cc:setjmp_warnings
      that it should complain if nonvolatile values are live.  For
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index 2fe120b3873..0fa0aefe613 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -1790,7 +1790,7 @@ nvptx_get_drap_rtx (void)
    argument to the next call.  */
 
 static void
-nvptx_call_args (rtx arg, tree fntype)
+nvptx_call_args (cumulative_args_t, rtx arg, tree fntype)
 {
   if (!cfun->machine->doing_call)
     {
@@ -1818,7 +1818,7 @@ nvptx_call_args (rtx arg, tree fntype)
    information we recorded.  */
 
 static void
-nvptx_end_call_args (void)
+nvptx_end_call_args (cumulative_args_t)
 {
   cfun->machine->doing_call = false;
   free_EXPR_LIST_list (&cfun->machine->call_args);
diff --git a/gcc/doc/gccint/target-macros/implementing-the-varargs-macros.rst b/gcc/doc/gccint/target-macros/implementing-the-varargs-macros.rst
index 1c940945056..8dd1ffab1b4 100644
--- a/gcc/doc/gccint/target-macros/implementing-the-varargs-macros.rst
+++ b/gcc/doc/gccint/target-macros/implementing-the-varargs-macros.rst
@@ -91,6 +91,11 @@ These machine description macros help implement varargs:
   :end-before: [TARGET_STRICT_ARGUMENT_NAMING]
 
 
+.. include:: tm.rst.in
+  :start-after: [TARGET_START_CALL_ARGS]
+  :end-before: [TARGET_START_CALL_ARGS]
+
+
 .. include:: tm.rst.in
   :start-after: [TARGET_CALL_ARGS]
   :end-before: [TARGET_CALL_ARGS]
diff --git a/gcc/doc/gccint/target-macros/tm.rst.in b/gcc/doc/gccint/target-macros/tm.rst.in
index a19fa38b811..04be4bda3f6 100644
--- a/gcc/doc/gccint/target-macros/tm.rst.in
+++ b/gcc/doc/gccint/target-macros/tm.rst.in
@@ -4346,31 +4346,64 @@
 
 [TARGET_SETUP_INCOMING_VARARGS]
 
+[TARGET_START_CALL_ARGS]
+.. function:: void TARGET_START_CALL_ARGS (cumulative_args_t complete_args)
+
+  This target hook is invoked while generating RTL for a function call,
+  after the argument values have been computed, and after stack arguments
+  have been initialized, but before register arguments have been moved into
+  their ABI-defined hard register locations.  It precedes calls to the related
+  hooks ``TARGET_CALL_ARGS`` and ``TARGET_END_CALL_ARGS``.  The significance
+  of this position in the call expansion is that:
+  
+  * No argument registers are live.
+  
+  * Although a call sequence can in general involve subcalls (such as using
+    ``memcpy`` to copy large arguments), no such subcall will occur between
+    the call to this hook and the generation of the main call instruction.
+  
+  The single argument :samp:`complete_args` is the state of the target
+  function's cumulative argument information after the final call to
+  ``TARGET_FUNCTION_ARG``.
+  
+  The hook can be used for things like switching processor mode, in cases
+  where different calls need different processor modes.  Most ports do not
+  need to implement anything for this hook.
+
+[TARGET_START_CALL_ARGS]
+
 [TARGET_CALL_ARGS]
-.. function:: void TARGET_CALL_ARGS (rtx, tree)
+.. function:: void TARGET_CALL_ARGS (cumulative_args_t complete_args, rtx loc, tree type)
 
   While generating RTL for a function call, this target hook is invoked once
   for each argument passed to the function, either a register returned by
   ``TARGET_FUNCTION_ARG`` or a memory location.  It is called just
-  before the point where argument registers are stored.  The type of the
-  function to be called is also passed as the second argument; it is
-  ``NULL_TREE`` for libcalls.  The ``TARGET_END_CALL_ARGS`` hook is
-  invoked just after the code to copy the return reg has been emitted.
-  This functionality can be used to perform special setup of call argument
-  registers if a target needs it.
+  before the point where argument registers are stored.
+  
+  :samp:`complete_args` is the state of the target function's cumulative
+  argument information after the final call to ``TARGET_FUNCTION_ARG``.
+  :samp:`loc` is the location of the argument.  :samp:`type` is the type of
+  the function being called, or ``NULL_TREE`` for libcalls.
+  
   For functions without arguments, the hook is called once with ``pc_rtx``
   passed instead of an argument register.
-  Most ports do not need to implement anything for this hook.
+  
+  This functionality can be used to perform special setup of call argument
+  registers, if a target needs it.  Most ports do not need to implement
+  anything for this hook.
 
 [TARGET_CALL_ARGS]
 
 [TARGET_END_CALL_ARGS]
-.. function:: void TARGET_END_CALL_ARGS (void)
+.. function:: void TARGET_END_CALL_ARGS (cumulative_args_t complete_args)
 
   This target hook is invoked while generating RTL for a function call,
   just after the point where the return reg is copied into a pseudo.  It
   signals that all the call argument and return registers for the just
-  emitted call are now no longer in use.
+  emitted call are now no longer in use.  :samp:`complete_args` is the
+  state of the target function's cumulative argument information after
+  the final call to ``TARGET_FUNCTION_ARG``.
+  
   Most ports do not need to implement anything for this hook.
 
 [TARGET_END_CALL_ARGS]
diff --git a/gcc/hooks.cc b/gcc/hooks.cc
index b29233f4f85..0f4e7ce1047 100644
--- a/gcc/hooks.cc
+++ b/gcc/hooks.cc
@@ -280,11 +280,6 @@ hook_void_FILEptr_tree (FILE *, tree)
 {
 }
 
-void
-hook_void_rtx_tree (rtx, tree)
-{
-}
-
 void
 hook_void_constcharptr (const char *)
 {
diff --git a/gcc/hooks.h b/gcc/hooks.h
index 1056e1e9e4d..e2a742f4325 100644
--- a/gcc/hooks.h
+++ b/gcc/hooks.h
@@ -83,7 +83,6 @@ extern void hook_void_FILEptr_constcharptr (FILE *, const char *);
 extern void hook_void_FILEptr_constcharptr_const_tree (FILE *, const char *,
 						       const_tree);
 extern bool hook_bool_FILEptr_rtx_false (FILE *, rtx);
-extern void hook_void_rtx_tree (rtx, tree);
 extern void hook_void_FILEptr_tree (FILE *, tree);
 extern void hook_void_tree (tree);
 extern void hook_void_tree_treeptr (tree, tree *);
diff --git a/gcc/target.def b/gcc/target.def
index 15fd939200b..e6a388f9675 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4732,32 +4732,64 @@ not generate any instructions in this case.",
 	int *pretend_args_size, int second_time),
  default_setup_incoming_varargs)
 
+DEFHOOK
+(start_call_args,
+ "This target hook is invoked while generating RTL for a function call,\n\
+after the argument values have been computed, and after stack arguments\n\
+have been initialized, but before register arguments have been moved into\n\
+their ABI-defined hard register locations.  It precedes calls to the related\n\
+hooks ``TARGET_CALL_ARGS`` and ``TARGET_END_CALL_ARGS``.  The significance\n\
+of this position in the call expansion is that:\n\
+\n\
+* No argument registers are live.\n\
+\n\
+* Although a call sequence can in general involve subcalls (such as using\n\
+  ``memcpy`` to copy large arguments), no such subcall will occur between\n\
+  the call to this hook and the generation of the main call instruction.\n\
+\n\
+The single argument :samp:`complete_args` is the state of the target\n\
+function's cumulative argument information after the final call to\n\
+``TARGET_FUNCTION_ARG``.\n\
+\n\
+The hook can be used for things like switching processor mode, in cases\n\
+where different calls need different processor modes.  Most ports do not\n\
+need to implement anything for this hook.",
+ void, (cumulative_args_t complete_args),
+ hook_void_CUMULATIVE_ARGS)
+
 DEFHOOK
 (call_args,
  "While generating RTL for a function call, this target hook is invoked once\n\
 for each argument passed to the function, either a register returned by\n\
 ``TARGET_FUNCTION_ARG`` or a memory location.  It is called just\n\
-before the point where argument registers are stored.  The type of the\n\
-function to be called is also passed as the second argument; it is\n\
-``NULL_TREE`` for libcalls.  The ``TARGET_END_CALL_ARGS`` hook is\n\
-invoked just after the code to copy the return reg has been emitted.\n\
-This functionality can be used to perform special setup of call argument\n\
-registers if a target needs it.\n\
+before the point where argument registers are stored.\n\
+\n\
+:samp:`complete_args` is the state of the target function's cumulative\n\
+argument information after the final call to ``TARGET_FUNCTION_ARG``.\n\
+:samp:`loc` is the location of the argument.  :samp:`type` is the type of\n\
+the function being called, or ``NULL_TREE`` for libcalls.\n\
+\n\
 For functions without arguments, the hook is called once with ``pc_rtx``\n\
 passed instead of an argument register.\n\
-Most ports do not need to implement anything for this hook.",
- void, (rtx, tree),
- hook_void_rtx_tree)
+\n\
+This functionality can be used to perform special setup of call argument\n\
+registers, if a target needs it.  Most ports do not need to implement\n\
+anything for this hook.",
+ void, (cumulative_args_t complete_args, rtx loc, tree type),
+ hook_void_CUMULATIVE_ARGS_rtx_tree)
 
 DEFHOOK
 (end_call_args,
  "This target hook is invoked while generating RTL for a function call,\n\
 just after the point where the return reg is copied into a pseudo.  It\n\
 signals that all the call argument and return registers for the just\n\
-emitted call are now no longer in use.\n\
+emitted call are now no longer in use.  :samp:`complete_args` is the\n\
+state of the target function's cumulative argument information after\n\
+the final call to ``TARGET_FUNCTION_ARG``.\n\
+\n\
 Most ports do not need to implement anything for this hook.",
- void, (void),
- hook_void_void)
+ void, (cumulative_args_t complete_args),
+ hook_void_CUMULATIVE_ARGS)
 
 DEFHOOK
 (push_argument,
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index 12a58456b39..f8b9a01b817 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -773,12 +773,22 @@ hook_int_CUMULATIVE_ARGS_arg_info_0 (cumulative_args_t,
   return 0;
 }
 
+void
+hook_void_CUMULATIVE_ARGS (cumulative_args_t)
+{
+}
+
 void
 hook_void_CUMULATIVE_ARGS_tree (cumulative_args_t ca ATTRIBUTE_UNUSED,
 				tree ATTRIBUTE_UNUSED)
 {
 }
 
+void
+hook_void_CUMULATIVE_ARGS_rtx_tree (cumulative_args_t, rtx, tree)
+{
+}
+
 /* Default implementation of TARGET_PUSH_ARGUMENT.  */
 
 bool
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index a6a423c1abb..1c43cefdcae 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -138,8 +138,9 @@ extern bool hook_bool_CUMULATIVE_ARGS_arg_info_true
   (cumulative_args_t, const function_arg_info &);
 extern int hook_int_CUMULATIVE_ARGS_arg_info_0
   (cumulative_args_t, const function_arg_info &);
-extern void hook_void_CUMULATIVE_ARGS_tree
-  (cumulative_args_t, tree);
+extern void hook_void_CUMULATIVE_ARGS (cumulative_args_t);
+extern void hook_void_CUMULATIVE_ARGS_tree (cumulative_args_t, tree);
+extern void hook_void_CUMULATIVE_ARGS_rtx_tree (cumulative_args_t, rtx, tree);
 extern const char *hook_invalid_arg_for_unprototyped_fn
   (const_tree, const_tree, const_tree);
 extern void default_function_arg_advance
