As we don't have RTL support for duplicating values into partial AdvSIMD
vector modes, any expression like (vec_duplicate:V4QI (reg:QI)) is going
to be malformed.  The ICE reported in PR125538 occurred because in
r17-897-g4ddae2a94a032d we started generating such expressions when doing
a splat of the most common element at aarch64.cc:25876.

To address the problem, this patch introduces the
aarch64_gen_vec_duplicate () wrapper, which handles the case of a
sub-64-bit destination mode by duplicating the source value into 64 bits
and wrapping that into a SUBREG expression.  The alternative here would be
to add some more vec_duplicate RTL patterns, but that would lead to some
code churn in aarch64-simd.md and break a long-standing invariant for no
obvious benefit.

I've added the reduced testcase from the PR, as well as appended some
similar tests to vec_init_5.c and vec-init-23.c.

Regtested and bootstrapped on aarch64-linux-gnu.

        PR target/125538

gcc/ChangeLog:

        * config/aarch64/aarch64-protos.h (aarch64_gen_vec_duplicate):
        Declare new function.
        * config/aarch64/aarch64.cc (aarch64_gen_vec_duplicate): Define
        it.
        (aarch64_expand_vector_init_fallback): Use
        aarch64_gen_vec_duplicate () instead of gen_vec_duplicate ().

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/sve/vec_init_5.c: Add new 8/16-bit testcases.
        * gcc.target/aarch64/vec-init-23.c: Likewise.
        * gcc.target/aarch64/pr125538.c: New test.
---
 gcc/config/aarch64/aarch64-protos.h           |  1 +
 gcc/config/aarch64/aarch64.cc                 | 36 ++++++++--
 gcc/testsuite/gcc.target/aarch64/pr125538.c   | 20 ++++++
 .../gcc.target/aarch64/sve/vec_init_5.c       | 69 ++++++++++++++++++
 .../gcc.target/aarch64/vec-init-23.c          | 71 ++++++++++++++++++-
 5 files changed, 191 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/pr125538.c

diff --git a/gcc/config/aarch64/aarch64-protos.h 
b/gcc/config/aarch64/aarch64-protos.h
index 513b556398f..3e679f6d36a 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -1014,6 +1014,7 @@ rtx aarch64_mask_from_zextract_ops (rtx, rtx);
 rtx aarch64_return_addr_rtx (void);
 rtx aarch64_return_addr (int, rtx);
 rtx aarch64_simd_gen_const_vector_dup (machine_mode, HOST_WIDE_INT);
+rtx aarch64_gen_vec_duplicate (machine_mode, rtx);
 rtx aarch64_gen_shareable_zero (machine_mode);
 bool aarch64_split_simd_shift_p (rtx_insn *);
 bool aarch64_simd_mem_operand_p (rtx);
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 5a859e12b1a..4c7173c162a 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -25039,6 +25039,30 @@ aarch64_gen_shareable_zero (machine_mode mode)
   return lowpart_subreg (mode, reg, GET_MODE (reg));
 }
 
+/* Duplicate value X into a vector of type MODE.  In case MODE is a
+   sub-64-bit mode and the result isn't a const_vector, duplicate into a
+   full register and take a SUBREG of that.  */
+
+rtx
+aarch64_gen_vec_duplicate (machine_mode mode, rtx x)
+{
+  gcc_assert (VECTOR_MODE_P (mode));
+
+  if (!aarch64_advsimd_sub_dword_mode_p (mode))
+    return gen_vec_duplicate (mode, x);
+
+  if (valid_for_const_vector_p (mode, x))
+    return gen_const_vec_duplicate (mode, x);
+
+  machine_mode dup_mode = mode_for_vector (GET_MODE_INNER (mode),
+                               64 / GET_MODE_BITSIZE (GET_MODE_INNER (mode)))
+                         .require ();
+
+  rtx reg = gen_reg_rtx (dup_mode);
+  aarch64_emit_move (reg, gen_rtx_VEC_DUPLICATE (dup_mode, x));
+  return lowpart_subreg (mode, reg, dup_mode);
+}
+
 /* INSN is some form of extension or shift that can be split into a
    permutation involving a shared zero.  Return true if we should
    perform such a split.
@@ -25699,7 +25723,7 @@ aarch64_expand_vector_init_fallback (rtx target, rtx 
vals)
                               2 * GET_MODE_SIZE (narrow_mode)));
       if (rtx_equal_p (v0, v1))
        aarch64_emit_move (target,
-                         gen_vec_duplicate (mode,
+                         aarch64_gen_vec_duplicate (mode,
                                             force_reg (narrow_mode, v0)));
       else
        emit_insn (gen_aarch64_vec_concat (narrow_mode, target,
@@ -25733,7 +25757,7 @@ aarch64_expand_vector_init_fallback (rtx target, rtx 
vals)
   if (all_same)
     {
       rtx x = force_reg (inner_mode, v0);
-      aarch64_emit_move (target, gen_vec_duplicate (mode, x));
+      aarch64_emit_move (target, aarch64_gen_vec_duplicate (mode, x));
       return;
     }
 
@@ -25769,7 +25793,8 @@ aarch64_expand_vector_init_fallback (rtx target, rtx 
vals)
              RTVEC_ELT (new_vals, i) = XVECEXP (vals, 0, i);
            aarch64_expand_vector_init (new_target,
                                        gen_rtx_PARALLEL (subv_mode, new_vals));
-           aarch64_emit_move (target, gen_vec_duplicate (mode, new_target));
+           aarch64_emit_move (target,
+                              aarch64_gen_vec_duplicate (mode, new_target));
            return;
          }
     }
@@ -25862,7 +25887,8 @@ aarch64_expand_vector_init_fallback (rtx target, rtx 
vals)
          if (const_elem)
            {
              maxelement = const_elem_pos;
-             aarch64_emit_move (target, gen_vec_duplicate (mode, const_elem));
+             aarch64_emit_move (target,
+                                aarch64_gen_vec_duplicate (mode, const_elem));
            }
          else
            {
@@ -25873,7 +25899,7 @@ aarch64_expand_vector_init_fallback (rtx target, rtx 
vals)
       else
        {
          rtx x = force_reg (inner_mode, XVECEXP (vals, 0, maxelement));
-         aarch64_emit_move (target, gen_vec_duplicate (mode, x));
+         aarch64_emit_move (target, aarch64_gen_vec_duplicate (mode, x));
        }
 
       /* Insert the rest.  */
diff --git a/gcc/testsuite/gcc.target/aarch64/pr125538.c 
b/gcc/testsuite/gcc.target/aarch64/pr125538.c
new file mode 100644
index 00000000000..f0cdcd58dfb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr125538.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv9.5-a" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+#define vect16 __attribute__((vector_size(16)))
+
+vect16 char fff(char _292, char _145, char _231)
+{
+    return (vect16 char) {_292, _145, _145, _231, _292, _145, _145, _231, 
_292, _145, _145, _231, _292, _145, _145, _231};
+}
+
+/*
+** fff:
+**     bfi     w0, w1, 8, 8
+**     bfi     w1, w2, 8, 8
+**     dup     v31\.4h, w0
+**     dup     v0\.4h, w1
+**     zip1    v0\.16b, v31\.16b, v0\.16b
+**     ret
+*/
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vec_init_5.c 
b/gcc/testsuite/gcc.target/aarch64/sve/vec_init_5.c
index 99e04aac265..112a0eafc7a 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/vec_init_5.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/vec_init_5.c
@@ -152,6 +152,27 @@
 **     ret
 */
 
+/*
+** test_int8_14:
+**     bfi     w0, w1, 8, 8
+**     bfi     w1, w2, 8, 8
+**     dup     v31\.4h, w0
+**     dup     v30\.4h, w1
+**     zip1    v31\.16b, v31\.16b, v30\.16b
+**     dup     z0\.q, z31.q\[0\]
+**     ret
+*/
+
+/*
+** test_int8_15:
+**     bfi     w0, w2, 8, 8
+**     dup     v30\.8b, w1
+**     dup     v31\.4h, w0
+**     zip1    v31\.16b, v31\.16b, v30\.16b
+**     dup     z0\.q, z31\.q\[0\]
+**     ret
+*/
+
 /*
 ** test_float16_1:
 **     fcvt    h0, s0
@@ -236,6 +257,33 @@
 **     ret
 */
 
+/*
+** test_float16_9:
+**     fcvt    h1, s1
+**     fcvt    h2, s2
+**     fcvt    h0, s0
+**     uzp1    v0\.4h, v0\.4h, v1\.4h
+**     uzp1    v1\.4h, v1\.4h, v2\.4h
+**     dup     v0\.2s, v0\.s\[0\]
+**     dup     v1\.2s, v1\.s\[0\]
+**     zip1    v0\.8h, v0\.8h, v1\.8h
+**     dup     z0\.q, z0.q\[0\]
+**     ret
+*/
+
+/*
+** test_float16_10:
+**     fcvt    h2, s2
+**     fcvt    h0, s0
+**     fcvt    h1, s1
+**     uzp1    v0\.4h, v0\.4h, v2\.4h
+**     dup     v1\.4h, v1\.h\[0\]
+**     dup     v0\.2s, v0\.s\[0\]
+**     zip1    v0\.8h, v0\.8h, v1\.8h
+**     dup     z0\.q, z0.q\[0\]
+**     ret
+*/
+
 /*
 ** test_int16_1:
 **     mov     z0\.h, w0
@@ -310,6 +358,27 @@
 **     ret
 */
 
+/*
+** test_int16_9:
+**     bfi     w0, w1, 16, 16
+**     bfi     w1, w2, 16, 16
+**     dup     v31\.2s, w0
+**     dup     v30\.2s, w1
+**     zip1    v31\.8h, v31\.8h, v30\.8h
+**     dup     z0\.q, z31\.q\[0\]
+**     ret
+*/
+
+/*
+** test_int16_10:
+**     bfi     w0, w2, 16, 16
+**     dup     v30\.4h, w1
+**     dup     v31\.2s, w0
+**     zip1    v31\.8h, v31\.8h, v30\.8h
+**     dup     z0\.q, z31\.q\[0\]
+**     ret
+*/
+
 /*
 ** test_float32_1:
 **     mov     z0\.s, s0
diff --git a/gcc/testsuite/gcc.target/aarch64/vec-init-23.c 
b/gcc/testsuite/gcc.target/aarch64/vec-init-23.c
index 8c154f3680d..4721b068366 100644
--- a/gcc/testsuite/gcc.target/aarch64/vec-init-23.c
+++ b/gcc/testsuite/gcc.target/aarch64/vec-init-23.c
@@ -41,7 +41,11 @@
     TESTCASE (TYPE, ETYPE, T, 8, 12, x16, x0, x1, 0, 1, x2, x3, 2, 3,\
                               x0, x1, 0, 1, x2, x3, 2, 3)\
     TESTCASE (TYPE, ETYPE, T, 8, 13, x16, 0, 1, x0, x1, 2, 3, x2, x3,\
-                              0, 1, x0, x1, 2, 3, x2, x3)
+                              0, 1, x0, x1, 2, 3, x2, x3) \
+    TESTCASE (TYPE, ETYPE, T, 8, 14, x16, x0, x1, x1, x2, x0, x1, x1, x2,\
+                              x0, x1, x1, x2, x0, x1, x1, x2) \
+    TESTCASE (TYPE, ETYPE, T, 8, 15, x16, x0, x1, x2, x1, x0, x1, x2, x1,\
+                              x0, x1, x2, x1, x0, x1, x2, x1)
 
 #define TEST_16(TYPE, ETYPE, T)\
     TESTCASE (TYPE, ETYPE, T, 16, 1, x8, x0, x0, x0, x0, x0, x0, x0, x0)\
@@ -52,6 +56,8 @@
     TESTCASE (TYPE, ETYPE, T, 16, 6, x8, x0, x1, 0, 1, x0, x1, 0, 1)\
     TESTCASE (TYPE, ETYPE, T, 16, 7, x8, 0, 1, x0, x1, 0, 1, x0, x1)\
     TESTCASE (TYPE, ETYPE, T, 16, 8, x8, 0, x0, 1, x1, 0, x0, 1, x1)\
+    TESTCASE (TYPE, ETYPE, T, 16, 9, x8, x0, x1, x1, x2, x0, x1, x1, x2)\
+    TESTCASE (TYPE, ETYPE, T, 16, 10, x8, x0, x1, x2, x1, x0, x1, x2, x1)
 
 #define TEST_32(TYPE, ETYPE, T)\
     TESTCASE (TYPE, ETYPE, T, 32, 1, x4, x0, x0, x0, x0)\
@@ -205,6 +211,25 @@ TEST_64(int, int64_t, s)
 **     ret
 */
 
+/*
+** test_int8_14:
+**     bfi     w0, w1, 8, 8
+**     bfi     w1, w2, 8, 8
+**     dup     v31\.4h, w0
+**     dup     v0\.4h, w1
+**     zip1    v0\.16b, v31\.16b, v0\.16b
+**     ret
+*/
+
+/*
+** test_int8_15:
+**     bfi     w0, w2, 8, 8
+**     dup     v0.8b, w1
+**     dup     v31.4h, w0
+**     zip1    v0.16b, v31.16b, v0.16b
+**     ret
+*/
+
 /*
 ** test_float16_1:
 **     fcvt    h0, s0
@@ -286,6 +311,31 @@ TEST_64(int, int64_t, s)
 **     ret
 */
 
+/*
+** test_float16_9:
+**     fcvt    h1, s1
+**     fcvt    h2, s2
+**     fcvt    h0, s0
+**     uzp1    v0\.4h, v0\.4h, v1\.4h
+**     uzp1    v1\.4h, v1\.4h, v2\.4h
+**     dup     v0\.2s, v0\.s\[0\]
+**     dup     v1\.2s, v1\.s\[0\]
+**     zip1    v0\.8h, v0\.8h, v1\.8h
+**     ret
+*/
+
+/*
+** test_float16_10:
+**     fcvt    h2, s2
+**     fcvt    h0, s0
+**     fcvt    h1, s1
+**     uzp1    v0\.4h, v0\.4h, v2\.4h
+**     dup     v1\.4h, v1\.h\[0\]
+**     dup     v0\.2s, v0\.s\[0\]
+**     zip1    v0\.8h, v0\.8h, v1\.8h
+**     ret
+*/
+
 /*
 ** test_int16_1:
 **     dup     v0\.8h, w0
@@ -356,6 +406,25 @@ TEST_64(int, int64_t, s)
 **     ret
 */
 
+/*
+** test_int16_9:
+**     bfi     w0, w1, 16, 16
+**     bfi     w1, w2, 16, 16
+**     dup     v31\.2s, w0
+**     dup     v0\.2s, w1
+**     zip1    v0\.8h, v31\.8h, v0\.8h
+**     ret
+*/
+
+/*
+** test_int16_10:
+**     bfi     w0, w2, 16, 16
+**     dup     v0\.4h, w1
+**     dup     v31\.2s, w0
+**     zip1    v0\.8h, v31\.8h, v0\.8h
+**     ret
+*/
+
 /*
 ** test_float32_1:
 **     dup     v0\.4s, v0\.s\[0\]
-- 
2.43.0

Reply via email to