Patchwork [IA-64] Fix dynamic allocation in leaf functions

login
register
mail settings
Submitter Eric Botcazou
Date Nov. 19, 2012, 10:12 p.m.
Message ID <3632647.sGSbmzomM5@polaris>
Download mbox | patch
Permalink /patch/200202/
State New
Headers show

Comments

Eric Botcazou - Nov. 19, 2012, 10:12 p.m.
Hi,

the IA-64 has a red zone of 16 bytes at the bottom of the stack:

/* IA64 has a 16 byte scratch area that is at the bottom of the stack.  */
#define STACK_POINTER_OFFSET 16

but doesn't maintain it for leaf functions:

  /* We always use the 16-byte scratch area provided by the caller, but
     if we are a leaf function, there's no one to which we need to provide
     a scratch area.  */
  if (crtl->is_leaf)
    total_size = MAX (0, total_size - 16);


Things go wrong when a dynamic allocation is made in a leaf function, because 
STACK_DYNAMIC_OFFSET comprises STACK_POINTER_OFFSET and thus thinks that the 
red zone is present.  This has probably been there since day #1 but was hidden 
by the double alignment that used to be made by allocate_dynamic_stack_space 
up to 4.5 and that was cleaned up by RTH in 4.6 and up.

Fix attached, bootstrapped/regtested on ia64-suse-linux.  It eliminates:

-FAIL: gcc.c-torture/execute/20040811-1.c execution,  -O0 
-FAIL: gcc.c-torture/execute/pr43220.c execution,  -O0 
-FAIL: gcc.c-torture/execute/vla-dealloc-1.c execution,  -O0 
-WARNING: program timed out.
-WARNING: program timed out.
-WARNING: program timed out.

on the mainline.   I think that we need to put this on mainline and 4.7 branch 
at least; not clear for the 4.6 branch at this point.  OK for which ones?


2012-11-19  Eric Botcazou  <ebotcazou@adacore.com>

	* config/ia64/ia64.c (ia64_compute_frame_size): Allocate the scratch
	area if the function allocates dynamic stack space.
	(ia64_initial_elimination_offset): Adjust offsets to above change.
Eric Botcazou - Dec. 3, 2012, 12:16 p.m.
> 2012-11-19  Eric Botcazou  <ebotcazou@adacore.com>
> 
> 	* config/ia64/ia64.c (ia64_compute_frame_size): Allocate the scratch
> 	area if the function allocates dynamic stack space.
> 	(ia64_initial_elimination_offset): Adjust offsets to above change.

Ping: http://gcc.gnu.org/ml/gcc-patches/2012-11/msg01617.html

Thanks in advance.
Richard Henderson - Dec. 3, 2012, 11:56 p.m.
On 2012-11-19 16:12, Eric Botcazou wrote:
> 2012-11-19  Eric Botcazou  <ebotcazou@adacore.com>
> 
> 	* config/ia64/ia64.c (ia64_compute_frame_size): Allocate the scratch
> 	area if the function allocates dynamic stack space.
> 	(ia64_initial_elimination_offset): Adjust offsets to above change.

Ok for any branch.


r~
Steve Ellcey - Dec. 4, 2012, 6:48 p.m.
On Mon, 2012-12-03 at 13:16 +0100, Eric Botcazou wrote:
> > 2012-11-19  Eric Botcazou  <ebotcazou@adacore.com>
> > 
> > 	* config/ia64/ia64.c (ia64_compute_frame_size): Allocate the scratch
> > 	area if the function allocates dynamic stack space.
> > 	(ia64_initial_elimination_offset): Adjust offsets to above change.
> 
> Ping: http://gcc.gnu.org/ml/gcc-patches/2012-11/msg01617.html
> 
> Thanks in advance.


Eric, this looks OK to me.  As for back porting it, that is OK with me
too as long as it is OK with the release/branch managers.

Steve Ellcey
sellcey@mips.com

Patch

Index: config/ia64/ia64.c
===================================================================
--- config/ia64/ia64.c	(revision 193596)
+++ config/ia64/ia64.c	(working copy)
@@ -2885,8 +2885,10 @@  ia64_compute_frame_size (HOST_WIDE_INT s
 
   /* We always use the 16-byte scratch area provided by the caller, but
      if we are a leaf function, there's no one to which we need to provide
-     a scratch area.  */
-  if (crtl->is_leaf)
+     a scratch area.  However, if the function allocates dynamic stack space,
+     the dynamic offset is computed early and contains STACK_POINTER_OFFSET,
+     so we need to cope.  */
+  if (crtl->is_leaf && !cfun->calls_alloca)
     total_size = MAX (0, total_size - 16);
 
   current_frame_info.total_size = total_size;
@@ -2920,18 +2922,15 @@  ia64_initial_elimination_offset (int fro
       switch (to)
 	{
 	case HARD_FRAME_POINTER_REGNUM:
-	  if (crtl->is_leaf)
-	    offset = -current_frame_info.total_size;
-	  else
-	    offset = -(current_frame_info.total_size
-		       - crtl->outgoing_args_size - 16);
+	  offset = -current_frame_info.total_size;
+	  if (!crtl->is_leaf || cfun->calls_alloca)
+	    offset += 16 + crtl->outgoing_args_size;
 	  break;
 
 	case STACK_POINTER_REGNUM:
-	  if (crtl->is_leaf)
-	    offset = 0;
-	  else
-	    offset = 16 + crtl->outgoing_args_size;
+	  offset = 0;
+	  if (!crtl->is_leaf || cfun->calls_alloca)
+	    offset += 16 + crtl->outgoing_args_size;
 	  break;
 
 	default: