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 <ebotca...@gcc.gnu.org>: https://gcc.gnu.org/g:074226d5aa86cd3de517014acfe34c7f69a2ccc7 commit r11-7439-g074226d5aa86cd3de517014acfe34c7f69a2ccc7 Author: Eric Botcazou <ebotca...@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.