aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2021-04-19 10:13:36 +0200
committerEric Botcazou <ebotcazou@adacore.com>2021-04-19 10:19:13 +0200
commit0bb37e80bb786e11cb7aa2d23b7d68bb0357fc15 (patch)
treeda29c545d6548ccf4e631d75c3c5c9035bce6e7c
parentd64720a07f611c55e8c815c775a852d650a2e738 (diff)
downloadgcc-0bb37e80bb786e11cb7aa2d23b7d68bb0357fc15.zip
gcc-0bb37e80bb786e11cb7aa2d23b7d68bb0357fc15.tar.gz
gcc-0bb37e80bb786e11cb7aa2d23b7d68bb0357fc15.tar.bz2
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.
-rw-r--r--gcc/config/i386/winnt.c16
-rw-r--r--gcc/testsuite/gnat.dg/opt92.adb38
2 files changed, 47 insertions, 7 deletions
diff --git a/gcc/config/i386/winnt.c b/gcc/config/i386/winnt.c
index cc12196..b66263a 100644
--- a/gcc/config/i386/winnt.c
+++ b/gcc/config/i386/winnt.c
@@ -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)
diff --git a/gcc/testsuite/gnat.dg/opt92.adb b/gcc/testsuite/gnat.dg/opt92.adb
new file mode 100644
index 0000000..f6eb6a0
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt92.adb
@@ -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;