https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48609

--- Comment #14 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:b085ae4b49b41e146c0a6a6c16c8c588438b9528

commit r17-3637-gb085ae4b49b41e146c0a6a6c16c8c588438b9528
Author: Roger Sayle <[email protected]>
Date:   Tue Aug 25 09:02:51 2026 -0500

    PR target/48609: RTL simplifications for x86 complex arg passing.

    Very many thanks to Richard Sandiford for his inspired
    feedback/proof-of-concept that addressed the big endian flaws in
    my original patch.  His suggestion to use an RTL get_ref_base_and_offset
    is inspired, and significantly cleans up this patch.  Chapeau.

    This patch adds an RTL simplification to simplify-rtx.cc to resolve
    PR target/48609, inefficient passing of complex values on x86.

    The motivating example, for the bugzilla PR, is:

    typedef _Complex float SCtype;
    extern SCtype bar;
    void foo (SCtype x)
    {
      bar = x;
    }

    which currently with -O2 generates some spurious instructions:

    foo:    movdqa  %xmm0, %xmm1
            shufps  $85, %xmm0, %xmm0
            unpcklps        %xmm0, %xmm1
            movlps  %xmm1, bar(%rip)
            ret

    with this patch we now generate (the optimal):

    foo:    movlps  %xmm0, bar(%rip)
            ret

    The insight is that combine reports these attempts:

    Trying 7, 4 -> 14:
        7: {r111:SI#0=r105:DI 0>>0x20;clobber flags:CC;}
          REG_UNUSED flags:CC
          REG_DEAD r105:DI
        4: r108:SI=r105:DI#0
       14: r112:V2SF=vec_concat(r108:SI#0,r111:SI#0)
          REG_DEAD r111:SI
          REG_DEAD r108:SI
    Failed to match this instruction:
    (set (reg:V2SF 112 [ _7 ])
        (vec_concat:V2SF (subreg:SF (subreg:SI (reg:DI 105 [ xD.2967 ]) 0) 0)
            (subreg:SF (subreg:SI (zero_extract:DI (reg:DI 105 [ xD.2967 ])
                        (const_int 32 [0x20])
                        (const_int 32 [0x20])) 0) 0)))
    Failed to match this instruction:
    (set (reg:V2SF 112 [ _7 ])
        (vec_concat:V2SF (subreg:SF (subreg:SI (reg:DI 105 [ xD.2967 ]) 0) 0)
            (subreg:SF (subreg:SI (lshiftrt:DI (reg:DI 105 [ xD.2967 ])
                        (const_int 32 [0x20])) 0) 0)))

    Conceptually, this pattern is the equivalent of the RTL expression
    (vec_concat (subreg_lowpart (reg X)) (subreg_highpart (reg X)) which
    of course is equal to the original (reg X).  The ABI splits the
    complex argument into __real__ and __imag__ parts, which it then
    tries to recombine with vec_concat, resulting in this strange no-op.

    2026-08-25  Roger Sayle  <[email protected]>
                Richard Sandiford  <[email protected]>

    gcc/ChangeLog
            PR target/48609
            * rtl.cc (rtvec_series_p): Enhance to allow START to be a
            poly_int64 instead of just an int.
            * rtl.h (rtvec_series_p): Update function prototype.
            * rtlanal.cc (vec_series_highpart_p): Now that rtxvec_series_p
            can handle poly_int64, we handle modes that aren't constant size.
            (vec_series_lowpart_p): Likewise.
            (get_ref_base_and_offset): New function to determine the base RTX
            and byte offset of an arbitrary expression, typically a SUBREG.
            * rtlanal.h (get_ref_base_and_offset): Prototype here.
            * simplify-rtx.cc (simplify_binary_operation_1) <case VEC_CONCAT>:
            Generalize the existing (vec_concat (first_half) (second_half))
            optimization using the new get_ref_base_and_offset function.

    gcc/testsuite/ChangeLog
            PR target/48609
            * gcc.target/i386/pr48609.c: New test case.

Reply via email to