Fix another -freorder-blocks-and-partition glitch with Windows SEH

Since GCC 8, the -freorder-blocks-and-partition pass can split a function
into hot and cold parts, thus generating 2 FDEs for a single function in
DWARF for exception purposes and doing an equivalent trick for Windows SEH.

Now the Windows system unwinder does not support arbitrarily large frames
and there is even a hard limit on the encoding of the CFI, which changes
the stack allocation strategy when it is topped and which must be reflected
everywhere.

gcc/
	* config/i386/winnt.c (i386_pe_seh_cold_init): Properly deal with
	frames larger than the SEH maximum frame size.
gcc/testsuite/
	* gnat.dg/opt92.adb: New test.
This commit is contained in:
Eric Botcazou 2021-04-19 10:13:36 +02:00
parent d64720a07f
commit 0bb37e80bb
2 changed files with 47 additions and 7 deletions

View file

@ -921,15 +921,17 @@ i386_pe_seh_cold_init (FILE *f, const char *name)
/* 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
is an exception if the function overflows the SEH maximum frame size
or accesses prior frames so, in this case, we need to pre-allocate a
small chunk of stack before setting it. */
offset = seh->sp_offset - INCOMING_FRAME_SP_OFFSET;
if (offset < SEH_MAX_FRAME_SIZE && !crtl->accesses_prior_frames)
alloc_offset = seh->sp_offset;
else
alloc_offset = MIN (seh->cfa_offset + 240, seh->sp_offset);
offset = alloc_offset - INCOMING_FRAME_SP_OFFSET;
if (offset > 0 && offset < SEH_MAX_FRAME_SIZE)
if (offset > 0)
fprintf (f, "\t.seh_stackalloc\t" HOST_WIDE_INT_PRINT_DEC "\n", offset);
for (int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
@ -958,7 +960,7 @@ i386_pe_seh_cold_init (FILE *f, const char *name)
fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset);
}
if (crtl->accesses_prior_frames)
if (alloc_offset != seh->sp_offset)
{
offset = seh->sp_offset - alloc_offset;
if (offset > 0 && offset < SEH_MAX_FRAME_SIZE)

View file

@ -0,0 +1,38 @@
-- { dg-do compile { target { lp64 || llp64 } } }
-- { dg-options "-O2 -gnatws" }
procedure Main is
subtype Int64 is Long_Long_Integer;
type Arr is array (Int64 range <>) of Boolean;
Pow : constant := 10;
procedure Compute (B : in out Arr) is
Factor : Int64 := 3;
Num : Int64;
begin
while Factor <= 10 ** (Pow / 2) loop
Num := Factor;
while Num < 10 ** Pow loop
if B (Num) then
Factor := Num;
exit;
end if;
Num := Num + 2;
end loop;
Num := Factor * Factor;
while Num < 10 ** Pow loop
B (Num) := False;
Num := Num + Factor * 2;
end loop;
Factor := Factor + 2;
end loop;
end;
B : Arr (1 .. 10 ** Pow) := (others => True);
begin
Compute (B);
end;