This is a small regression just introduced on the mainline by my patch fixing
the -freorder-blocks-and-partition optimization on x86-64/Windows. On this
platform, the SEH scheme imposes constraints on the prologue of functions, in
particular the frame pointer is near the bottom of the frame. But there is an
exception when __builtin_{frame,return}_address is present in the code and the
implementation of i386_pe_seh_cold_init fails to account for it.
Tested on x86-64/Windows, applied on the mainline as obvious.
2018-03-09 Eric Botcazou <ebotca...@adacore.com>
PR target/84763
* config/i386/winnt.c (i386_pe_seh_cold_init): Use small pre-allocation
when the function accesses prior frames.
2018-03-09 Eric Botcazou <ebotca...@adacore.com>
* gcc.c-torture/compile/20180309-1.c: New test.
--
Eric Botcazou
Index: config/i386/winnt.c
===================================================================
--- config/i386/winnt.c (revision 258338)
+++ config/i386/winnt.c (working copy)
@@ -879,7 +879,7 @@ void
i386_pe_seh_cold_init (FILE *f, const char *name)
{
struct seh_frame_state *seh;
- HOST_WIDE_INT offset;
+ HOST_WIDE_INT alloc_offset, offset;
if (!TARGET_SEH)
return;
@@ -891,7 +891,16 @@ i386_pe_seh_cold_init (FILE *f, const ch
assemble_name (f, name);
fputc ('\n', f);
- offset = seh->sp_offset - INCOMING_FRAME_SP_OFFSET;
+ /* In the normal case, the frame pointer is near the bottom of the frame
+ so we can do the full stack allocation and set it afterwards. There
+ is an exception when the function accesses prior frames so, in this
+ case, we need to pre-allocate a small chunk before setting it. */
+ if (crtl->accesses_prior_frames)
+ alloc_offset = seh->cfa_offset;
+ else
+ alloc_offset = seh->sp_offset;
+
+ offset = alloc_offset - INCOMING_FRAME_SP_OFFSET;
if (offset > 0 && offset < SEH_MAX_FRAME_SIZE)
fprintf (f, "\t.seh_stackalloc\t" HOST_WIDE_INT_PRINT_DEC "\n", offset);
@@ -903,12 +912,12 @@ i386_pe_seh_cold_init (FILE *f, const ch
: (gcc_unreachable (), "")), f);
print_reg (gen_rtx_REG (DImode, regno), 0, f);
fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n",
- seh->sp_offset - seh->reg_offset[regno]);
+ alloc_offset - seh->reg_offset[regno]);
}
if (seh->cfa_reg != stack_pointer_rtx)
{
- offset = seh->sp_offset - seh->cfa_offset;
+ offset = alloc_offset - seh->cfa_offset;
gcc_assert ((offset & 15) == 0);
gcc_assert (IN_RANGE (offset, 0, 240));
@@ -918,6 +927,13 @@ i386_pe_seh_cold_init (FILE *f, const ch
fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset);
}
+ if (crtl->accesses_prior_frames)
+ {
+ offset = seh->sp_offset - alloc_offset;
+ if (offset > 0 && offset < SEH_MAX_FRAME_SIZE)
+ fprintf (f, "\t.seh_stackalloc\t" HOST_WIDE_INT_PRINT_DEC "\n", offset);
+ }
+
fputs ("\t.seh_endprologue\n", f);
}
/* PR target/84763 */
/* { dg-require-effective-target return_address } */
extern void abort (void);
void *foo (unsigned int *data, unsigned int len)
{
unsigned int local_data[128];
if (len > 128)
abort ();
for (unsigned int i = 0; i < len; i++)
local_data[i] = data[i] + data[len - 1 - i] * 2;
void *ret = __builtin_frame_address (0);
for (unsigned int i = 0; i < len; i++)
ret = ret + local_data[i] % 8;
return ret;
}