Add a hook to inform a port about call arguments.
authorBernd Schmidt <bernds@codesourcery.com>
Thu, 6 Nov 2014 17:20:13 +0000 (17:20 +0000)
committerBernd Schmidt <bernds@gcc.gnu.org>
Thu, 6 Nov 2014 17:20:13 +0000 (17:20 +0000)
* target.def (call_args, end_call_args): New hooks.
* hooks.c (hook_void_rtx_tree): New empty function.
* hooks.h (hook_void_rtx_tree): Declare.
* doc/tm.texi.in (TARGET_CALL_ARGS, TARGET_END_CALL_ARGS): Add.
* doc/tm.texi: Regenerate.
* calls.c (expand_call): Slightly rearrange the code.  Use the two new
hooks.
(expand_library_call_value_1): Use the two new hooks.

From-SVN: r217199

gcc/ChangeLog
gcc/calls.c
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/hooks.c
gcc/hooks.h
gcc/target.def

index 085f0b1ec2a67069d95ba9f62003e4a20130ee78..75ab1fa7bbfafe105365bb0dc3447f82453a38fe 100644 (file)
@@ -1,5 +1,14 @@
 2014-11-06  Bernd Schmidt  <bernds@codesourcery.com>
 
+       * target.def (call_args, end_call_args): New hooks.
+       * hooks.c (hook_void_rtx_tree): New empty function.
+       * hooks.h (hook_void_rtx_tree): Declare.
+       * doc/tm.texi.in (TARGET_CALL_ARGS, TARGET_END_CALL_ARGS): Add.
+       * doc/tm.texi: Regenerate.
+       * calls.c (expand_call): Slightly rearrange the code.  Use the two new
+       hooks.
+       (expand_library_call_value_1): Use the two new hooks.
+
        * expr.c (use_reg_mode): Just return for pseudo registers.
 
        * combine.c (try_combine): Don't allow a call as one of the source
index 43ac5d2f6b34ff8fc8a1a830210e821ea99a73c9..06b8485ff7fa82708a8f290b6c90b76cf0321731 100644 (file)
@@ -3103,45 +3103,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;
-      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;
-           }
-       }
-
       /* 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);
@@ -3223,6 +3184,55 @@ 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++)
        {
@@ -3582,6 +3592,8 @@ 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 ();
+
       insns = get_insns ();
       end_sequence ();
 
@@ -4111,6 +4123,18 @@ 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.  */
 
   /* ARGNUM indexes the ARGVEC array in the order in which the arguments
@@ -4351,6 +4375,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
index 7af23e5247aa9d597ab4e914fe017dfa8c31b5c1..a55206d6c051d6781615ed8e980e599426423d93 100644 (file)
@@ -4976,6 +4976,29 @@ except the last are treated as named.
 You need not define this hook if it always returns @code{false}.
 @end deftypefn
 
+@deftypefn {Target Hook} void TARGET_CALL_ARGS (rtx, @var{tree})
+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
+@code{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
+@code{NULL_TREE} for libcalls.  The @code{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.
+For functions without arguments, the hook is called once with @code{pc_rtx}
+passed instead of an argument register.
+Most ports do not need to implement anything for this hook.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_END_CALL_ARGS (void)
+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.
+Most ports do not need to implement anything for this hook.
+@end deftypefn
+
 @deftypefn {Target Hook} bool TARGET_PRETEND_OUTGOING_VARARGS_NAMED (cumulative_args_t @var{ca})
 If you need to conditionally change ABIs so that one works with
 @code{TARGET_SETUP_INCOMING_VARARGS}, but the other works like neither
index f739fdfee91da5d992a5a040c46c677c223916d2..e0c52c8a37a084c05afae532e7f54d2ce0839bd8 100644 (file)
@@ -3860,6 +3860,10 @@ These machine description macros help implement varargs:
 
 @hook TARGET_STRICT_ARGUMENT_NAMING
 
+@hook TARGET_CALL_ARGS
+
+@hook TARGET_END_CALL_ARGS
+
 @hook TARGET_PRETEND_OUTGOING_VARARGS_NAMED
 
 @hook TARGET_LOAD_BOUNDS_FOR_ARG
index b5b158752c27b1a840ff8c00512ee63acbac98ef..91e17cd70c2be987f238070638cd67bed17388ae 100644 (file)
@@ -244,6 +244,11 @@ hook_void_tree (tree a ATTRIBUTE_UNUSED)
 {
 }
 
+void
+hook_void_rtx_tree (rtx, tree)
+{
+}
+
 void
 hook_void_constcharptr (const char *a ATTRIBUTE_UNUSED)
 {
index 90b31fb5d18b3a64bb6a18da4517f0b112197f52..4006cad3412cb9a0aeedb279210c6bd4788649dd 100644 (file)
@@ -71,6 +71,7 @@ extern void hook_void_constcharptr (const char *);
 extern void hook_void_rtx_insn_int (rtx_insn *, int);
 extern void hook_void_FILEptr_constcharptr (FILE *, const char *);
 extern bool hook_bool_FILEptr_rtx_false (FILE *, rtx);
+extern void hook_void_rtx_tree (rtx, tree);
 extern void hook_void_tree (tree);
 extern void hook_void_tree_treeptr (tree, tree *);
 extern void hook_void_int_int (int, int);
index 4c02c1113d1afb6b265f67a43cbcf4b6ed1340bc..d6198ad3569ca94605b611f2fec170d74509677d 100644 (file)
@@ -4001,6 +4001,33 @@ into the stack.  Arguments meaning is similar to\n\
        int *pretend_args_size, int second_time),
  default_setup_incoming_vararg_bounds)
 
+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\
+@code{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\
+@code{NULL_TREE} for libcalls.  The @code{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\
+For functions without arguments, the hook is called once with @code{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)
+
+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\
+Most ports do not need to implement anything for this hook.",
+ void, (void),
+ hook_void_void)
+
 DEFHOOK
 (strict_argument_naming,
  "Define this hook to return @code{true} if the location where a function\n\