[Bug target/126619] [17 Regression] Slowdown of s116 from TSVC on x86_64 since r17-2876-gf0bd50e8317926
cvs-commit at gcc dot gnu.org
gcc-bugzilla@gcc.gnu.org
Tue Aug 25 13:55:59 GMT 2026
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126619
--- Comment #7 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Roger Sayle <sayle@gcc.gnu.org>:
https://gcc.gnu.org/g:45c9868f1b20481f4eebdcce8fffc7d61724095b
commit r17-3636-g45c9868f1b20481f4eebdcce8fffc7d61724095b
Author: Roger Sayle <roger@nextmovesoftware.com>
Date: Tue Aug 25 08:50:48 2026 -0500
PR target/126619: Improve V4SF vector initialization on x86 SSE.
This patch addresses PR target/126619, a performance regression caused by
my recent update of SSE vector initialization on x86_64. The new idiom
attempts to benefit from the implicit zero extension provided by movss
and movd, but this causes problems for (V4SF) cases were the (SFmode)
value is already in a register. Without newer extensions, GCC's approach
to zero extension (i.e. vec_init of (V4SF){ x, 0, 0, 0 }) is to perform
an interunit transfer to a general purpose integer register, and then
transfer the value back again. Inter-unit moves are expensive, especially
on older microarchitectures.
The problem is fixed in several ways. The first is to tweak register
preferencing in vec_set<mode>_0's define_insn, so that general registers
are only used if the source/destination is already an integer GPR.
This changes reload from generating (two instructions):
movd %xmm0, %eax
movd %eax, %xmm0
to instead using:
pxor %xmm1, %xmm1
movss %xmm0, %xmm1
movaps %xmm1, %xmm0
which requires 3 instructions, and 1 extra register, but requires
no inter-unit moves. This matches what clang/llvm does.
However, it's possible to do better, borrowing an idiom from
the middle-end's expansion of integer zero-extensions.
pslldq $12, %xmm0
psrldq $12, %xmm0
uses two instructions, and doesn't require an extra register.
Indeed, initializing the vector (V4SF){ 0, 0, 0, x } can be
done in a single instruction, as it doesn't require a "right"
shift.
Additionally, for cases such as (V4SF){ a, b, c, d }, where
there is no benefit from zero extension, we should continue
using GCC's original CONCAT of V2SF idiom, avoiding any overhead
of zero extension (Hongtao's suggestion in the Bugzilla PR).
Additionally, there are some additional V4SF initialization
tweaks. When loading from memory, where zero extension is
free "onevar_perm"s should construct { x, 0, 0, 0 } then
perform a shuffle using shufps, but when the source is a
register, it should construct { 0, 0, 0, x } (using the
single shift instruction described above), and perform a
modified shuffle using shufps from there.
With TARGET_SSE4_1, the first insertps can be used to clear
(initialize) all the other elements to zero, and the remaining
non-zero elements can be inserted with regular insertps.
As explained above, optimal code generation depends upon
knowing whether the source elements are in memory or in
registers. Currently this decision is made during RTL
expansion even though the final allocations/sources aren't
known until reload [CSE can convert a MEM to a REG, and
reload can spill a REG to a MEM]. Things work fine when the
tree-ssa optimizers correctly predict things well, but there
are one two cases than could still be improved (in either
combine or peephole2) where late changes are made to the
RTL.
2026-08-25 Roger Sayle <roger@nextmovesoftware.com>
Hongtao Liu <hongtao.liu@intel.com>
gcc/ChangeLog
PR target/126619
* config/i386/i386-expand.cc
(ix86_expand_vector_init_one_nonzero) <case E_V4SFmode>:
Improved initialization of one non-zero element V4SF vectors.
(ix86_expand_vector_init_v4sf): Reuse the above function
ix86_expand_vector_init_one_nonzero where possible. Various
improvements. Fall back to using (the original)
ix86_expand_vector_init_concat in the general case, when
SSE 4.1 instructions aren't available.
* config/i386/sse.md (vec_set<mode>_0): Prefer to avoid
inter-unit moves to general purpose registers in reload.
(vec_setv4sf_sse4_1): Remove asterisk to expose to i386-expand.
(sse4_1_insertps_v4sf_init): Variant of insertps that clears
all the other elements of the destination to zero.
(sse2_insertps_v4sf_3): Implementation of the above instruction
available on SSE2 by using the pslldq instruction.
gcc/testsuite/ChangeLog
PR target/126619
* gcc.target/i386/avx-init-v4sf-1.c: Update test case.
* gcc.target/i386/avx-init-v4sf-2.c: Likewise.
* gcc.target/i386/avx2-init-v4sf-1.c: Likewise.
* gcc.target/i386/sse-init-v4sf-2.c: Likewise.
* gcc.target/i386/sse-init-v4sf-3.c: Likewise.
* gcc.target/i386/sse2-init-v4sf-1.c: Likewise.
* gcc.target/i386/sse2-init-v4sf-2.c: Likewise.
* gcc.target/i386/sse4_1-init-v4sf-2.c: Likewise.
* gcc.target/i386/sse4_1-init-v4sf-3.c: Likewise.
More information about the Gcc-bugs
mailing list