diff mbox

-fuse-caller-save - Collect register usage information

Message ID 535798F0.7070809@mentor.com
State New
Headers show

Commit Message

Tom de Vries April 23, 2014, 10:41 a.m. UTC
On 22-04-14 17:05, Tom de Vries wrote:
> I've updated the fuse-caller-save patch series to model non-callee call clobbers
> in CALL_INSN_FUNCTION_USAGE.

Vladimir,

This is the updated version of the previously approved patch 
http://gcc.gnu.org/ml/gcc-patches/2013-03/msg01320.html , updated for the new 
hook call_fusage_contains_non_callee_clobbers.

The only difference is in the functions get_call_reg_set_usage and 
collect_fn_hard_reg_usage which use the hook.

OK for trunk?

Thanks,
- Tom

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

	* cgraph.h (struct cgraph_node): Add function_used_regs,
	function_used_regs_initialized and function_used_regs_valid fields.
	* final.c: Move include of hard-reg-set.h to before rtl.h to declare
	find_all_hard_reg_sets.
	(collect_fn_hard_reg_usage, get_call_fndecl, get_call_cgraph_node)
	(get_call_reg_set_usage): New function.
	(rest_of_handle_final): Use collect_fn_hard_reg_usage.

Comments

Vladimir Makarov April 23, 2014, 3:10 p.m. UTC | #1
On 2014-04-23, 6:41 AM, Tom de Vries wrote:
> On 22-04-14 17:05, Tom de Vries wrote:
>> I've updated the fuse-caller-save patch series to model non-callee
>> call clobbers
>> in CALL_INSN_FUNCTION_USAGE.
>
> Vladimir,
>
> This is the updated version of the previously approved patch
> http://gcc.gnu.org/ml/gcc-patches/2013-03/msg01320.html , updated for
> the new hook call_fusage_contains_non_callee_clobbers.
>
> The only difference is in the functions get_call_reg_set_usage and
> collect_fn_hard_reg_usage which use the hook.
>
> OK for trunk?
>
> 2013-04-29  Radovan Obradovic  <robradovic@mips.com>
>              Tom de Vries  <tom@codesourcery.com>
>
>      * cgraph.h (struct cgraph_node): Add function_used_regs,
>      function_used_regs_initialized and function_used_regs_valid fields.
>      * final.c: Move include of hard-reg-set.h to before rtl.h to declare
>      find_all_hard_reg_sets.
>      (collect_fn_hard_reg_usage, get_call_fndecl, get_call_cgraph_node)
>      (get_call_reg_set_usage): New function.
>      (rest_of_handle_final): Use collect_fn_hard_reg_usage.
>

It looks ok for me, Tom.  But to be straight I am not a maintainer for 
this part of the compiler.  So it is just my recommendation.  I guess to 
get an approval for these changes, you should ask Jan Hubicka (cgraph.h) 
or a global or RTL reviewer for final.c.
Richard Sandiford April 23, 2014, 3:16 p.m. UTC | #2
Tom de Vries <Tom_deVries@mentor.com> writes:
> +/* Collect hard register usage for the current function.  */
> +
> +static void
> +collect_fn_hard_reg_usage (void)
> +{
> +  rtx insn;
> +  int i;
> +  struct cgraph_node *node;
> +
> +  if (!flag_use_caller_save)
> +    return;
> +
> +  node = cgraph_get_node (current_function_decl);
> +  gcc_assert (node != NULL);
> +
> +  gcc_assert (!node->function_used_regs_initialized);
> +  node->function_used_regs_initialized = 1;
> +
> +  for (insn = get_insns (); insn != NULL_RTX; insn = next_insn (insn))
> +    {
> +      HARD_REG_SET insn_used_regs;
> +
> +      if (!NONDEBUG_INSN_P (insn))
> +	continue;
> +
> +      find_all_hard_reg_sets (insn, &insn_used_regs, false);
> +
> +      if (CALL_P (insn)
> +	  && (!targetm.call_fusage_contains_non_callee_clobbers ()
> +	      || !get_call_reg_set_usage (insn, &insn_used_regs, call_used_reg_set)))

If the uses of flag_use_caller_save also check
call_fusage_contains_non_callee_clobbers, would it be better to test
them both together here too, rather than waiting to see a call?

> +  /* Be conservative - mark fixed and global registers as used.  */
> +  IOR_HARD_REG_SET (node->function_used_regs, fixed_reg_set);
> +  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
> +    if (global_regs[i])
> +      SET_HARD_REG_BIT (node->function_used_regs, i);

The loop isn't needed; all globals are fixed.

Thanks again for working on this.

Richard
Mike Stump Oct. 10, 2014, 9:38 p.m. UTC | #3
On Apr 23, 2014, at 3:41 AM, Tom de Vries <Tom_deVries@mentor.com> wrot
> On 22-04-14 17:05, Tom de Vries wrote:
>> I've updated the fuse-caller-save patch series to model non-callee call clobbers
>> in CALL_INSN_FUNCTION_USAGE.

> @item -fuse-caller-save
> Use caller save registers for allocation if those registers are not used by
> any called function.  In that case it is not necessary to save and restore
> them around calls.  This is only possible if called functions are part of
> same compilation unit as current function and they are compiled before it.

So, I hate the name of the option, and the documentation seems wrong to me.  It doesn’t use the caller saved registers for allocation, it uses the call clobbered registers for allocation.  Or, one could say it uses the callee saved registers for allocation.
Eric Botcazou Oct. 11, 2014, 10:46 a.m. UTC | #4
> So, I hate the name of the option, and the documentation seems wrong to me. 
> It doesn’t use the caller saved registers for allocation, it uses the call
> clobbered registers for allocation.  Or, one could say it uses the callee
> saved registers for allocation.

Seconded, the description is a bit confusing and "caller saved"/"callee saved" 
should be avoided IMO, "call clobbered"/"call saved" is much clearer.
Tom de Vries Oct. 16, 2014, 9:28 p.m. UTC | #5
On 11-10-14 12:46, Eric Botcazou wrote:
>> So, I hate the name of the option, and the documentation seems wrong to me.
>> It doesn’t use the caller saved registers for allocation, it uses the call
>> clobbered registers for allocation.  Or, one could say it uses the callee
>> saved registers for allocation.
>

Eric,
Mike,

thanks for the comments.

I know the following definition of caller-vs-callee saved registers:
- at function entry, a caller-save register can be used immediately, without
   needing to save it first. However, in order to store a value in it that is
   live across calls, it needs to be saved and restored around each call (hence
   the term caller-save).
- at function entry, a callee-save register first needs to be saved before it
   can be used (hence the name callee-save). However, that means that it can be
   used to store a value that is live across calls, without further need for
   saving/restoring.

So, AFAIU, call clobbered corresponds with caller-save, not with callee saved. 
So I'd say the documentation is in fact correct.

Having said that, in my mind, what is confusing about the name 
-fuse-caller-save, is that in fact the caller-save registers are already used in 
register allocation. It's just that they're used across calls without the need 
to save them, but -fuse-caller-save-across-calls-without-saving-if-possible is 
not such a good option name.

Another thing that - in my mind - is confusing is that there's an option 
fcaller-saves which controls behaviour for caller-save registers:
- for -fno-caller-saves, caller-save registers are not used across calls
- for -fcaller-saves, caller-save registers are used across calls
The name is similar to -fuse-caller-save, and it won't be clear from just the 
names what the difference is.

> Seconded, the description is a bit confusing and "caller saved"/"callee saved"
> should be avoided IMO, "call clobbered"/"call saved" is much clearer.
>

I have no objection to go with another terminology in the documentation. But 
before going into a patch, let's settle on the option name.

As for the name, I'm not sure just changing terminology will make things 
clearer, in other words, I'm not sure fuse-call-clobbered is any clearer than 
fuse-caller-save.

I've pondered the name -fipa-ira, but I rejected that earlier because that might 
suggest actual register allocation at the interprocedural scope, while this is 
only register allocation at the scope of a single procedure, taking some 
interprocedural information into account. Furthermore, it's not only ira that 
uses the interprocedural information.

So, let's a generate a list of option names.
-fuse-caller-save
-fuse-call-clobbered
-fprecise-call-clobbers
-foptimize-call-clobbers
-fprune-call-clobbers
-freduce-call-clobbers
-fcall-clobbers-ipa

Any preferences, alternatives?

Thanks,
- Tom
Eric Botcazou Oct. 16, 2014, 9:46 p.m. UTC | #6
> Having said that, in my mind, what is confusing about the name
> -fuse-caller-save, is that in fact the caller-save registers are already
> used in register allocation. It's just that they're used across calls
> without the need to save them, but
> -fuse-caller-save-across-calls-without-saving-if-possible is not such a
> good option name.

Agreed.

> Another thing that - in my mind - is confusing is that there's an option
> fcaller-saves which controls behaviour for caller-save registers:
> - for -fno-caller-saves, caller-save registers are not used across calls
> - for -fcaller-saves, caller-save registers are used across calls
> The name is similar to -fuse-caller-save, and it won't be clear from just
> the names what the difference is.

OK, so the existing -fcaller-saves is in fact -fuse-caller-saves, which means 
that we should really find a better name for yours. :-)

> I've pondered the name -fipa-ira, but I rejected that earlier because that
> might suggest actual register allocation at the interprocedural scope,
> while this is only register allocation at the scope of a single procedure,
> taking some interprocedural information into account. Furthermore, it's not
> only ira that uses the interprocedural information.
> 
> So, let's a generate a list of option names.
> -fuse-caller-save
> -fuse-call-clobbered
> -fprecise-call-clobbers
> -foptimize-call-clobbers
> -fprune-call-clobbers
> -freduce-call-clobbers
> -fcall-clobbers-ipa
> 
> Any preferences, alternatives?

Given the existing -fcaller-saves, I'd keep "caller-saves" in the name, so 
something along the lines of -foptimize-caller-saves or -fipa-caller-saves.
Mike Stump Oct. 16, 2014, 10:09 p.m. UTC | #7
On Oct 16, 2014, at 2:28 PM, Tom de Vries <Tom_deVries@mentor.com> wrote:
> So I'd say the documentation is in fact correct.

Agreed.  I was confused.  Apparently my mind likes to think in volatile and non-volatile (call-clobbered and non-call-clobbered) and I managed to map it wrong in my mind and not catch that fact I mapped them wrong.

> So, let's a generate a list of option names.

> Any preferences, alternatives?

So, since I was confused, my primary reason for not liking the option name was misguided.
Tom de Vries Oct. 17, 2014, 10:47 a.m. UTC | #8
On 16-10-14 23:46, Eric Botcazou wrote:
>> Having said that, in my mind, what is confusing about the name
>> -fuse-caller-save, is that in fact the caller-save registers are already
>> used in register allocation. It's just that they're used across calls
>> without the need to save them, but
>> -fuse-caller-save-across-calls-without-saving-if-possible is not such a
>> good option name.
>
> Agreed.
>
>> Another thing that - in my mind - is confusing is that there's an option
>> fcaller-saves which controls behaviour for caller-save registers:
>> - for -fno-caller-saves, caller-save registers are not used across calls
>> - for -fcaller-saves, caller-save registers are used across calls
>> The name is similar to -fuse-caller-save, and it won't be clear from just
>> the names what the difference is.
>
> OK, so the existing -fcaller-saves is in fact -fuse-caller-saves,

Right, in the sense that a caller-save is the save of caller-save register, as 
opposed to short for a caller-save register, which is how it's used in 
-fuse-caller-save.

> which means
> that we should really find a better name for yours. :-)
>

Agreed :)

>> I've pondered the name -fipa-ira, but I rejected that earlier because that
>> might suggest actual register allocation at the interprocedural scope,
>> while this is only register allocation at the scope of a single procedure,
>> taking some interprocedural information into account. Furthermore, it's not
>> only ira that uses the interprocedural information.
>>
>> So, let's a generate a list of option names.
>> -fuse-caller-save
>> -fuse-call-clobbered
>> -fprecise-call-clobbers
>> -foptimize-call-clobbers
>> -fprune-call-clobbers
>> -freduce-call-clobbers
>> -fcall-clobbers-ipa
>>
>> Any preferences, alternatives?
>
> Given the existing -fcaller-saves, I'd keep "caller-saves" in the name, so
> something along the lines of -foptimize-caller-saves or -fipa-caller-saves.
>

Let's look at the effect of the option (after the recent fix for PR61605) on 
gcc.target/i386/fuse-calller-save.c:
...
  foo:
  .LFB1:
  	.cfi_startproc
-	pushq	%rbx
-	.cfi_def_cfa_offset 16
-	.cfi_offset 3, -16
-	movl	%edi, %ebx
  	call	bar
-	addl	%ebx, %eax
-	popq	%rbx
-	.cfi_def_cfa_offset 8
+	addl	%edi, %eax
  	ret
  	.cfi_endproc
  .LFE1:
...
So, the effect is: instead of using a callee-save register, we use a caller-save 
register to store a value that's live over a call, without needing to add a 
caller-save, as would be normally the case.

If I see an option -foptimize-caller-saves, I'd expect the effect to be that 
without, there are some caller-saves and with, there are less. This is not the 
case in the diff above. Nevertheless, if we'd have a case where we already have 
caller-saves, that would be indeed the observed effect. I'm just trying to point 
out that the optimization does more than just removing caller-saves.

The optimization, at it's core, can be regarded as removing superfluous clobbers 
from calls, and everything else is derived from that:
- if a caller-save register is not clobbered by a call, then there's no need
   for a caller-save before that call, so it's cheaper to use across that call
   than a callee-save register.
   (which explains what we see in the diff)
- if a caller-save register is live across a call, and is not clobbered by a
   call, then there's no need for a caller-save, and it can be removed.
   (which explains what we see in case we have an example where there are
    actual caller-saves without the optimization, and less so with the
    optimization)

I'm starting to lean towards -foptimize-call-clobbers or similar.

Thanks,
- Tom
Richard Biener Oct. 17, 2014, 11 a.m. UTC | #9
On Fri, Oct 17, 2014 at 12:47 PM, Tom de Vries <Tom_deVries@mentor.com> wrote:
> On 16-10-14 23:46, Eric Botcazou wrote:
>>>
>>> Having said that, in my mind, what is confusing about the name
>>> -fuse-caller-save, is that in fact the caller-save registers are already
>>> used in register allocation. It's just that they're used across calls
>>> without the need to save them, but
>>> -fuse-caller-save-across-calls-without-saving-if-possible is not such a
>>> good option name.
>>
>>
>> Agreed.
>>
>>> Another thing that - in my mind - is confusing is that there's an option
>>> fcaller-saves which controls behaviour for caller-save registers:
>>> - for -fno-caller-saves, caller-save registers are not used across calls
>>> - for -fcaller-saves, caller-save registers are used across calls
>>> The name is similar to -fuse-caller-save, and it won't be clear from just
>>> the names what the difference is.
>>
>>
>> OK, so the existing -fcaller-saves is in fact -fuse-caller-saves,
>
>
> Right, in the sense that a caller-save is the save of caller-save register,
> as opposed to short for a caller-save register, which is how it's used in
> -fuse-caller-save.
>
>> which means
>> that we should really find a better name for yours. :-)
>>
>
> Agreed :)
>
>>> I've pondered the name -fipa-ira, but I rejected that earlier because
>>> that
>>> might suggest actual register allocation at the interprocedural scope,
>>> while this is only register allocation at the scope of a single
>>> procedure,
>>> taking some interprocedural information into account. Furthermore, it's
>>> not
>>> only ira that uses the interprocedural information.
>>>
>>> So, let's a generate a list of option names.
>>> -fuse-caller-save
>>> -fuse-call-clobbered
>>> -fprecise-call-clobbers
>>> -foptimize-call-clobbers
>>> -fprune-call-clobbers
>>> -freduce-call-clobbers
>>> -fcall-clobbers-ipa
>>>
>>> Any preferences, alternatives?
>>
>>
>> Given the existing -fcaller-saves, I'd keep "caller-saves" in the name, so
>> something along the lines of -foptimize-caller-saves or
>> -fipa-caller-saves.
>>
>
> Let's look at the effect of the option (after the recent fix for PR61605) on
> gcc.target/i386/fuse-calller-save.c:
> ...
>  foo:
>  .LFB1:
>         .cfi_startproc
> -       pushq   %rbx
> -       .cfi_def_cfa_offset 16
> -       .cfi_offset 3, -16
> -       movl    %edi, %ebx
>         call    bar
> -       addl    %ebx, %eax
> -       popq    %rbx
> -       .cfi_def_cfa_offset 8
> +       addl    %edi, %eax
>         ret
>         .cfi_endproc
>  .LFE1:
> ...
> So, the effect is: instead of using a callee-save register, we use a
> caller-save register to store a value that's live over a call, without
> needing to add a caller-save, as would be normally the case.
>
> If I see an option -foptimize-caller-saves, I'd expect the effect to be that
> without, there are some caller-saves and with, there are less. This is not
> the case in the diff above. Nevertheless, if we'd have a case where we
> already have caller-saves, that would be indeed the observed effect. I'm
> just trying to point out that the optimization does more than just removing
> caller-saves.
>
> The optimization, at it's core, can be regarded as removing superfluous
> clobbers from calls, and everything else is derived from that:
> - if a caller-save register is not clobbered by a call, then there's no need
>   for a caller-save before that call, so it's cheaper to use across that
> call
>   than a callee-save register.
>   (which explains what we see in the diff)
> - if a caller-save register is live across a call, and is not clobbered by a
>   call, then there's no need for a caller-save, and it can be removed.
>   (which explains what we see in case we have an example where there are
>    actual caller-saves without the optimization, and less so with the
>    optimization)
>
> I'm starting to lean towards -foptimize-call-clobbers or similar.

Well, it is really some form of IPA driven register allocation.  Whether
you want to call it -fipa-ra or not is another question - but if we had
such option then enabling it with that option would be fine.

Also users may have no idea what call vs callee clobbers are, but
IPA RA may be a term that is more widely known (or at least google
can come up with something for you).

So - I like -fipa-ra more.

I can't see the obvious difference between -foptimize-caller-saves
and -foptimize-call-clobbers (for the latter -fipa-call-clobbers would
be more to the point?)

Richard.

> Thanks,
> - Tom
Jeff Law Oct. 17, 2014, 3:50 p.m. UTC | #10
On 10/17/14 05:00, Richard Biener wrote:
>>
>> I'm starting to lean towards -foptimize-call-clobbers or similar.
>
> Well, it is really some form of IPA driven register allocation.  Whether
> you want to call it -fipa-ra or not is another question - but if we had
> such option then enabling it with that option would be fine.
>
> Also users may have no idea what call vs callee clobbers are, but
> IPA RA may be a term that is more widely known (or at least google
> can come up with something for you).
>
> So - I like -fipa-ra more.
Similarly.  At the heart of the matter is we're utilizing information 
about the callee's behaviour to improve the code we generate in the 
caller.  That's clearly in IPA's domain IMHO.



Jeff
Mike Stump Oct. 17, 2014, 5:15 p.m. UTC | #11
On Oct 17, 2014, at 8:50 AM, Jeff Law <law@redhat.com> wrote:
>> So - I like -fipa-ra more.
> Similarly.

Yeah, I was going to say I liked the ipa tag in there some place but didn’t cause I didn’t want to bikeshed, but, since a few others like that, dogpiling seems ok.  :-)
Eric Botcazou Oct. 17, 2014, 7:24 p.m. UTC | #12
> Let's look at the effect of the option (after the recent fix for PR61605) on
> gcc.target/i386/fuse-calller-save.c:
> ...
>   foo:
>   .LFB1:
>   	.cfi_startproc
> -	pushq	%rbx
> -	.cfi_def_cfa_offset 16
> -	.cfi_offset 3, -16
> -	movl	%edi, %ebx
>   	call	bar
> -	addl	%ebx, %eax
> -	popq	%rbx
> -	.cfi_def_cfa_offset 8
> +	addl	%edi, %eax
>   	ret
>   	.cfi_endproc
>   .LFE1:
> ...
> So, the effect is: instead of using a callee-save register, we use a
> caller-save register to store a value that's live over a call, without
> needing to add a caller-save, as would be normally the case.
> 
> If I see an option -foptimize-caller-saves, I'd expect the effect to be that
> without, there are some caller-saves and with, there are less. This is not
> the case in the diff above.

To me it is, "movl %edi, %ebx"/"addl %ebx, %eax" is a caller-save/restore.

> I'm starting to lean towards -foptimize-call-clobbers or similar.

Yes, that's also a good name and was my initial preference.  But you pointed 
out the existing -fcaller-saves:

`-fcaller-saves'
     Enable allocation of values to registers that are clobbered by
     function calls, by emitting extra instructions to save and restore
     the registers around such calls.  Such allocation is done only
     when it seems to result in better code.

so -foptimize-caller-saves can be understood as optimizing out the "extra 
instructions to save and restore  the registers around such calls" and, thus, 
as having a direct relationship with -fcaller-saves.
Tom de Vries Oct. 19, 2014, 11:52 a.m. UTC | #13
On 17-10-14 21:24, Eric Botcazou wrote:
>> Let's look at the effect of the option (after the recent fix for PR61605) on
>> gcc.target/i386/fuse-calller-save.c:
>> ...
>>    foo:
>>    .LFB1:
>>    	.cfi_startproc
>> -	pushq	%rbx
>> -	.cfi_def_cfa_offset 16
>> -	.cfi_offset 3, -16
>> -	movl	%edi, %ebx
>>    	call	bar
>> -	addl	%ebx, %eax
>> -	popq	%rbx
>> -	.cfi_def_cfa_offset 8
>> +	addl	%edi, %eax
>>    	ret
>>    	.cfi_endproc
>>    .LFE1:
>> ...
>> So, the effect is: instead of using a callee-save register, we use a
>> caller-save register to store a value that's live over a call, without
>> needing to add a caller-save, as would be normally the case.
>>
>> If I see an option -foptimize-caller-saves, I'd expect the effect to be that
>> without, there are some caller-saves and with, there are less. This is not
>> the case in the diff above.
>
> To me it is, "movl %edi, %ebx"/"addl %ebx, %eax" is a caller-save/restore.
>

I agree that it can look like that. But the insn 'movl %edi, %ebx' is generated 
by assign_parm_setup_reg at expand. AFAIU, the purpose is to decouple the value 
of the argument and its uses from the register it's passed in.

The definition of -fcaller-saves below explains why insn 'movl %edi, %ebx' is 
not a caller-save: because it's not generated before a call, but rather at the 
start of a function. This seems to be confirmed by the fact that the insn 'movl 
%edi, %ebx' is still generated with -fno-caller-saves.

>> I'm starting to lean towards -foptimize-call-clobbers or similar.
>
> Yes, that's also a good name and was my initial preference.  But you pointed
> out the existing -fcaller-saves:
>
> `-fcaller-saves'
>       Enable allocation of values to registers that are clobbered by
>       function calls, by emitting extra instructions to save and restore
>       the registers around such calls.  Such allocation is done only
>       when it seems to result in better code.
>
> so -foptimize-caller-saves can be understood as optimizing out the "extra
> instructions to save and restore  the registers around such calls"  and, thus,
> as having a direct relationship with -fcaller-saves.

Agree.

But, given the preference of a number of others for fipa-ra, could you live with 
that?

Thanks,
- Tom
Eric Botcazou Oct. 20, 2014, 5:17 p.m. UTC | #14
> But, given the preference of a number of others for fipa-ra, could you live
> with that?

Yes, IMO that's too vague a name but still better than the existing one. :-)
diff mbox

Patch

diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 15310d8..eb0fe8e 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -408,6 +408,15 @@  public:
   /* Time profiler: first run of function.  */
   int tp_first_run;
 
+  /* Call unsaved hard registers really used by the corresponding
+     function (including ones used by functions called by the
+     function).  */
+  HARD_REG_SET function_used_regs;
+  /* Set if function_used_regs is initialized.  */
+  unsigned function_used_regs_initialized: 1;
+  /* Set if function_used_regs is valid.  */
+  unsigned function_used_regs_valid: 1;
+
   /* Set when decl is an abstract function pointed to by the
      ABSTRACT_DECL_ORIGIN of a reachable function.  */
   unsigned used_as_abstract_origin : 1;
diff --git a/gcc/final.c b/gcc/final.c
index 83abee2..0b1947d 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -49,6 +49,7 @@  along with GCC; see the file COPYING3.  If not see
 
 #include "tree.h"
 #include "varasm.h"
+#include "hard-reg-set.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "regs.h"
@@ -57,7 +58,6 @@  along with GCC; see the file COPYING3.  If not see
 #include "recog.h"
 #include "conditions.h"
 #include "flags.h"
-#include "hard-reg-set.h"
 #include "output.h"
 #include "except.h"
 #include "function.h"
@@ -223,6 +223,7 @@  static int alter_cond (rtx);
 static int final_addr_vec_align (rtx);
 #endif
 static int align_fuzz (rtx, rtx, int, unsigned);
+static void collect_fn_hard_reg_usage (void);
 
 /* Initialize data in final at the beginning of a compilation.  */
 
@@ -4425,6 +4426,7 @@  rest_of_handle_final (void)
   assemble_start_function (current_function_decl, fnname);
   final_start_function (get_insns (), asm_out_file, optimize);
   final (get_insns (), asm_out_file, optimize);
+  collect_fn_hard_reg_usage ();
   final_end_function ();
 
   /* The IA-64 ".handlerdata" directive must be issued before the ".endp"
@@ -4720,3 +4722,119 @@  make_pass_clean_state (gcc::context *ctxt)
 {
   return new pass_clean_state (ctxt);
 }
+
+/* Collect hard register usage for the current function.  */
+
+static void
+collect_fn_hard_reg_usage (void)
+{
+  rtx insn;
+  int i;
+  struct cgraph_node *node;
+
+  if (!flag_use_caller_save)
+    return;
+
+  node = cgraph_get_node (current_function_decl);
+  gcc_assert (node != NULL);
+
+  gcc_assert (!node->function_used_regs_initialized);
+  node->function_used_regs_initialized = 1;
+
+  for (insn = get_insns (); insn != NULL_RTX; insn = next_insn (insn))
+    {
+      HARD_REG_SET insn_used_regs;
+
+      if (!NONDEBUG_INSN_P (insn))
+	continue;
+
+      find_all_hard_reg_sets (insn, &insn_used_regs, false);
+
+      if (CALL_P (insn)
+	  && (!targetm.call_fusage_contains_non_callee_clobbers ()
+	      || !get_call_reg_set_usage (insn, &insn_used_regs, call_used_reg_set)))
+	{
+	  CLEAR_HARD_REG_SET (node->function_used_regs);
+	  return;
+	}
+
+      IOR_HARD_REG_SET (node->function_used_regs, insn_used_regs);
+    }
+
+  /* Be conservative - mark fixed and global registers as used.  */
+  IOR_HARD_REG_SET (node->function_used_regs, fixed_reg_set);
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (global_regs[i])
+      SET_HARD_REG_BIT (node->function_used_regs, i);
+
+#ifdef STACK_REGS
+  /* Handle STACK_REGS conservatively, since the df-framework does not
+     provide accurate information for them.  */
+
+  for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
+    SET_HARD_REG_BIT (node->function_used_regs, i);
+#endif
+
+  node->function_used_regs_valid = 1;
+}
+
+/* Get the declaration of the function called by INSN.  */
+
+static tree
+get_call_fndecl (rtx insn)
+{
+  rtx note, datum;
+
+  if (!flag_use_caller_save)
+    return NULL_TREE;
+
+  note = find_reg_note (insn, REG_CALL_DECL, NULL_RTX);
+  if (note == NULL_RTX)
+    return NULL_TREE;
+
+  datum = XEXP (note, 0);
+  if (datum != NULL_RTX)
+    return SYMBOL_REF_DECL (datum);
+
+  return NULL_TREE;
+}
+
+static struct cgraph_node *
+get_call_cgraph_node (rtx insn)
+{
+  tree fndecl;
+
+  if (insn == NULL_RTX)
+    return NULL;
+
+  fndecl = get_call_fndecl (insn);
+  if (fndecl == NULL_TREE
+      || !targetm.binds_local_p (fndecl))
+    return NULL;
+
+  return cgraph_get_node (fndecl);
+}
+
+/* Find hard registers used by function call instruction INSN, and return them
+   in REG_SET.  Return DEFAULT_SET in REG_SET if not found.  */
+
+bool
+get_call_reg_set_usage (rtx insn, HARD_REG_SET *reg_set,
+			HARD_REG_SET default_set)
+{
+  if (flag_use_caller_save
+      && targetm.call_fusage_contains_non_callee_clobbers ())
+    {
+      struct cgraph_node *node = get_call_cgraph_node (insn);
+      if (node != NULL
+	  && node->function_used_regs_valid)
+	{
+	  COPY_HARD_REG_SET (*reg_set, node->function_used_regs);
+	  AND_HARD_REG_SET (*reg_set, default_set);
+	  return true;
+	}
+    }
+
+  COPY_HARD_REG_SET (*reg_set, default_set);
+  return false;
+}
diff --git a/gcc/regs.h b/gcc/regs.h
index 006caca..44cc005 100644
--- a/gcc/regs.h
+++ b/gcc/regs.h
@@ -421,4 +421,8 @@  range_in_hard_reg_set_p (const HARD_REG_SET set, unsigned regno, int nregs)
   return true;
 }
 
+/* Get registers used by given function call instruction.  */
+extern bool get_call_reg_set_usage (rtx insn, HARD_REG_SET *reg_set,
+				    HARD_REG_SET default_set);
+
 #endif /* GCC_REGS_H */