> On 28 May 2026, at 18:24, Kyrylo Tkachov <[email protected]> wrote: > > Hi all, > > PR122827 is a miscompile of 526.blender_r in SPEC2017 with > -Ofast -flto=auto -mcpu=neoverse-v2 -msve-vector-bits=128 --param > aarch64-autovec-preference=sve-only. > Bisection landed on g:b191e8bdecf (the IRA cost-model rework for PR117477), > and the > miscompile disappears with -mearly-ra=none, -fno-caller-saves, or > -fno-early-ra, all of which steer register allocation away from V8-V15. > > The bug is in shade_material_loop in shadeinput.c, where a broadcast of > a float scalar to a VNx2SF value is held in V14 across a call: > > mov z14.s, s15 ; broadcast s15 -> all 4 .s lanes of z14 > ... > bl shade_lamp_loop ; clobbers V14[127:64] > ... > fmla z20.s, p7/m, z14.s, z21.s ; reads all 4 .s lanes of z14 > > Under AAPCS64 only the low 64 bits of V8-V15 (D8-D15) are callee-saved. > The prologue dutifully saves d14/d15, but the broadcast and FMA both > touch the full Z register, and the upper half of v14 gets corrupted by > the call -- producing wrong floating-point results. > > VNx2SF has GET_MODE_SIZE == 8, so the previous part-clobber check > treated V14 as fully preserved for that mode. The mode size is > correct for the *data* (two 32-bit lanes), but the underlying SVE > instructions are not packed -- the two .s lanes live at byte offsets > 0-3 and 8-11 of the Z register (the .d-strided layout used for partial > SVE modes), so byte 8 onwards is outside the AAPCS64-preserved range. > Any SVE mode in V8-V15 across a call is therefore partially clobbered, > regardless of GET_MODE_SIZE. > > The change in g:b191e8bdecf made the cost of allocating a callee-saved > register low enough that IRA started picking V14 for these pseudos, > exposing the latent miscompile. > > Two places need fixing: > > * aarch64_hard_regno_call_part_clobbered uses GET_MODE_SIZE to decide > whether the callee-preserved low 64 bits are enough for the value. > For SVE modes, compare against BYTES_PER_SVE_VECTOR instead: any > SVE mode physically uses the full Z register. > > * early-RA classifies allocno groups into FPR_D/FPR_Q/FPR_Z by mode > bit size, and partial_fpr_clobbers then maps FPR_D to V8QImode for > the ABI check. That synthetic V8QImode hides the fact that the > pseudo is actually an SVE mode, so V8-V15 are not excluded from the > candidate set. Classify any SVE mode as FPR_Z so that > partial_fpr_clobbers uses VNx16QImode and correctly removes V8-V15. > > A new test is added in gcc.target/aarch64/sve/pr122827.c > Before the fix the execution test aborts (V14 is allocated to the broadcast > across the call, and the explicit clobber inside the callee corrupts its upper > lanes). after the fix it passes. > > Explicitly clobbering V14 with inline assembly in the test may be a bit > fragile > as it depends on RA picking V14 for the pre-call broadcast to trigger the bug > but I couldn't find a good way of generalising it without perturbing RA in > ways > that made the bug not trigger > > With this patch blender passes again and no regressions on > aarch64-none-linux-gnu bootstrap. > > Ok for trunk and eventually backports?
I’ve pushed this to trunk so it can get some wider testing. Will back port after some time of baking. Thanks, Kyrill > > Signed-off-by: Kyrylo Tkachov <[email protected]> > > gcc/ChangeLog: > > PR target/122827 > * config/aarch64/aarch64.cc (aarch64_hard_regno_call_part_clobbered): > For SVE modes use BYTES_PER_SVE_VECTOR for the per-register size > rather than GET_MODE_SIZE. > * config/aarch64/aarch64-early-ra.cc (early_ra::get_allocno_subgroup): > Classify any SVE mode as FPR_Z. > > gcc/testsuite/ChangeLog: > > PR target/122827 > * gcc.target/aarch64/sve/pr122827.c: New test. > > <0001-PR-target-122827-aarch64-Treat-SVE-modes-as-full-Z-f.patch>
