On Fri, Feb 26, 2021 at 5:14 PM Eric Botcazou <botca...@adacore.com> wrote:
>
> Hi,
>
> this wrong-code PR for the C++ compiler on x86-64/Windows is a regression
> in GCC 9 and later, but the underlying issue has probably been there since
> SEH was implemented and is exposed by this comment in config/i386/winnt.c:
>
>   /* SEH records saves relative to the "current" stack pointer, whether
>      or not there's a frame pointer in place.  This tracks the current
>      stack pointer offset from the CFA.  */
>   HOST_WIDE_INT sp_offset;
>
> That's not what the (current) Microsoft documentation says; instead it says:
>
>   /* SEH records offsets relative to the lowest address of the fixed stack
>      allocation.  If there is no frame pointer, these offsets are from the
>      stack pointer; if there is a frame pointer, these offsets are from the
>      value of the stack pointer when the frame pointer was established, i.e.
>      the frame pointer minus the offset in the .seh_setframe directive.
>
> That's why the implementation is correct only under the condition that the
> frame pointer be established *after* the fixed stack allocation; as a matter
> of fact, that's clearly the model underpinning SEH, but is the opposite of
> what is done e.g. on Linux.
>
> However the issue is mostly papered over in practice because:
>
>   1. SEH forces use_fast_prologue_epilogue to false, which in turns forces
> save_regs_using_mov to false, so the general regs are always pushed when they
> need to be saved, which eliminates the offset computation for them.
>
>   2. As soon as a frame is larger than 240 bytes, the frame pointer is fixed
> arbitrarily to 128 bytes above the stack pointer, which of course requires
> that it be established after the fixed stack allocation.
>
> So you need a very small frame clobbering one of the call-saved XMM registers
> in order to generate wrong SEH unwind info.
>
> The attached fix makes sure that the frame pointer is always established after
> the fixed stack allocation by pointing it at or below the lowest used register
> save area, i.e. the SSE save area, and removing the special early saves in the
> prologue; the end result is a uniform prologue sequence for SEH whatever the
> frame size.  And it avoids a weird discrepancy between cases where the number
> of saved general regs is even and cases where it is odd.
>
> Tested on x86_64-w64-mingw32, OK for mainline, 10 and 9 branches?
>
>
> 2021-02-26 Eric Botcazou  <ebotca...@adacore.com>
>
>         PR target/99264
>         * config/i386/i386.c (ix86_compute_frame_layout): For a SEH target,
>         point the hard frame pointer to the SSE register save area instead
>         of the general register save area.  Perform only minimal adjustment
>         for small frames if it is initially not correctly aligned.
>         (ix86_expand_prologue): Remove early saves for a SEH target.
>         * config/i386/winnt.c (struct seh_frame_state): Document constraint.
>
>
> 2021-02-26 Eric Botcazou  <ebotca...@adacore.com>
>
>         * g++.dg/eh/seh-xmm-unwind.C: New test.

LGTM.

Thanks,
Uros.

> --
> Eric Botcazou

Reply via email to