https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128527
Uroš Bizjak <ubizjak at gmail dot com> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |hjl at gcc dot gnu.org
Ever confirmed|0 |1
Last reconfirmed| |2026-11-09
Target Milestone|--- |15.4
Status|UNCONFIRMED |NEW
--- Comment #1 from Uroš Bizjak <ubizjak at gmail dot com> ---
Confirmed. The ICE is in the wrapped body f.strub.0, not in f.
The assert at i386.cc:9056 is the one in the stack_realign_finalized
early-exit path of ix86_finalize_stack_frame_flags:
if (crtl->stack_realign_finalized)
{
gcc_assert (crtl->stack_realign_needed == stack_realign);
return;
}
The call from ix86_expand_prologue is the one that set
crtl->stack_realign_needed to true. On entry to that call
crtl->stack_realign_needed was false and all crtl alignment fields were 128,
and none of them were modified, so the local stack_alignment must have been
raised to 256 inside ix86_find_max_used_stack_alignment.
The only insn with A256 is:
(insn 22 20 59 5 (set (mem:V4SI (reg:DI 0 ax [orig:102 ivtmp.15 ]) [1 MEM
<vector(4) int> [(int *)_3]+0 S16 A256])
(reg:V4SI 22 xmm2 [114])) "f.c":5:10 {movv4si_internal}
This is the vectorized store to the global array a, which is legitimately
32-byte aligned. It has nothing to do with the stack.
The relevant part of the pro_and_epilogue input (cmpelim dump):
bb 2:
(insn 61 3 9 2 (set (reg/f:DI 0 ax [108])
(plus:DI (reg/f:DI 7 sp)
(const_int -128 [0xffffffffffffff80]))) "f.c":2:6 {*leadi}
(insn 10 ... (set (reg:CC 17 flags)
(compare:CC (reg/f:DI 0 ax [108])
(mem/f/c:DI (reg/f:DI 5 di [orig:130 .strub.watermark_ptr ]) ...
bb 3:
(insn 12 ... (set (mem/f:DI (reg/f:DI 5 di [orig:130 .strub.watermark_ptr ])
...
(reg/f:DI 0 ax [108]))
bb 4:
(insn 14 47 15 4 (set (reg:DI 0 ax [orig:102 ivtmp.15 ])
(symbol_ref:DI ("a") ...
Insn 61 is the strub watermark computation, and the only stack-derived
definition in the function (the only non-artificial use of sp/bp). It is used
only by insns 10 and 12, after which that value of ax is dead (ax is not live
out of bb3 and not live into bb4). Insn 14 then defines ax from a symbol_ref,
and the loop uses ax as the induction pointer into a. These are two unrelated
values that happen to share
the hard register ax after RA.
The stack alignment scan tracks hard registers, not values. Since insn 61 uses
sp, ax is added to the set of registers that may hold a stack address, and then
every MEM addressed through ax is treated as a stack access, including insn 22.
This yields stack_alignment = 256 and stack_realign = 1 in the prologue call.
The epilogue call recomputes stack_realign from crtl, which still says 128, so
it computes 0 and the assert fires.
The assert is doing its job: a genuine stack access with 256-bit alignment
would already be reflected in crtl->max_used_stack_slot_alignment or
crtl->stack_alignment_needed, so a scan result that disagrees with crtl means
the scan is wrong.
This is the same class of problem as PR118936 (where the scan also accounted
for accesses that are not stack accesses), and a fix at the level of the
destination register class / MEM source filter cannot handle it. The scan needs
to follow definitions rather than hard registers, e.g. by walking DF def-use
chains from the stack-derived defs (insn 61 here) and ignoring uses of the same
hard register that
are reached only from other defs.
Any testcase that reuses a call-clobbered register first for a sp-derived value
and then as a pointer to an over-aligned global should trigger this; strub just
provides the sp-derived watermark computation at function entry.
CC author.