On Wed, Oct 07, 2026 at 05:08:11PM +0530, Surya Kumari Jangala wrote:
> Hi,
> 
> On 06/10/26 3:04 AM, Kishan Parmar wrote:
> > Hello All,
> > 
> > Changes from v1:
> >     - Dropped pr123055.c testcase from previsous patch. The
> >       existing pr116030.c already carries scan-assembler-not
> >       "stxvd2x" assertion that matches the regression, making a
> >       separate pr123055.c redundant.
> > 
> > Below patch is regtested and bootstrapped on power64le-linux-gnu.
> > 
> > Thank You,
> > Kishan
> > 
> > PR123055 reports a regression on power little-endian systems,
> > where gcc.target/powerpc/pr116030.c began emitting stxvd2x starting
> > from r16-5947-ga6c50ec2c6ebcb.
> > 
> > Commit r16-5947 introduced -ffuse-ops-with-volatile-access (enabled by
> > default), which relaxes general_operand to accept volatile memory
> > references.  As a side effect, the vsx_stxvd2x4_le_const_<mode> pattern
> > whose destination was the "memory_operand" predicate started
> > matching aligned volatile destinations such as the 16-byte-aligned
> > volatile union U128 in pr116030.c.
> 
> Why is it incorrect if the vsx_stxvd2x4_le_const_<mode> pattern starts
> matching now?
> 
> vsx_stxvd2x4_le_const_<mode> ends up generating stxvd2x but stxvd2x
> is not worse than stvx. stxvd2x could require a swap instruction to get 
> the correct element order, but in vsx_stxvd2x4_le_const_<mode>, we ensure
> that operand 1 is a splat constant (a vector constant with a duplicated 
> element value).
> So we don't require a swap instruction.
> 
> The fix to PR123055 would be to just modify the failing testcase.

Let me try to give a context for what is going on.

In the original Altivec additions to the PowerPC architure for the G5
and later power6, there was a separate Altivec register bank with 32
128-bit vector registers.  The Altivec load vector instruction (LVX)
and store vector instruction (STVX) that was defined for either endian
setup and it would swap bytes on a little endian system.

However LVX and STVX have a serious flaw in that these instructions
would ignore the bottom 4 bits of the address.  If you know the address
is aligned properly you could use these instructions, but you couldn't
use these instructions if the address was potentially unaligned.

When power7 came out with the new VSX instruction set, the VSX register
set included both the traditional floating point registers (VSX
registers 0..31) and Altivec registers (VSX registers 32..63) as a
combined register set.  However the initial VSX instruction set did not
do the byte swapping on the entire 128 bits for the VSX load register
instructions (LXVD2X and LXVW4X) and VSX store register instructions
(STXVD2X and STXW4K).  At the time the power7 came out, it was only
used on big endian systems.  LXVD2K/STXVD2K would swap the bytes within
each 64-bit half of the register, and LXVW4K/STXVW4K would swap the
bytes within each of the 4 32-bit elements in the register.

After the power8 was designed, it was decided to switch the Linux
operating system from big endian to little endian and restrict the base
processor for little endian Linux to be the power8.

Given that the vector load/store instructions used in the power7 and
power8 did not properly swap all 16 bytes (128 bits), the compiler had
to do a LXVD2K instruction followed by a XXPERMDI instruction to
properly swap all of the bytes (i.w. LXVD2K would swap the 8 bytes in
each 64-bit segment, and then XXPERMDI would swap the two 64-bit
elements).  Similarly before the vector store could be done, the
compiler would have to generate a XXPERMDI instruction to swap the 2
64-bit elements before the STXVD2K would be done.

GCC added a pass controlled by the -moptimize-swaps option that would
detect when it was safe to omit the XXPERMI swaps.  I.e. if the code
was doing 2 loads, and add, and a store, you could eliminate the
XXPERMDI's since the add instruction care that the individual elements
were out of order.  I.e. without -moptimize-swaps the code:

        void foo (vector float *p, vector float *q, vector float *r)
        {
          *p = *q + *r;
        }

would generate:

        rldicr 4,4,0,59
        rldicr 5,5,0,59
        lxvd2x 0,0,4
        lxvd2x 12,0,5
        xxpermdi 0,0,0,2
        xxpermdi 12,12,12,2
        xvaddsp 0,0,12
        xxpermdi 0,0,0,2
        stxvd2x 0,0,3

and with -moptimize-swaps, it would generate:

        lxvd2x 0,0,4
        lxvd2x 12,0,5
        xvaddsp 0,0,12
        stxvd2x 0,0,3

When the power9 came out, new vector load instructions (LXV and LXVX)
and new vector store instructions (STXV and STXVX) were added that
properly byte swapped all 16 bytes.  Thus the optimize-swap pass was
disabled.

As noted, the special case where a vector constant that is duplicated
(splat'ed), you don't have to do the element swapping.

-- 
Michael Meissner, IBM
PO Box 98, Ayer, Massachusetts, USA, 01432
email: [email protected]

Reply via email to