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;
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);
: (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));
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);
}
--- /dev/null
+/* 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;
+}