diff mbox

register CALL_INSN_FUNCTION_USAGE in find_all_hard_reg_sets

Message ID 534E5166.6020709@mentor.com
State New
Headers show

Commit Message

Tom de Vries April 16, 2014, 9:46 a.m. UTC
On 16-01-14 09:13, Richard Sandiford wrote:
> Tom de Vries <Tom_deVries@mentor.com> writes:
>> * The set of registers which are clobbered during a call by things like the plt
>>     - these are not picked up by the use-caller-save optimization. We need the
>>     hook to inform the compiler about these registers
>
> Right, but...
>
>> * And finally, registers clobbered in the caller itself during a sequence of
>>     instructions implementing a function call. On mips, that's R6, which may be
>>     clobbered by the call. Normally that doesn't need mentioning in the RTL since
>>     it's a call_used_reg, but since use-caller-save might discover a set of
>>     registers for the called function that does not include R6, it becomes
>>     important to record this clobber explicitly. It could be represented in the
>>     RTL by a clobber on the insn, or a clobber in C_I_F_U. Or it could just be
>>     part of the registers returned by the hook - but that was previously deemed
>>     not acceptable (and it doesn't match the description of the hook).
>
> ...why do we need two different mechanisms to deal with these two?
> IMO the set recorded for the callee should contain what the callee
> instructions clobber and nothing else.  CALL_INSN_FUNCTION_USAGE
> should contain everything clobbered by a call outside the callee,
> whether that's in the calling function itself, in a PLT, in a MIPS16
> stub, or whatever.
>

Richard,

Is this what you mean?

This patch introduces a hook that specifies which registers are implicitly 
clobbered by a call, not including the registers that are clobbered in the 
called function, and then uses that hook to add those registers to 
CALL_INSN_FUNCTION_USAGE.

Thanks,
- Tom

2013-04-29  Radovan Obradovic  <robradovic@mips.com>
             Tom de Vries  <tom@codesourcery.com>

	* target.def (call_clobbered_regs): New DEFHOOK.
	* doc/tm.texi.in (@node Stack and Calling): Add Miscellaneous Register
	Hooks to @menu.
	(@node Miscellaneous Register Hooks): New node.
	(@hook TARGET_CALL_CLOBBERED_REGS): New hook.
	* doc/tm.texi: Regenerate.
	* calls.c (expand_call, emit_library_call_value_1): Add regs in
	targetm.call_clobbered_regs to CALL_INSN_FUNCTION_USAGE.

Comments

Richard Sandiford April 16, 2014, 10:28 a.m. UTC | #1
Tom de Vries <Tom_deVries@mentor.com> writes:
> On 16-01-14 09:13, Richard Sandiford wrote:
>> Tom de Vries <Tom_deVries@mentor.com> writes:
>>> * The set of registers which are clobbered during a call by things
>>> like the plt
>>>     - these are not picked up by the use-caller-save optimization. We
>>> need the
>>>     hook to inform the compiler about these registers
>>
>> Right, but...
>>
>>> * And finally, registers clobbered in the caller itself during a sequence of
>>>     instructions implementing a function call. On mips, that's R6,
>>> which may be
>>>     clobbered by the call. Normally that doesn't need mentioning in
>>> the RTL since
>>>     it's a call_used_reg, but since use-caller-save might discover a set of
>>>     registers for the called function that does not include R6, it becomes
>>>     important to record this clobber explicitly. It could be
>>> represented in the
>>>     RTL by a clobber on the insn, or a clobber in C_I_F_U. Or it
>>> could just be
>>>     part of the registers returned by the hook - but that was
>>> previously deemed
>>>     not acceptable (and it doesn't match the description of the hook).
>>
>> ...why do we need two different mechanisms to deal with these two?
>> IMO the set recorded for the callee should contain what the callee
>> instructions clobber and nothing else.  CALL_INSN_FUNCTION_USAGE
>> should contain everything clobbered by a call outside the callee,
>> whether that's in the calling function itself, in a PLT, in a MIPS16
>> stub, or whatever.
>>
>
> Richard,
>
> Is this what you mean?
>
> This patch introduces a hook that specifies which registers are implicitly 
> clobbered by a call, not including the registers that are clobbered in the 
> called function, and then uses that hook to add those registers to 
> CALL_INSN_FUNCTION_USAGE.

I don't think a new hook is needed.  The call patterns should just add
the registers to CALL_INSN_FUNCTION_USAGE when generating the call insn.
MIPS already does this some cases where normally-call-saved registers
are actually clobbered:

      /* If we are handling a floating-point return value, we need to
         save $18 in the function prologue.  Putting a note on the
         call will mean that df_regs_ever_live_p ($18) will be true if the
         call is not eliminated, and we can check that in the prologue
         code.  */
      if (fp_ret_p)
	CALL_INSN_FUNCTION_USAGE (insn) =
	  gen_rtx_EXPR_LIST (VOIDmode,
			     gen_rtx_CLOBBER (VOIDmode,
					      gen_rtx_REG (word_mode, 18)),
			     CALL_INSN_FUNCTION_USAGE (insn));

Although we really should have a utility function like use_reg, but for
clobbers, so that the above would become:

  clobber_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (word_mode, 18));

Thanks,
Richard
Tom de Vries April 16, 2014, 11:09 a.m. UTC | #2
On 16/04/14 12:28, Richard Sandiford wrote:
>> > This patch introduces a hook that specifies which registers are implicitly 
>> > clobbered by a call, not including the registers that are clobbered in the 
>> > called function, and then uses that hook to add those registers to 
>> > CALL_INSN_FUNCTION_USAGE.

> I don't think a new hook is needed.

Richard,

the hook enables us to determine whether a target supplies the information
provided by the hook. If the target does not provide this information, the
fuse-caller-save optimization is possibly not safe.

How do you propose to handle this without this hook?

Apart from that, I don't see the reason why we should add similar code to
several targets, if we can add a hook that specifies information about the
target, and add generic code that handles the information.

Thanks,
- Tom
Jakub Jelinek April 16, 2014, 11:12 a.m. UTC | #3
On Wed, Apr 16, 2014 at 11:46:14AM +0200, Tom de Vries wrote:
> >...why do we need two different mechanisms to deal with these two?
> >IMO the set recorded for the callee should contain what the callee
> >instructions clobber and nothing else.  CALL_INSN_FUNCTION_USAGE
> >should contain everything clobbered by a call outside the callee,
> >whether that's in the calling function itself, in a PLT, in a MIPS16
> >stub, or whatever.

Always putting all call clobbered registers to C_I_F_U explicitly
can be a serious memory hog on some architectures, e.g. doesn't
ia64 have ~ 160 call clobbered hard registers, times number of calls in a
function (sometimes tens of thousands)?

	Jakub
Richard Sandiford April 16, 2014, 11:41 a.m. UTC | #4
Jakub Jelinek <jakub@redhat.com> writes:
> On Wed, Apr 16, 2014 at 11:46:14AM +0200, Tom de Vries wrote:
>> >...why do we need two different mechanisms to deal with these two?
>> >IMO the set recorded for the callee should contain what the callee
>> >instructions clobber and nothing else.  CALL_INSN_FUNCTION_USAGE
>> >should contain everything clobbered by a call outside the callee,
>> >whether that's in the calling function itself, in a PLT, in a MIPS16
>> >stub, or whatever.
>
> Always putting all call clobbered registers to C_I_F_U explicitly
> can be a serious memory hog on some architectures, e.g. doesn't
> ia64 have ~ 160 call clobbered hard registers, times number of calls in a
> function (sometimes tens of thousands)?

That isn't what we're doing though.  The problem Tom's trying to solve
is that call sequences themselves can sometimes use call-clobbered
registers internally, on the assumption that they cannot possibly hold
a live value.  These uses aren't always exposed in the rtl, at least not
until after reload (which is later than Tom needs the information).
So it isn't always correct to assume that a call only clobbers the
registers that are clobbered by the call target.

E.g. $gp is call-clobbered on MIPS o32, so we need to restore it after
a call if the GOT base is still needed.  This is doing using post-reload
split of the call insn.  And on MIPS16 we need a temporary register to
do that, since it isn't possible to load directly into $gp.  The temporary
register we use is the call-clobbered $6.

Tom's original approach was to have a hook that told the target-independent
code that $6 might be clobbered in this way.  My argument was that we
should reuse CALL_INSN_FUNCTION_USAGE instead, since it already holds
other such special uses and clobbers.  The difference is that the special
registers we need to know about here are call-clobbered, whereas until now
it has only been necessary to mention call-saved ones (or, in the case of
USEs, registers set up before the call and not otherwise used by the call).

Thanks,
Richard
Richard Sandiford April 16, 2014, 11:43 a.m. UTC | #5
Tom de Vries <Tom_deVries@mentor.com> writes:
> On 16/04/14 12:28, Richard Sandiford wrote:
>>> > This patch introduces a hook that specifies which registers are implicitly 
>>> > clobbered by a call, not including the registers that are clobbered in the 
>>> > called function, and then uses that hook to add those registers to 
>>> > CALL_INSN_FUNCTION_USAGE.
>
>> I don't think a new hook is needed.
>
> Richard,
>
> the hook enables us to determine whether a target supplies the information
> provided by the hook. If the target does not provide this information, the
> fuse-caller-save optimization is possibly not safe.
>
> How do you propose to handle this without this hook?

Maybe we should just have a bool field in the target structure to say
whether -fuse-caller-save is supported, a bit like delay_sched2.

Thanks,
Richard
diff mbox

Patch

diff --git a/gcc/calls.c b/gcc/calls.c
index e798c7a..edee262 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -3191,6 +3191,27 @@  expand_call (tree exp, rtx target, int ignore)
 	  add_reg_note (last, REG_CALL_DECL, datum);
 	}
 
+      if (targetm.call_clobbered_regs != NULL)
+	{
+	  struct hard_reg_set_container call_clobbered_regs;
+	  rtx last = last_call_insn ();
+
+	  CLEAR_HARD_REG_SET (call_clobbered_regs.set);
+	  if (targetm.call_clobbered_regs (fndecl, &call_clobbered_regs))
+	    {
+	      hard_reg_set_iterator hrsi;
+	      unsigned int i;
+	      EXECUTE_IF_SET_IN_HARD_REG_SET (call_clobbered_regs.set, 0, i, hrsi)
+		{
+		  rtx reg = gen_rtx_REG (word_mode, i);
+		  CALL_INSN_FUNCTION_USAGE (last)
+		    = gen_rtx_EXPR_LIST (VOIDmode,
+					 gen_rtx_CLOBBER (VOIDmode, reg),
+					 CALL_INSN_FUNCTION_USAGE (last));
+		}
+	    }
+	}
+
       /* If the call setup or the call itself overlaps with anything
 	 of the argument setup we probably clobbered our call address.
 	 In that case we can't do sibcalls.  */
@@ -4226,6 +4247,27 @@  emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
       add_reg_note (last, REG_CALL_DECL, datum);
     }
 
+  if (targetm.call_clobbered_regs != NULL)
+    {
+      struct hard_reg_set_container call_clobbered_regs;
+      rtx last = last_call_insn ();
+
+      CLEAR_HARD_REG_SET (call_clobbered_regs.set);
+      if (targetm.call_clobbered_regs (fndecl, &call_clobbered_regs))
+	{
+	  hard_reg_set_iterator hrsi;
+	  unsigned int i;
+	  EXECUTE_IF_SET_IN_HARD_REG_SET (call_clobbered_regs.set, 0, i, hrsi)
+	    {
+	      rtx reg = gen_rtx_REG (word_mode, i);
+	      CALL_INSN_FUNCTION_USAGE (last)
+		= gen_rtx_EXPR_LIST (VOIDmode,
+				     gen_rtx_CLOBBER (VOIDmode, reg),
+				     CALL_INSN_FUNCTION_USAGE (last));
+	    }
+	}
+    }
+
   /* Right-shift returned value if necessary.  */
   if (!pcc_struct_value
       && TYPE_MODE (tfom) != BLKmode
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index b8ca17e..cd52f73 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3091,6 +3091,7 @@  This describes the stack layout and calling conventions.
 * Profiling::
 * Tail Calls::
 * Stack Smashing Protection::
+* Miscellaneous Register Hooks::
 @end menu
 
 @node Frame Layout
@@ -5016,6 +5017,14 @@  normally defined in @file{libgcc2.c}.
 Whether this target supports splitting the stack when the options described in @var{opts} have been passed.  This is called after options have been parsed, so the target may reject splitting the stack in some configurations.  The default version of this hook returns false.  If @var{report} is true, this function may issue a warning or error; if @var{report} is false, it must simply return a value
 @end deftypefn
 
+@node Miscellaneous Register Hooks
+@subsection Miscellaneous register hooks
+@cindex miscellaneous register hooks
+
+@deftypefn {Target Hook} bool TARGET_CALL_CLOBBERED_REGS (tree @var{fndecl}, struct hard_reg_set_container *@var{regs})
+Add any hard registers to @var{regs} that are set or clobbered by a call @var{fndecl} which are not present in the rtl representation.  This includes f.i. registers reserved for PLT, or tmp registers set or clobbered by the call, but not registers set or clobbered by the called function.  This hook returns true if it added any registers to @var{regs}.  Not defining this hook will result in conservative assumptions.
+@end deftypefn
+
 @node Varargs
 @section Implementing the Varargs Macros
 @cindex varargs implementation
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index d793d26..7022d7c 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2720,6 +2720,7 @@  This describes the stack layout and calling conventions.
 * Profiling::
 * Tail Calls::
 * Stack Smashing Protection::
+* Miscellaneous Register Hooks::
 @end menu
 
 @node Frame Layout
@@ -3985,6 +3986,12 @@  the function prologue.  Normally, the profiling code comes after.
 
 @hook TARGET_SUPPORTS_SPLIT_STACK
 
+@node Miscellaneous Register Hooks
+@subsection Miscellaneous register hooks
+@cindex miscellaneous register hooks
+
+@hook TARGET_CALL_CLOBBERED_REGS
+
 @node Varargs
 @section Implementing the Varargs Macros
 @cindex varargs implementation
diff --git a/gcc/target.def b/gcc/target.def
index 3a64cd1..b7bb40c 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -5130,6 +5130,17 @@  FRAME_POINTER_REGNUM, ARG_POINTER_REGNUM, and the PIC_OFFSET_TABLE_REGNUM.",
  void, (bitmap regs),
  hook_void_bitmap)
 
+DEFHOOK
+(call_clobbered_regs,
+ "Add any hard registers to @var{regs} that are set or clobbered by a call\
+ @var{fndecl} which are not present in the rtl representation.  This includes\
+ f.i. registers reserved for PLT, or tmp registers set or clobbered by the\
+ call, but not registers set or clobbered by the called function.  This hook\
+ returns true if it added any registers to @var{regs}.  Not defining this hook\
+ will result in conservative assumptions.",
+ bool, (tree fndecl, struct hard_reg_set_container *regs),
+ NULL)
+
 /* Fill in additional registers set up by prologue into a regset.  */
 DEFHOOK
 (set_up_by_prologue,
-- 
1.8.3.2