[Bug target/99234] [10/11 regression] wrong result for 1.0/3.0 with -O2 -fno-omit-frame-pointer -frounding-math

cvs-commit at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Mon Mar 1 06:59:11 GMT 2021


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99234

--- Comment #19 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Eric Botcazou <ebotcazou@gcc.gnu.org>:

https://gcc.gnu.org/g:074226d5aa86cd3de517014acfe34c7f69a2ccc7

commit r11-7439-g074226d5aa86cd3de517014acfe34c7f69a2ccc7
Author: Eric Botcazou <ebotcazou@adacore.com>
Date:   Mon Mar 1 07:53:05 2021 +0100

    Fix wrong result for 1.0/3.0 at -O2 -fno-omit-frame-pointer -frounding-math

    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 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 discrepancy between cases
    where the number of saved general regs is even and cases where it is odd.

    gcc/
            PR target/99234
            * 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.
    gcc/testsuite/
            * g++.dg/eh/seh-xmm-unwind.C: New test.


More information about the Gcc-bugs mailing list