When vectorizing the vectorization loading of the source operand, it was found
that during the processing of the half-region exchange index(such as [4,5,6,7,
0,1,2,3]). there was no direct match.  By using the method of xvperm.w +
memory loading index, it can be optimized to xvpermi.d, thereby reducing
the number of instructions.

//test.c
int a[N], b[N], c[N];

void func () {
  for (int i = 0; i < N; i += 8) {
    c[i+0] = a[i+4]; c[i+1] = a[i+5];
    c[i+2] = a[i+6]; c[i+3] = a[i+7];
    c[i+4] = a[i+0]; c[i+5] = a[i+1];
    c[i+6] = a[i+2]; c[i+7] = a[i+3];
  }
}

before asm:
        la.local        $r15,.LC0  //{4,5,6,7,0,1,2,3}
        la.local        $r12,a
        xvld            $xr0,$r15,0
        la.local        $r13,c
        la.local        $r14,a+4096
.L2:
        xvld            $xr1,$r12,0
        xvperm.w        $xr4,$xr1,$xr0
...

after asm:
        la.local        $r12,a
        la.local        $r13,c
        la.local        $r14,a+4096
.L2:
        xvld    $xr3,$r12,0
        xvpermi.d       $xr3,$xr3,78
...

gcc/ChangeLog:

        * config/loongarch/loongarch-builtins.cc (CODE_FOR_lsx_vpermi_w):
        Add icode support.
        * config/loongarch/loongarch.cc (loongarch_is_lasx_dword_perm): New
        function.
        (loongarch_is_lsx_word_perm): Dito.
        (loongarch_expand_vec_perm_const): Impement the half-zone processing
        function for a single source operation.
        * config/loongarch/lsx.md (lsx_vpermi_w): Add mode support.
        (@lsx_vpermi_w<LSX:mode>): Dito.

gcc/testsuite/ChangeLog:

        * gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-float.c: New 
test.
        * gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-int.c: New 
test.
        * gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-char.c: New 
test.
        * gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-short.c: New 
test.
---
 gcc/config/loongarch/loongarch-builtins.cc    |   1 +
 gcc/config/loongarch/loongarch.cc             |  86 ++++++++++++
 gcc/config/loongarch/lsx.md                   |  14 +-
 .../vector/lasx/vect-quad-perm-verify-float.c |  35 +++++
 .../vector/lasx/vect-quad-perm-verify-int.c   |  35 +++++
 .../vector/lsx/vect-quad-perm-verify-char.c   | 126 ++++++++++++++++++
 .../vector/lsx/vect-quad-perm-verify-short.c  |  86 ++++++++++++
 7 files changed, 376 insertions(+), 7 deletions(-)
 create mode 100644 
gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-float.c
 create mode 100644 
gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-int.c
 create mode 100644 
gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-char.c
 create mode 100644 
gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-short.c

diff --git a/gcc/config/loongarch/loongarch-builtins.cc 
b/gcc/config/loongarch/loongarch-builtins.cc
index 14bd9d24741..a165329c53d 100644
--- a/gcc/config/loongarch/loongarch-builtins.cc
+++ b/gcc/config/loongarch/loongarch-builtins.cc
@@ -380,6 +380,7 @@ AVAIL_ALL (lasx_frecipe, ISA_HAS_LASX && ISA_HAS_FRECIPE)
 #define CODE_FOR_lsx_vpcnt_h CODE_FOR_popcountv8hi2
 #define CODE_FOR_lsx_vpcnt_w CODE_FOR_popcountv4si2
 #define CODE_FOR_lsx_vpcnt_d CODE_FOR_popcountv2di2
+#define CODE_FOR_lsx_vpermi_w CODE_FOR_lsx_vpermi_wv4si
 #define CODE_FOR_lsx_vxor_v CODE_FOR_xorv16qi3
 #define CODE_FOR_lsx_vxori_b CODE_FOR_xorv16qi3
 #define CODE_FOR_lsx_vsll_b CODE_FOR_vashlv16qi3
diff --git a/gcc/config/loongarch/loongarch.cc 
b/gcc/config/loongarch/loongarch.cc
index 3001d552574..3b3cb9aa243 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -9671,6 +9671,86 @@ loongarch_is_elem_duplicate (struct expand_vec_perm_d *d)
    c) Use other instructions to process op and put correct result into target.
    */
 
+/* Check if a constant LASX permutation can be implemented as a single
+   xvpermi.d instruction.  This handles cases where all elements of each
+   result 64-bit dword come from the same source dword in the same order,
+   i.e., the permutation can be expressed as a dword-level shuffle.
+   Returns true if the pattern matches and emits the instruction.  */
+
+static bool
+loongarch_is_lasx_dword_perm (struct expand_vec_perm_d *d)
+{
+  if (!ISA_HAS_LASX)
+    return false;
+  if (GET_MODE_SIZE (d->vmode) != 32 || !d->one_vector_p)
+    return false;
+
+  unsigned int nelt = d->nelt;
+  unsigned int nelts_per_dw = nelt / 4;
+
+  for (unsigned int dw = 0; dw < 4; dw++)
+    {
+      unsigned int base = dw * nelts_per_dw;
+      unsigned int sdw = d->perm[base] / nelts_per_dw;
+      for (unsigned int k = 0; k < nelts_per_dw; k++)
+       if (d->perm[base + k] != sdw * nelts_per_dw + k)
+          return false;
+    }
+
+  if (d->testing_p)
+      return true;
+
+  unsigned int imm = 0;
+  for (unsigned int dw = 0; dw < 4; dw++)
+    {
+      unsigned int base = dw * nelts_per_dw;
+      unsigned int sdw = d->perm[base] / nelts_per_dw;
+      imm |= sdw << (dw * 2);
+    }
+
+  emit_insn (gen_lasx_xvpermi_d (d->vmode, d->target, d->op0, GEN_INT (imm)));
+  return true;
+}
+
+static bool
+loongarch_is_lsx_word_perm (struct expand_vec_perm_d *d)
+{
+  if (!ISA_HAS_LSX)
+    return false;
+  if (GET_MODE_SIZE (d->vmode) != 16 || !d->one_vector_p)
+    return false;
+
+  unsigned int nelt = d->nelt;
+  unsigned int nelts_per_dw = nelt / 4;
+
+  if (nelts_per_dw == 0 || nelts_per_dw == 1)
+      return false;
+
+  for (unsigned int dw = 0; dw < 4; dw++)
+    {
+      unsigned int base = dw * nelts_per_dw;
+      unsigned int sdw = d->perm[base] / nelts_per_dw;
+      for (unsigned int k = 0; k < nelts_per_dw; k++)
+       if (d->perm[base + k] != sdw * nelts_per_dw + k)
+          return false;
+    }
+
+  if (d->testing_p)
+    return true;
+
+  unsigned int imm = 0;
+  for (unsigned int dw = 0; dw < 4; dw++)
+    {
+      unsigned int base = dw * nelts_per_dw;
+      unsigned int sdw = d->perm[base] / nelts_per_dw;
+      imm |= sdw << (dw * 2);
+    }
+
+  emit_insn (gen_lsx_vpermi_w (d->vmode, d->target, d->op0,
+             d->op0, GEN_INT (imm)));
+  return true;
+}
+
 /* Implementation of constant vector permutation.  This function identifies
    recognized pattern of permutation selector argument, and use one or more
    instruction (s) to finish the permutation job correctly.  For unsupported
@@ -9714,6 +9794,9 @@ loongarch_expand_vec_perm_const (struct expand_vec_perm_d 
*d)
            return true;
        }
 
+      if (loongarch_is_lsx_word_perm (d))
+       return true;
+
       if (GET_MODE_SIZE (d->vmode) == 16)
        return loongarch_expand_lsx_shuffle (d);
 
@@ -9782,6 +9865,9 @@ loongarch_expand_vec_perm_const (struct expand_vec_perm_d 
*d)
          goto expand_perm_const_end;
        }
 
+      if (loongarch_is_lasx_dword_perm (d))
+         return true;
+
       if (loongarch_is_elem_duplicate (d))
        {
          if (d->testing_p)
diff --git a/gcc/config/loongarch/lsx.md b/gcc/config/loongarch/lsx.md
index 53eba3ffe6b..d1280ccd415 100644
--- a/gcc/config/loongarch/lsx.md
+++ b/gcc/config/loongarch/lsx.md
@@ -3180,16 +3180,16 @@ (define_insn "lsx_vssrarni_<lsxfmt_u>_<dlsxfmt>"
   [(set_attr "type" "simd_shift")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "lsx_vpermi_w"
-  [(set (match_operand:V4SI 0 "register_operand" "=f")
-       (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "0")
-                     (match_operand:V4SI 2 "register_operand" "f")
-                     (match_operand 3 "const_uimm8_operand" "")]
-                    UNSPEC_LSX_VPERMI))]
+(define_insn "@lsx_vpermi_w<LSX:mode>"
+  [(set (match_operand:LSX 0 "register_operand" "=f")
+       (unspec:LSX[(match_operand:LSX 1 "register_operand" "0")
+                   (match_operand:LSX 2 "register_operand" "f")
+                   (match_operand 3 "const_uimm8_operand" "")]
+                   UNSPEC_LSX_VPERMI))]
   "ISA_HAS_LSX"
   "vpermi.w\t%w0,%w2,%3"
   [(set_attr "type" "simd_bit")
-   (set_attr "mode" "V4SI")])
+   (set_attr "mode" "<MODE>")])
 
 ;; Delete one of two instructions that exactly play the same role.
 (define_peephole2
diff --git 
a/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-float.c 
b/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-float.c
new file mode 100644
index 00000000000..7c901f3ffce
--- /dev/null
+++ 
b/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-float.c
@@ -0,0 +1,35 @@
+/* { dg-do compile { target { loongarch64*-*-* } } } */
+/* { dg-options "-mabi=lp64d -Ofast -mlasx " } */
+/* { dg-final { scan-assembler-times "xvpermi.d" 12 } } */
+
+#define N 1024
+float a[N], b[N], c[N];
+
+void test_swap_halves() {
+  for (int i = 0; i < N; i += 8) {
+    c[i+0] = a[i+4]; c[i+1] = a[i+5];
+    c[i+2] = a[i+6]; c[i+3] = a[i+7];
+    c[i+4] = a[i+0]; c[i+5] = a[i+1];
+    c[i+6] = a[i+2]; c[i+7] = a[i+3];
+  }
+}
+
+void test_broadcast_low() {
+  for (int i = 0; i < N; i += 8) {
+    c[i+0] = a[i+0]; c[i+1] = a[i+1];
+    c[i+2] = a[i+2]; c[i+3] = a[i+3];
+    c[i+4] = a[i+0]; c[i+5] = a[i+1];
+    c[i+6] = a[i+2]; c[i+7] = a[i+3];
+  }
+}
+
+/* { dg-final { scan-assembler-times 
"test_broadcast_high:.*\txvpermi\\.q.*test_broadcast_high" 1 } } */
+void test_broadcast_high() {
+  for (int i = 0; i < N; i += 8) {
+    c[i+0] = a[i+4]; c[i+1] = a[i+5];
+    c[i+2] = a[i+6]; c[i+3] = a[i+7];
+    c[i+4] = a[i+4]; c[i+5] = a[i+5];
+    c[i+6] = a[i+6]; c[i+7] = a[i+7];
+  }
+}
+
diff --git 
a/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-int.c 
b/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-int.c
new file mode 100644
index 00000000000..968bb67aedc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/vector/lasx/vect-quad-perm-verify-int.c
@@ -0,0 +1,35 @@
+/* { dg-do compile { target { loongarch64*-*-* } } } */
+/* { dg-options "-mabi=lp64d -Ofast -mlasx " } */
+/* { dg-final { scan-assembler-times "xvpermi.d" 12 } } */
+
+#define N 1024
+int a[N], b[N], c[N];
+
+void test_swap_halves() {
+  for (int i = 0; i < N; i += 8) {
+    c[i+0] = a[i+4]; c[i+1] = a[i+5];
+    c[i+2] = a[i+6]; c[i+3] = a[i+7];
+    c[i+4] = a[i+0]; c[i+5] = a[i+1];
+    c[i+6] = a[i+2]; c[i+7] = a[i+3];
+  }
+}
+
+void test_broadcast_low() {
+  for (int i = 0; i < N; i += 8) {
+    c[i+0] = a[i+0]; c[i+1] = a[i+1];
+    c[i+2] = a[i+2]; c[i+3] = a[i+3];
+    c[i+4] = a[i+0]; c[i+5] = a[i+1];
+    c[i+6] = a[i+2]; c[i+7] = a[i+3];
+  }
+}
+
+/* { dg-final { scan-assembler-times 
"test_broadcast_high:.*\txvpermi\\.q.*test_broadcast_high" 1 } } */
+void test_broadcast_high() {
+  for (int i = 0; i < N; i += 8) {
+    c[i+0] = a[i+4]; c[i+1] = a[i+5];
+    c[i+2] = a[i+6]; c[i+3] = a[i+7];
+    c[i+4] = a[i+4]; c[i+5] = a[i+5];
+    c[i+6] = a[i+6]; c[i+7] = a[i+7];
+  }
+}
+
diff --git 
a/gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-char.c 
b/gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-char.c
new file mode 100644
index 00000000000..eb6e6681cbf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-char.c
@@ -0,0 +1,126 @@
+/* { dg-do compile { target { loongarch64*-*-* } } } */
+/* { dg-options "-mabi=lp64d -Ofast -mlsx " } */
+/* { dg-final { scan-assembler-times "vpermi.w" 15 } } */
+
+#define N 1024
+char a[N], b[N], c[N];
+
+void
+test_swap_halves ()
+{
+  for (int i = 0; i < N; i += 16)
+    {
+      c[i + 0] = a[i + 8];
+      c[i + 1] = a[i + 9];
+      c[i + 2] = a[i + 10];
+      c[i + 3] = a[i + 11];
+      c[i + 4] = a[i + 12];
+      c[i + 5] = a[i + 13];
+      c[i + 6] = a[i + 14];
+      c[i + 7] = a[i + 15];
+      c[i + 8] = a[i + 0];
+      c[i + 9] = a[i + 1];
+      c[i + 10] = a[i + 2];
+      c[i + 11] = a[i + 3];
+      c[i + 12] = a[i + 4];
+      c[i + 13] = a[i + 5];
+      c[i + 14] = a[i + 6];
+      c[i + 15] = a[i + 7];
+    }
+}
+
+void
+test_broadcast_low ()
+{
+  for (int i = 0; i < N; i += 16)
+    {
+      c[i + 0] = a[i + 0];
+      c[i + 1] = a[i + 1];
+      c[i + 2] = a[i + 2];
+      c[i + 3] = a[i + 3];
+      c[i + 4] = a[i + 4];
+      c[i + 5] = a[i + 5];
+      c[i + 6] = a[i + 6];
+      c[i + 7] = a[i + 7];
+      c[i + 8] = a[i + 0];
+      c[i + 9] = a[i + 1];
+      c[i + 10] = a[i + 2];
+      c[i + 11] = a[i + 3];
+      c[i + 12] = a[i + 4];
+      c[i + 13] = a[i + 5];
+      c[i + 14] = a[i + 6];
+      c[i + 15] = a[i + 7];
+    }
+}
+
+void
+test_broadcast_high ()
+{
+  for (int i = 0; i < N; i += 16)
+    {
+      c[i + 0] = a[i + 8];
+      c[i + 1] = a[i + 9];
+      c[i + 2] = a[i + 10];
+      c[i + 3] = a[i + 11];
+      c[i + 4] = a[i + 12];
+      c[i + 5] = a[i + 13];
+      c[i + 6] = a[i + 14];
+      c[i + 7] = a[i + 15];
+      c[i + 8] = a[i + 8];
+      c[i + 9] = a[i + 9];
+      c[i + 10] = a[i + 10];
+      c[i + 11] = a[i + 11];
+      c[i + 12] = a[i + 12];
+      c[i + 13] = a[i + 13];
+      c[i + 14] = a[i + 14];
+      c[i + 15] = a[i + 15];
+    }
+}
+
+void
+test_reverse_words ()
+{
+  for (int i = 0; i < N; i += 16)
+    {
+      c[i + 0] = a[i + 7];
+      c[i + 1] = a[i + 6];
+      c[i + 2] = a[i + 5];
+      c[i + 3] = a[i + 4];
+      c[i + 4] = a[i + 3];
+      c[i + 5] = a[i + 2];
+      c[i + 6] = a[i + 1];
+      c[i + 7] = a[i + 0];
+      c[i + 8] = a[i + 15];
+      c[i + 9] = a[i + 14];
+      c[i + 10] = a[i + 13];
+      c[i + 11] = a[i + 12];
+      c[i + 12] = a[i + 11];
+      c[i + 13] = a[i + 10];
+      c[i + 14] = a[i + 9];
+      c[i + 15] = a[i + 8];
+    }
+}
+
+void
+test_reverse_words1 ()
+{
+  for (int i = 0; i < N; i += 16)
+    {
+      c[i + 0] = a[i + 8];
+      c[i + 1] = a[i + 9];
+      c[i + 2] = a[i + 10];
+      c[i + 3] = a[i + 11];
+      c[i + 4] = a[i + 0];
+      c[i + 5] = a[i + 1];
+      c[i + 6] = a[i + 2];
+      c[i + 7] = a[i + 3];
+      c[i + 8] = a[i + 12];
+      c[i + 9] = a[i + 13];
+      c[i + 10] = a[i + 14];
+      c[i + 11] = a[i + 15];
+      c[i + 12] = a[i + 4];
+      c[i + 13] = a[i + 5];
+      c[i + 14] = a[i + 6];
+      c[i + 15] = a[i + 7];
+    }
+}
diff --git 
a/gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-short.c 
b/gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-short.c
new file mode 100644
index 00000000000..a9ab014339e
--- /dev/null
+++ 
b/gcc/testsuite/gcc.target/loongarch/vector/lsx/vect-quad-perm-verify-short.c
@@ -0,0 +1,86 @@
+/* { dg-do compile { target { loongarch64*-*-* } } } */
+/* { dg-options "-mabi=lp64d -Ofast -mlsx " } */
+/* { dg-final { scan-assembler-times "vpermi.w" 15 } } */
+
+#define N 1024
+short a[N], b[N], c[N];
+
+void
+test_swap_halves ()
+{
+  for (int i = 0; i < N; i += 8)
+    {
+      c[i + 0] = a[i + 4];
+      c[i + 1] = a[i + 5];
+      c[i + 2] = a[i + 6];
+      c[i + 3] = a[i + 7];
+      c[i + 4] = a[i + 0];
+      c[i + 5] = a[i + 1];
+      c[i + 6] = a[i + 2];
+      c[i + 7] = a[i + 3];
+    }
+}
+
+void
+test_broadcast_low ()
+{
+  for (int i = 0; i < N; i += 8)
+    {
+      c[i + 0] = a[i + 0];
+      c[i + 1] = a[i + 1];
+      c[i + 2] = a[i + 2];
+      c[i + 3] = a[i + 3];
+      c[i + 4] = a[i + 0];
+      c[i + 5] = a[i + 1];
+      c[i + 6] = a[i + 2];
+      c[i + 7] = a[i + 3];
+    }
+}
+
+void
+test_broadcast_high ()
+{
+  for (int i = 0; i < N; i += 8)
+    {
+      c[i + 0] = a[i + 4];
+      c[i + 1] = a[i + 5];
+      c[i + 2] = a[i + 6];
+      c[i + 3] = a[i + 7];
+      c[i + 4] = a[i + 4];
+      c[i + 5] = a[i + 5];
+      c[i + 6] = a[i + 6];
+      c[i + 7] = a[i + 7];
+    }
+}
+
+void
+test_reverse_words ()
+{
+  for (int i = 0; i < N; i += 8)
+    {
+      c[i + 0] = a[i + 3];
+      c[i + 1] = a[i + 2];
+      c[i + 2] = a[i + 1];
+      c[i + 3] = a[i + 0];
+      c[i + 4] = a[i + 7];
+      c[i + 5] = a[i + 6];
+      c[i + 6] = a[i + 5];
+      c[i + 7] = a[i + 4];
+    }
+}
+
+void
+test_reverse_words1 ()
+{
+  for (int i = 0; i < N; i += 8)
+    {
+      c[i + 0] = a[i + 0];
+      c[i + 1] = a[i + 1];
+      c[i + 2] = a[i + 4];
+      c[i + 3] = a[i + 5];
+      c[i + 4] = a[i + 2];
+      c[i + 5] = a[i + 3];
+      c[i + 6] = a[i + 6];
+      c[i + 7] = a[i + 7];
+    }
+}
-- 
2.20.1

Reply via email to