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 <[email protected]>: https://gcc.gnu.org/g:45c9868f1b20481f4eebdcce8fffc7d61724095b commit r17-3636-g45c9868f1b20481f4eebdcce8fffc7d61724095b Author: Roger Sayle <[email protected]> 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 <[email protected]> Hongtao Liu <[email protected]> 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.
