Initializing a vector with one non-zero element and zeros must
start from a zero vector and insert the element, instead of
broadcasting the element and inserting every zero.

before:
        or      $r12,$r0,$r0
        vreplgr2vr.w    $vr0,$r4
        vinsgr2vr.w     $vr0,$r12,1
        vinsgr2vr.w     $vr0,$r12,2
        vinsgr2vr.w     $vr0,$r12,3
        movfr2gr.d      $r4,$f0
        vpickve2gr.d    $r5,$vr0,1
after:
        vrepli.b        $vr0,0
        vinsgr2vr.w     $vr0,$r4,0
        movfr2gr.d      $r4,$f0
        vpickve2gr.d    $r5,$vr0,1

gcc/ChangeLog:

        * config/loongarch/loongarch.cc (loongarch_expand_vector_init):
        Optimization.

gcc/testsuite/ChangeLog:

        * gcc.target/loongarch/vector/lasx/vec-init-zero.c: New test.
        * gcc.target/loongarch/vector/lsx/vec-init-zero.c: New test.

---
 gcc/config/loongarch/loongarch.cc             | 31 +++++++++++++++++++
 .../loongarch/vector/lasx/vec-init-zero.c     | 11 +++++++
 .../loongarch/vector/lsx/vec-init-zero.c      | 11 +++++++
 3 files changed, 53 insertions(+)
 create mode 100644 
gcc/testsuite/gcc.target/loongarch/vector/lasx/vec-init-zero.c
 create mode 100644 
gcc/testsuite/gcc.target/loongarch/vector/lsx/vec-init-zero.c

diff --git a/gcc/config/loongarch/loongarch.cc 
b/gcc/config/loongarch/loongarch.cc
index bf401602394..7f65787fd40 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -10592,6 +10592,37 @@ loongarch_expand_vector_init (rtx target, rtx vals)
       gcc_unreachable ();
     }
 
+  /* Fast path for a mostly-zero initializer such as { x, 0, 0, 0 }:
+     start from a zero vector and insert the single non-zero element.
+     Otherwise we would broadcast a non-zero element and then insert each
+     zero separately, which is both longer and needs a zero in a GPR.  */
+  if ((ISA_HAS_LASX && GET_MODE_SIZE (vmode) == 32)
+      || (ISA_HAS_LSX && GET_MODE_SIZE (vmode) == 16))
+    {
+      unsigned int nz = 0, nz_index = 0;
+      rtx zero = CONST0_RTX (imode);
+
+      for (i = 0; i < nelt; i++)
+       if (!rtx_equal_p (val[i], zero))
+         {
+           nz++;
+           nz_index = i;
+         }
+
+      if (nz == 1)
+       {
+         emit_move_insn (target, CONST0_RTX (vmode));
+         op0 = force_reg (imode, val[nz_index]);
+         if (GET_MODE_SIZE (vmode) == 32)
+           emit_insn (loongarch_vec_set256 (target, op0,
+                                            GEN_INT (nz_index)));
+         else
+           emit_insn (loongarch_vec_set128 (target, op0,
+                                            GEN_INT (nz_index)));
+         return;
+       }
+    }
+
   if (ISA_HAS_LASX && GET_MODE_SIZE (vmode) == 32)
     {
       /* If all elements are the same, just do a broadcost.  */
diff --git a/gcc/testsuite/gcc.target/loongarch/vector/lasx/vec-init-zero.c 
b/gcc/testsuite/gcc.target/loongarch/vector/lasx/vec-init-zero.c
new file mode 100644
index 00000000000..24d6fdadfa7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/vector/lasx/vec-init-zero.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlasx" } */
+/* { dg-final { scan-assembler-times "xvinsgr2vr\.w" 1 } } */
+
+typedef int v8si __attribute__ ((vector_size (32)));
+
+v8si
+init_zero_lasx (int x)
+{
+  return (v8si) {0, 0, 0, 0, x, 0, 0, 0};
+}
diff --git a/gcc/testsuite/gcc.target/loongarch/vector/lsx/vec-init-zero.c 
b/gcc/testsuite/gcc.target/loongarch/vector/lsx/vec-init-zero.c
new file mode 100644
index 00000000000..ad0e567e7f0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/vector/lsx/vec-init-zero.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlsx" } */
+/* { dg-final { scan-assembler-times "vinsgr2vr\.w" 1 } } */
+
+typedef int v4si __attribute__ ((vector_size (16)));
+
+v4si
+init_zero_lsx (int x)
+{
+  return (v4si) {x, 0, 0, 0};
+}
-- 
2.55.0

Reply via email to