diff mbox

[ARM] Avoid spilling ip for nested APCS frames

Message ID 2875293.NhuTJeLEWM@polaris
State New
Headers show

Commit Message

Eric Botcazou May 31, 2013, 5:59 p.m. UTC
The ARM/VxWorks port uses APCS frames and therefore ip to establish frames 
with a frame pointer.  Now, for nested functions, ip is also the static chain 
register so it needs to be preserved when the frame is being established.

There is code to that effect trying to save ip into r3 if the latter register 
is available but, unfortunately, it uses df_regs_ever_live_p (3) to detect the 
availability and this returns true for any non-toy function.

Fixed by implementing an arm_r3_live_at_start_p modelled on the implementation 
of an equivalent predicate for %eax in the x86 back-end.

Tested on ARM/VxWorks, OK for the mainline?


2013-05-31  Eric Botcazou  <ebotcazou@adacore.com>

	* config/arm/arm.c (arm_r3_live_at_start_p): New predicate.
	(arm_compute_static_chain_stack_bytes): Use it.  Tidy up.
	(arm_expand_prologue): Likewise.

Comments

Richard Earnshaw June 6, 2013, 4:13 p.m. UTC | #1
On 31/05/13 18:59, Eric Botcazou wrote:
> The ARM/VxWorks port uses APCS frames and therefore ip to establish frames
> with a frame pointer.  Now, for nested functions, ip is also the static chain
> register so it needs to be preserved when the frame is being established.
>
> There is code to that effect trying to save ip into r3 if the latter register
> is available but, unfortunately, it uses df_regs_ever_live_p (3) to detect the
> availability and this returns true for any non-toy function.
>
> Fixed by implementing an arm_r3_live_at_start_p modelled on the implementation
> of an equivalent predicate for %eax in the x86 back-end.
>
> Tested on ARM/VxWorks, OK for the mainline?
>
>
> 2013-05-31  Eric Botcazou  <ebotcazou@adacore.com>
>
> 	* config/arm/arm.c (arm_r3_live_at_start_p): New predicate.
> 	(arm_compute_static_chain_stack_bytes): Use it.  Tidy up.
> 	(arm_expand_prologue): Likewise.
>

OK

R.
diff mbox

Patch

Index: config/arm/arm.c
===================================================================
--- config/arm/arm.c	(revision 199343)
+++ config/arm/arm.c	(working copy)
@@ -16135,25 +16135,34 @@  arm_compute_save_reg0_reg12_mask (void)
   return save_reg_mask;
 }
 
+/* Return true if r3 is live at the start of the function.  */
+
+static bool
+arm_r3_live_at_start_p (void)
+{
+  /* Just look at cfg info, which is still close enough to correct at this
+     point.  This gives false positives for broken functions that might use
+     uninitialized data that happens to be allocated in r3, but who cares?  */
+  return REGNO_REG_SET_P (df_get_live_out (ENTRY_BLOCK_PTR), 3);
+}
 
 /* Compute the number of bytes used to store the static chain register on the
-   stack, above the stack frame. We need to know this accurately to get the
-   alignment of the rest of the stack frame correct. */
+   stack, above the stack frame.  We need to know this accurately to get the
+   alignment of the rest of the stack frame correct.  */
 
-static int arm_compute_static_chain_stack_bytes (void)
+static int
+arm_compute_static_chain_stack_bytes (void)
 {
-  unsigned long func_type = arm_current_func_type ();
-  int static_chain_stack_bytes = 0;
+  /* See the defining assertion in arm_expand_prologue.  */
+  if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM
+      && IS_NESTED (arm_current_func_type ())
+      && arm_r3_live_at_start_p ()
+      && crtl->args.pretend_args_size == 0)
+    return 4;
 
-  if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM &&
-      IS_NESTED (func_type) &&
-      df_regs_ever_live_p (3) && crtl->args.pretend_args_size == 0)
-    static_chain_stack_bytes = 4;
-
-  return static_chain_stack_bytes;
+  return 0;
 }
 
-
 /* 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.  */
@@ -18081,16 +18090,16 @@  arm_expand_prologue (void)
 	}
       else if (IS_NESTED (func_type))
 	{
-	  /* The Static chain register is the same as the IP register
+	  /* The static chain register is the same as the IP register
 	     used as a scratch register during stack frame creation.
 	     To get around this need to find somewhere to store IP
 	     whilst the frame is being created.  We try the following
 	     places in order:
 
-	       1. The last argument register.
+	       1. The last argument register r3.
 	       2. A slot on the stack above the frame.  (This only
 	          works if the function is not a varargs function).
-	       3. Register r3, after pushing the argument registers
+	       3. Register r3 again, after pushing the argument registers
 	          onto the stack.
 
 	     Note - we only need to tell the dwarf2 backend about the SP
@@ -18098,7 +18107,7 @@  arm_expand_prologue (void)
 	     doesn't need to be unwound, as it doesn't contain a value
 	     inherited from the caller.  */
 
-	  if (df_regs_ever_live_p (3) == false)
+	  if (!arm_r3_live_at_start_p ())
 	    insn = emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
 	  else if (args_to_push == 0)
 	    {
@@ -18239,8 +18248,7 @@  arm_expand_prologue (void)
 	  if (IS_NESTED (func_type))
 	    {
 	      /* Recover the static chain register.  */
-	      if (!df_regs_ever_live_p (3)
-		  || saved_pretend_args)
+	      if (!arm_r3_live_at_start_p () || saved_pretend_args)
 		insn = gen_rtx_REG (SImode, 3);
 	      else /* if (crtl->args.pretend_args_size == 0) */
 		{