diff mbox

[ARM] Add a new target hook to compute the frame layout

Message ID AM4PR0701MB2162E930AA1FF46D63E3AC55E4E80@AM4PR0701MB2162.eurprd07.prod.outlook.com
State New
Headers show

Commit Message

Bernd Edlinger May 6, 2017, 6:07 p.m. UTC
On 05/05/17 16:59, Richard Earnshaw (lists) wrote:
> On 05/09/16 17:43, Bernd Edlinger wrote:
>> Hi Richard,
>>
>> what do you think of this patch, is it OK (with the suggested wording)?
>>
>
> Bernd,
>
> Apologies, this seems to have fallen through a crack.
>
> I'm happy with this.  Does it still apply?
>

Yes, only in a few places the context lines changed slightly.
So I attached a refreshed patch for your reference.

> If so, I suggest applying it after a 24-hour cooling off period for any
> final comments.
>

Fine, then I will apply it on monday evening, unless someone objects.


Thanks
Bernd.

> R.
>
>>
>> Thanks
>> Bernd.
>>
>> On 08/05/16 16:06, Richard Earnshaw (lists) wrote:
>>> On 05/08/16 13:49, Bernd Edlinger wrote:
>>>> On 08/05/16 11:29, Richard Earnshaw (lists) wrote:
>>>>> On 04/08/16 22:16, Bernd Edlinger wrote:
>>>>>> Hi,
>>>>>>
>>>>>> this patch introduces a new target hook that allows the target's
>>>>>> INITIAL_ELIMINATION_OFFSET function to use cached values instead of
>>>>>> re-computing the frame layout every time.
>>>>>>
>>>>>> I have updated the documentation a bit and hope it is clearer this time.
>>>>>>
>>>>>> It still needs a review by ARM port maintainers.
>>>>>>
>>>>>> If the ARM port maintainers find this patch useful, that would be fine.
>>>>>>
>>>>>
>>>>> I need to look into this more, but my first thought was that the
>>>>> documentation is confusing, or there is a real problem in this patch.
>>>>>
>>>>
>>>> Thanks for your quick response.
>>>>
>>>> The documentation is actually the most difficult part for me.
>>>>
>>>>> As I understand it the frame has to be re-laid out each time the
>>>>> contents of the frame changes (an extra register becomes live or another
>>>>> spill slot is needed).  So saying that it is laid out once can't be
>>>>> right if (as I read it initially) you mean 'once per function' since I
>>>>> think it needs to be 'once for each time the frame contents changes'.
>>>>>
>>>>> Of course, things might be a bit different with LRA compared with
>>>>> reload, but I strongly suspect this is never going to be an 'exactly
>>>>> once per function' operation.
>>>>>
>>>>
>>>> Right.  It will be done 2 or 3 times for each function.
>>>> LRA and reload behave identical in that respect.
>>>>
>>>> But each time reload changes something in the input data the
>>>> INITIAL_EMIMINATION_OFFSET is called several times, and the results
>>>> have to be consistent in each iteration.
>>>>
>>>> The frame layout function has no way to know if the frame layout
>>>> is expected to change or not.
>>>>
>>>> Many targets use reload_completed as an indication when the frame layout
>>>> may not change at all, but that is only an approximation.
>>>>
>>>>> Can you clarify your meaning in the documentation please?
>>>>>
>>>>
>>>> I meant 'once' in the sense of 'once for each time the frame contents
>>>> change'.
>>>>
>>>> Thus I'd change that sentence to:
>>>>
>>>> "This target hook allows the target to compute the frame layout once for
>>>> each time the frame contents change and make use of the cached frame
>>>> layout in @code{INITIAL_ELIMINATION_OFFSET} instead of re-computing it
>>>> on every invocation.  This is particularly useful for targets that have
>>>> an expensive frame layout function.  Implementing this callback is
>>>> optional."
>>>>
>>>
>>> Thanks, that's pretty much what I expected would be the case.
>>>
>>> Could I suggest:
>>>
>>> This target hook is called once each time the frame layout needs to be
>>> recalculated.  The calculations can be cached by the target and can then
>>> be used by @code{INITIAL_ELIMINATION_OFFSET} instead of re-computing the
>>> layout on every invocation of that hook.  This is particularly useful
>>> for targets that have an expensive frame layout function.  Implementing
>>> this callback is optional.
>>>
>>> R.
>>>
>>>>
>>>> Thanks
>>>> Bernd.
>>>>
>>>>
>>>>> R.
>>>>>
>>>>>>
>>>>>> Thanks
>>>>>> Bernd.
>>>>>>
>>>>>> On 06/21/16 23:29, Jeff Law wrote:
>>>>>>> On 06/16/2016 08:47 AM, Bernd Edlinger wrote:
>>>>>>>> Hi!
>>>>>>>>
>>>>>>>>
>>>>>>>> By the design of the target hook INITIAL_ELIMINATION_OFFSET
>>>>>>>> it is necessary to call this function several times with
>>>>>>>> different register combinations.
>>>>>>>> Most targets use a cached data structure that describes the
>>>>>>>> exact frame layout of the current function.
>>>>>>>>
>>>>>>>> It is safe to skip the computation when reload_completed = true,
>>>>>>>> and most targets do that already.
>>>>>>>>
>>>>>>>> However while reload is doing its work, it is not clear when to
>>>>>>>> do the computation and when not.  This results in unnecessary
>>>>>>>> work.  Computing the frame layout can be a simple function or an
>>>>>>>> arbitrarily complex one, that walks all instructions of the current
>>>>>>>> function for instance, which is more or less the common case.
>>>>>>>>
>>>>>>>>
>>>>>>>> This patch adds a new optional target hook that can be used
>>>>>>>> by the target to factor the INITIAL_ELIMINATION_OFFSET-hook
>>>>>>>> into a O(n) computation part, and a O(1) result function.
>>>>>>>>
>>>>>>>> The patch implements a compute_frame_layout target hook just
>>>>>>>> for ARM in the moment, to show the principle.
>>>>>>>> Other targets may also implement that hook, if it seems appropriate.
>>>>>>>>
>>>>>>>>
>>>>>>>> Boot-strapped and reg-tested on arm-linux-gnueabihf.
>>>>>>>> OK for trunk?
>>>>>>>>
>>>>>>>>
>>>>>>>> Thanks
>>>>>>>> Bernd.
>>>>>>>>
>>>>>>>>
>>>>>>>> changelog-frame-layout.txt
>>>>>>>>
>>>>>>>>
>>>>>>>> 2016-06-16  Bernd Edlinger  <bernd.edlinger@hotmail.de>
>>>>>>>>
>>>>>>>>       * target.def (compute_frame_layout): New optional target hook.
>>>>>>>>       * doc/tm.texi.in (TARGET_COMPUTE_FRAME_LAYOUT): Add hook.
>>>>>>>>       * doc/tm.texi (TARGET_COMPUTE_FRAME_LAYOUT): Add documentation.
>>>>>>>>       * lra-eliminations.c (update_reg_eliminate): Call
>>>>>>>> compute_frame_layout
>>>>>>>>       target hook.
>>>>>>>>       * reload1.c (verify_initial_elim_offsets): Likewise.
>>>>>>>>       * config/arm/arm.c (TARGET_COMPUTE_FRAME_LAYOUT): Define.
>>>>>>>>       (use_simple_return_p): Call arm_compute_frame_layout if needed.
>>>>>>>>       (arm_get_frame_offsets): Split up into this ...
>>>>>>>>       (arm_compute_frame_layout): ... and this function.
>>>>>>> The ARM maintainers would need to chime in on the ARM specific changes
>>>>>>> though.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> Index: gcc/target.def
>>>>>>>> ===================================================================
>>>>>>>> --- gcc/target.def    (Revision 233176)
>>>>>>>> +++ gcc/target.def    (Arbeitskopie)
>>>>>>>> @@ -5245,8 +5245,19 @@ five otherwise.  This is best for most machines.",
>>>>>>>>     unsigned int, (void),
>>>>>>>>     default_case_values_threshold)
>>>>>>>>
>>>>>>>> -/* Retutn true if a function must have and use a frame pointer.  */
>>>>>>> s/Retutn/Return
>>>>>>>
>>>>>>>> +/* Optional callback to advise the target to compute the frame
>>>>>>>> layout.  */
>>>>>>>>    DEFHOOK
>>>>>>>> +(compute_frame_layout,
>>>>>>>> + "This target hook is called immediately before reload wants to call\n\
>>>>>>>> +@code{INITIAL_ELIMINATION_OFFSET} and allows the target to cache the
>>>>>>>> frame\n\
>>>>>>>> +layout instead of re-computing it on every invocation.  This is
>>>>>>>> particularly\n\
>>>>>>>> +useful for targets that have an O(n) frame layout function.
>>>>>>>> Implementing\n\
>>>>>>>> +this callback is optional.",
>>>>>>>> + void, (void),
>>>>>>>> + hook_void_void)
>>>>>>> So the docs say "immediately before", but that's not actually reality in
>>>>>>> lra-eliminations.  I think you can just say "This target hook is called
>>>>>>> before reload or lra-eliminations calls
>>>>>>> @code{INITIAL_ELIMINATION_OFFSET} and allows ..."
>>>>>>>
>>>>>>>
>>>>>>> How does this macro interact with INITIAL_FRAME_POINTER_OFFSET?
>>>>>>>
>>>>>>> I'm OK with this conceptually.  I think you need a minor doc update and
>>>>>>> OK from the ARM maintainers before it can be installed though.
>>>>>>>
>>>>>>> jeff
>>>>>>>
>>>>>>> changelog-frame-layout.txt
>>>>>>>
>>>>>>>
>>>>>>> 2016-06-16  Bernd Edlinger  <bernd.edlinger@hotmail.de>
>>>>>>>
>>>>>>> 	* target.def (compute_frame_layout): New optional target hook.
>>>>>>> 	* doc/tm.texi.in (TARGET_COMPUTE_FRAME_LAYOUT): Add hook.
>>>>>>> 	* doc/tm.texi (TARGET_COMPUTE_FRAME_LAYOUT): Add documentation.
>>>>>>> 	* lra-eliminations.c (update_reg_eliminate): Call compute_frame_layout
>>>>>>> 	target hook.
>>>>>>> 	* reload1.c (verify_initial_elim_offsets): Likewise.
>>>>>>> 	* config/arm/arm.c (TARGET_COMPUTE_FRAME_LAYOUT): Define.
>>>>>>> 	(use_simple_return_p): Call arm_compute_frame_layout if needed.
>>>>>>> 	(arm_get_frame_offsets): Split up into this ...
>>>>>>> 	(arm_compute_frame_layout): ... and this function.
>>>>>>>
>>>>>>> patch-frame-layout.diff
>>>>>>>
>>>>>>>
>>>>>>> Index: gcc/config/arm/arm.c
>>>>>>> ===================================================================
>>>>>>> --- gcc/config/arm/arm.c	(revision 239144)
>>>>>>> +++ gcc/config/arm/arm.c	(working copy)
>>>>>>> @@ -81,6 +81,7 @@ static bool arm_const_not_ok_for_debug_p (rtx);
>>>>>>>    static bool arm_needs_doubleword_align (machine_mode, const_tree);
>>>>>>>    static int arm_compute_static_chain_stack_bytes (void);
>>>>>>>    static arm_stack_offsets *arm_get_frame_offsets (void);
>>>>>>> +static void arm_compute_frame_layout (void);
>>>>>>>    static void arm_add_gc_roots (void);
>>>>>>>    static int arm_gen_constant (enum rtx_code, machine_mode, rtx,
>>>>>>>    			     unsigned HOST_WIDE_INT, rtx, rtx, int, int);
>>>>>>> @@ -663,6 +664,9 @@ static const struct attribute_spec arm_attribute_t
>>>>>>>    #undef TARGET_SCALAR_MODE_SUPPORTED_P
>>>>>>>    #define TARGET_SCALAR_MODE_SUPPORTED_P arm_scalar_mode_supported_p
>>>>>>>
>>>>>>> +#undef TARGET_COMPUTE_FRAME_LAYOUT
>>>>>>> +#define TARGET_COMPUTE_FRAME_LAYOUT arm_compute_frame_layout
>>>>>>> +
>>>>>>>    #undef TARGET_FRAME_POINTER_REQUIRED
>>>>>>>    #define TARGET_FRAME_POINTER_REQUIRED arm_frame_pointer_required
>>>>>>>
>>>>>>> @@ -3880,6 +3884,10 @@ use_simple_return_p (void)
>>>>>>>    {
>>>>>>>      arm_stack_offsets *offsets;
>>>>>>>
>>>>>>> +  /* Note this function can be called before or after reload.  */
>>>>>>> +  if (!reload_completed)
>>>>>>> +    arm_compute_frame_layout ();
>>>>>>> +
>>>>>>>      offsets = arm_get_frame_offsets ();
>>>>>>>      return offsets->outgoing_args != 0;
>>>>>>>    }
>>>>>>> @@ -19370,7 +19378,7 @@ arm_compute_static_chain_stack_bytes (void)
>>>>>>>
>>>>>>>    /* Compute a bit mask of which registers need to be
>>>>>>>       saved on the stack for the current function.
>>>>>>> -   This is used by arm_get_frame_offsets, which may add extra registers.  */
>>>>>>> +   This is used by arm_compute_frame_layout, which may add extra registers.  */
>>>>>>>
>>>>>>>    static unsigned long
>>>>>>>    arm_compute_save_reg_mask (void)
>>>>>>> @@ -20926,12 +20934,25 @@ any_sibcall_could_use_r3 (void)
>>>>>>>      alignment.  */
>>>>>>>
>>>>>>>
>>>>>>> +/* Return cached stack offsets.  */
>>>>>>> +
>>>>>>> +static arm_stack_offsets *
>>>>>>> +arm_get_frame_offsets (void)
>>>>>>> +{
>>>>>>> +  struct arm_stack_offsets *offsets;
>>>>>>> +
>>>>>>> +  offsets = &cfun->machine->stack_offsets;
>>>>>>> +
>>>>>>> +  return offsets;
>>>>>>> +}
>>>>>>> +
>>>>>>> +
>>>>>>>    /* Calculate stack offsets.  These are used to calculate register elimination
>>>>>>>       offsets and in prologue/epilogue code.  Also calculates which registers
>>>>>>>       should be saved.  */
>>>>>>>
>>>>>>> -static arm_stack_offsets *
>>>>>>> -arm_get_frame_offsets (void)
>>>>>>> +static void
>>>>>>> +arm_compute_frame_layout (void)
>>>>>>>    {
>>>>>>>      struct arm_stack_offsets *offsets;
>>>>>>>      unsigned long func_type;
>>>>>>> @@ -20943,19 +20964,6 @@ any_sibcall_could_use_r3 (void)
>>>>>>>
>>>>>>>      offsets = &cfun->machine->stack_offsets;
>>>>>>>
>>>>>>> -  /* We need to know if we are a leaf function.  Unfortunately, it
>>>>>>> -     is possible to be called after start_sequence has been called,
>>>>>>> -     which causes get_insns to return the insns for the sequence,
>>>>>>> -     not the function, which will cause leaf_function_p to return
>>>>>>> -     the incorrect result.
>>>>>>> -
>>>>>>> -     to know about leaf functions once reload has completed, and the
>>>>>>> -     frame size cannot be changed after that time, so we can safely
>>>>>>> -     use the cached value.  */
>>>>>>> -
>>>>>>> -  if (reload_completed)
>>>>>>> -    return offsets;
>>>>>>> -
>>>>>>>      /* Initially this is the size of the local variables.  It will translated
>>>>>>>         into an offset once we have determined the size of preceding data.  */
>>>>>>>      frame_size = ROUND_UP_WORD (get_frame_size ());
>>>>>>> @@ -21022,7 +21030,7 @@ any_sibcall_could_use_r3 (void)
>>>>>>>        {
>>>>>>>          offsets->outgoing_args = offsets->soft_frame;
>>>>>>>          offsets->locals_base = offsets->soft_frame;
>>>>>>> -      return offsets;
>>>>>>> +      return;
>>>>>>>        }
>>>>>>>
>>>>>>>      /* Ensure SFP has the correct alignment.  */
>>>>>>> @@ -21098,8 +21106,6 @@ any_sibcall_could_use_r3 (void)
>>>>>>>    	offsets->outgoing_args += 4;
>>>>>>>          gcc_assert (!(offsets->outgoing_args & 7));
>>>>>>>        }
>>>>>>> -
>>>>>>> -  return offsets;
>>>>>>>    }
>>>>>>>
>>>>>>>
>>>>>>> Index: gcc/doc/tm.texi
>>>>>>> ===================================================================
>>>>>>> --- gcc/doc/tm.texi	(revision 239144)
>>>>>>> +++ gcc/doc/tm.texi	(working copy)
>>>>>>> @@ -3693,6 +3693,14 @@ registers.  This macro must be defined if @code{EL
>>>>>>>    defined.
>>>>>>>    @end defmac
>>>>>>>
>>>>>>> +@deftypefn {Target Hook} void TARGET_COMPUTE_FRAME_LAYOUT (void)
>>>>>>> +This target hook allows the target to compute the frame layout once and
>>>>>>> +make use of the cached frame layout in @code{INITIAL_ELIMINATION_OFFSET}
>>>>>>> +instead of re-computing it on every invocation.  This is particularly
>>>>>>> +useful for targets that have an expensive frame layout function.
>>>>>>> +Implementing this callback is optional.
>>>>>>> +@end deftypefn
>>>>>>> +
>>>>>>>    @node Stack Arguments
>>>>>>>    @subsection Passing Function Arguments on the Stack
>>>>>>>    @cindex arguments on stack
>>>>>>> Index: gcc/doc/tm.texi.in
>>>>>>> ===================================================================
>>>>>>> --- gcc/doc/tm.texi.in	(revision 239144)
>>>>>>> +++ gcc/doc/tm.texi.in	(working copy)
>>>>>>> @@ -3227,6 +3227,8 @@ registers.  This macro must be defined if @code{EL
>>>>>>>    defined.
>>>>>>>    @end defmac
>>>>>>>
>>>>>>> +@hook TARGET_COMPUTE_FRAME_LAYOUT
>>>>>>> +
>>>>>>>    @node Stack Arguments
>>>>>>>    @subsection Passing Function Arguments on the Stack
>>>>>>>    @cindex arguments on stack
>>>>>>> Index: gcc/lra-eliminations.c
>>>>>>> ===================================================================
>>>>>>> --- gcc/lra-eliminations.c	(revision 239144)
>>>>>>> +++ gcc/lra-eliminations.c	(working copy)
>>>>>>> @@ -1203,6 +1203,10 @@ update_reg_eliminate (bitmap insns_with_changed_of
>>>>>>>      struct lra_elim_table *ep, *ep1;
>>>>>>>      HARD_REG_SET temp_hard_reg_set;
>>>>>>>
>>>>>>> +#ifdef ELIMINABLE_REGS
>>>>>>> +  targetm.compute_frame_layout ();
>>>>>>> +#endif
>>>>>>> +
>>>>>>>      /* Clear self elimination offsets.  */
>>>>>>>      for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
>>>>>>>        self_elim_offsets[ep->from] = 0;
>>>>>>> Index: gcc/reload1.c
>>>>>>> ===================================================================
>>>>>>> --- gcc/reload1.c	(revision 239144)
>>>>>>> +++ gcc/reload1.c	(working copy)
>>>>>>> @@ -3831,6 +3831,7 @@ verify_initial_elim_offsets (void)
>>>>>>>      {
>>>>>>>       struct elim_table *ep;
>>>>>>>
>>>>>>> +   targetm.compute_frame_layout ();
>>>>>>>       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
>>>>>>>         {
>>>>>>>           INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, t);
>>>>>>> @@ -3855,6 +3856,7 @@ set_initial_elim_offsets (void)
>>>>>>>      struct elim_table *ep = reg_eliminate;
>>>>>>>
>>>>>>>    #ifdef ELIMINABLE_REGS
>>>>>>> +  targetm.compute_frame_layout ();
>>>>>>>      for (; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
>>>>>>>        {
>>>>>>>          INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, ep->initial_offset);
>>>>>>> Index: gcc/target.def
>>>>>>> ===================================================================
>>>>>>> --- gcc/target.def	(revision 239144)
>>>>>>> +++ gcc/target.def	(working copy)
>>>>>>> @@ -5269,8 +5269,19 @@ five otherwise.  This is best for most machines.",
>>>>>>>     unsigned int, (void),
>>>>>>>     default_case_values_threshold)
>>>>>>>
>>>>>>> -/* Retutn true if a function must have and use a frame pointer.  */
>>>>>>> +/* Optional callback to advise the target to compute the frame layout.  */
>>>>>>>    DEFHOOK
>>>>>>> +(compute_frame_layout,
>>>>>>> + "This target hook allows the target to compute the frame layout once and\n\
>>>>>>> +make use of the cached frame layout in @code{INITIAL_ELIMINATION_OFFSET}\n\
>>>>>>> +instead of re-computing it on every invocation.  This is particularly\n\
>>>>>>> +useful for targets that have an expensive frame layout function.\n\
>>>>>>> +Implementing this callback is optional.",
>>>>>>> + void, (void),
>>>>>>> + hook_void_void)
>>>>>>> +
>>>>>>> +/* Return true if a function must have and use a frame pointer.  */
>>>>>>> +DEFHOOK
>>>>>>>    (frame_pointer_required,
>>>>>>>     "This target hook should return @code{true} if a function must have and use\n\
>>>>>>>    a frame pointer.  This target hook is called in the reload pass.  If its return\n\
>>>>>
>>>>
>>>
>
2016-06-16  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* target.def (compute_frame_layout): New optional target hook.
	* doc/tm.texi.in (TARGET_COMPUTE_FRAME_LAYOUT): Add hook.
	* doc/tm.texi (TARGET_COMPUTE_FRAME_LAYOUT): Add documentation.
	* lra-eliminations.c (update_reg_eliminate): Call compute_frame_layout
	target hook.
	* reload1.c (verify_initial_elim_offsets): Likewise.
	* config/arm/arm.c (TARGET_COMPUTE_FRAME_LAYOUT): Define.
	(use_simple_return_p): Call arm_compute_frame_layout if needed.
	(arm_get_frame_offsets): Split up into this ...
	(arm_compute_frame_layout): ... and this function.
diff mbox

Patch

Index: gcc/config/arm/arm.c
===================================================================
--- gcc/config/arm/arm.c	(revision 247710)
+++ gcc/config/arm/arm.c	(working copy)
@@ -85,6 +85,7 @@  static bool arm_const_not_ok_for_debug_p (rtx);
 static int arm_needs_doubleword_align (machine_mode, const_tree);
 static int arm_compute_static_chain_stack_bytes (void);
 static arm_stack_offsets *arm_get_frame_offsets (void);
+static void arm_compute_frame_layout (void);
 static void arm_add_gc_roots (void);
 static int arm_gen_constant (enum rtx_code, machine_mode, rtx,
 			     unsigned HOST_WIDE_INT, rtx, rtx, int, int);
@@ -680,6 +681,9 @@  static const struct attribute_spec arm_attribute_t
 #undef TARGET_SCALAR_MODE_SUPPORTED_P
 #define TARGET_SCALAR_MODE_SUPPORTED_P arm_scalar_mode_supported_p
 
+#undef TARGET_COMPUTE_FRAME_LAYOUT
+#define TARGET_COMPUTE_FRAME_LAYOUT arm_compute_frame_layout
+
 #undef TARGET_FRAME_POINTER_REQUIRED
 #define TARGET_FRAME_POINTER_REQUIRED arm_frame_pointer_required
 
@@ -4031,6 +4035,10 @@  use_simple_return_p (void)
 {
   arm_stack_offsets *offsets;
 
+  /* Note this function can be called before or after reload.  */
+  if (!reload_completed)
+    arm_compute_frame_layout ();
+
   offsets = arm_get_frame_offsets ();
   return offsets->outgoing_args != 0;
 }
@@ -19138,7 +19146,7 @@  arm_compute_static_chain_stack_bytes (void)
 
 /* Compute a bit mask of which registers need to be
    saved on the stack for the current function.
-   This is used by arm_get_frame_offsets, which may add extra registers.  */
+   This is used by arm_compute_frame_layout, which may add extra registers.  */
 
 static unsigned long
 arm_compute_save_reg_mask (void)
@@ -20772,12 +20780,25 @@  any_sibcall_could_use_r3 (void)
   alignment.  */
 
 
+/* Return cached stack offsets.  */
+
+static arm_stack_offsets *
+arm_get_frame_offsets (void)
+{
+  struct arm_stack_offsets *offsets;
+
+  offsets = &cfun->machine->stack_offsets;
+
+  return offsets;
+}
+
+
 /* Calculate stack offsets.  These are used to calculate register elimination
    offsets and in prologue/epilogue code.  Also calculates which registers
    should be saved.  */
 
-static arm_stack_offsets *
-arm_get_frame_offsets (void)
+static void
+arm_compute_frame_layout (void)
 {
   struct arm_stack_offsets *offsets;
   unsigned long func_type;
@@ -20788,9 +20809,6 @@  any_sibcall_could_use_r3 (void)
 
   offsets = &cfun->machine->stack_offsets;
 
-  if (reload_completed)
-    return offsets;
-
   /* Initially this is the size of the local variables.  It will translated
      into an offset once we have determined the size of preceding data.  */
   frame_size = ROUND_UP_WORD (get_frame_size ());
@@ -20855,7 +20873,7 @@  any_sibcall_could_use_r3 (void)
     {
       offsets->outgoing_args = offsets->soft_frame;
       offsets->locals_base = offsets->soft_frame;
-      return offsets;
+      return;
     }
 
   /* Ensure SFP has the correct alignment.  */
@@ -20931,8 +20949,6 @@  any_sibcall_could_use_r3 (void)
 	offsets->outgoing_args += 4;
       gcc_assert (!(offsets->outgoing_args & 7));
     }
-
-  return offsets;
 }
 
 
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 247710)
+++ gcc/doc/tm.texi	(working copy)
@@ -3684,6 +3684,15 @@  such as the result of @code{get_frame_size ()} and
 registers @code{df_regs_ever_live_p} and @code{call_used_regs}.
 @end defmac
 
+@deftypefn {Target Hook} void TARGET_COMPUTE_FRAME_LAYOUT (void)
+This target hook is called once each time the frame layout needs to be
+recalculated.  The calculations can be cached by the target and can then
+be used by @code{INITIAL_ELIMINATION_OFFSET} instead of re-computing the
+layout on every invocation of that hook.  This is particularly useful
+for targets that have an expensive frame layout function.  Implementing
+this callback is optional.
+@end deftypefn
+
 @node Stack Arguments
 @subsection Passing Function Arguments on the Stack
 @cindex arguments on stack
Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in	(revision 247710)
+++ gcc/doc/tm.texi.in	(working copy)
@@ -3213,6 +3213,8 @@  such as the result of @code{get_frame_size ()} and
 registers @code{df_regs_ever_live_p} and @code{call_used_regs}.
 @end defmac
 
+@hook TARGET_COMPUTE_FRAME_LAYOUT
+
 @node Stack Arguments
 @subsection Passing Function Arguments on the Stack
 @cindex arguments on stack
Index: gcc/lra-eliminations.c
===================================================================
--- gcc/lra-eliminations.c	(revision 247710)
+++ gcc/lra-eliminations.c	(working copy)
@@ -1196,6 +1196,10 @@  update_reg_eliminate (bitmap insns_with_changed_of
   struct lra_elim_table *ep, *ep1;
   HARD_REG_SET temp_hard_reg_set;
 
+#ifdef ELIMINABLE_REGS
+  targetm.compute_frame_layout ();
+#endif
+
   /* Clear self elimination offsets.  */
   for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
     self_elim_offsets[ep->from] = 0;
Index: gcc/reload1.c
===================================================================
--- gcc/reload1.c	(revision 247710)
+++ gcc/reload1.c	(working copy)
@@ -3821,6 +3821,7 @@  verify_initial_elim_offsets (void)
   if (!num_eliminable)
     return true;
 
+  targetm.compute_frame_layout ();
   for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
     {
       INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, t);
@@ -3838,6 +3839,7 @@  set_initial_elim_offsets (void)
 {
   struct elim_table *ep = reg_eliminate;
 
+  targetm.compute_frame_layout ();
   for (; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
     {
       INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, ep->initial_offset);
Index: gcc/target.def
===================================================================
--- gcc/target.def	(revision 247710)
+++ gcc/target.def	(working copy)
@@ -5395,6 +5395,18 @@  five otherwise.  This is best for most machines.",
  unsigned int, (void),
  default_case_values_threshold)
 
+/* Optional callback to advise the target to compute the frame layout.  */
+DEFHOOK
+(compute_frame_layout,
+ "This target hook is called once each time the frame layout needs to be\n\
+recalculated.  The calculations can be cached by the target and can then\n\
+be used by @code{INITIAL_ELIMINATION_OFFSET} instead of re-computing the\n\
+layout on every invocation of that hook.  This is particularly useful\n\
+for targets that have an expensive frame layout function.  Implementing\n\
+this callback is optional.",
+ void, (void),
+ hook_void_void)
+
 /* Return true if a function must have and use a frame pointer.  */
 DEFHOOK
 (frame_pointer_required,