Hi,

(still trying to get some things out of the door before stage 1 closes, 
this is one of them).

I noticed that we can do better bswap when Zvbb is available while
investigating permute costing.  This patch extends shuffle_bswap_pattern
by expanding to a vrev8 instruction.  That allows us to swap more than
just HImode elements.  Before we didn't do SImode or DImode because it
required just too many generic instructions to be profitable.

Regtested on rva23u64.

Regards
 Robin

gcc/ChangeLog:

        * config/riscv/riscv-v.cc (shuffle_bswap_pattern): Use vrev8.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-1.c: New test.
        * gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-1.c: New test.
        * gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-run.c: New test.
        * gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-run.c: New test.
---
 gcc/config/riscv/riscv-v.cc                   | 44 ++++++++++++++-----
 gcc/config/riscv/vector.md                    |  2 +-
 .../riscv/rvv/autovec/unop/bswap-zvbb-1.c     | 13 ++++++
 .../rvv/autovec/unop/bswap-zvbb-perm-1.c      |  9 ++++
 .../rvv/autovec/unop/bswap-zvbb-perm-run.c    | 32 ++++++++++++++
 .../autovec/unop/bswap-zvbb-perm-template.h   | 28 ++++++++++++
 .../riscv/rvv/autovec/unop/bswap-zvbb-run.c   | 39 ++++++++++++++++
 .../rvv/autovec/unop/bswap-zvbb-template.h    | 16 +++++++
 8 files changed, 172 insertions(+), 11 deletions(-)
 create mode 100644 
gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-1.c
 create mode 100644 
gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-1.c
 create mode 100644 
gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-run.c
 create mode 100644 
gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-template.h
 create mode 100644 
gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-run.c
 create mode 100644 
gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-template.h

diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index 6ae806e01aa..8c15e469c67 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -4197,6 +4197,9 @@ shuffle_bswap_pattern (struct expand_vec_perm_d *d)
       break;
     case 32:
     case 64:
+      if ((TARGET_ZVBB || TARGET_ZVKB) && GET_MODE_UNIT_SIZE (d->vmode) == 1)
+       break;
+
       /* We will have VEC_PERM_EXPR after rtl expand when invoking
         __builtin_bswap.  It will generate about 9 instructions in
         loop as below, no matter it is bswap16, bswap32 or bswap64.
@@ -4242,29 +4245,50 @@ shuffle_bswap_pattern (struct expand_vec_perm_d *d)
   if (!known_gt (GET_MODE_NUNITS (d->vmode), 2))
     return false;
 
+  /* Build the element mode we need to use for swapping.  */
+  scalar_mode elmode;
+  if (step == 2)
+    elmode = HImode;
+  else if (step == 4)
+    elmode = SImode;
+  else if (step == 8)
+    elmode = DImode;
+  else
+    gcc_unreachable ();
+
+  machine_mode swap_mode;
+  poly_uint64 swap_mode_nunits = exact_div (GET_MODE_NUNITS (d->vmode), step);
+  if (!get_vector_mode (elmode, swap_mode_nunits).exists (&swap_mode))
+    return false;
+
   if (d->testing_p)
     return true;
 
-  machine_mode vhi_mode;
-  poly_uint64 vhi_nunits = exact_div (GET_MODE_NUNITS (d->vmode), 2);
-
-  if (!get_vector_mode (HImode, vhi_nunits).exists (&vhi_mode))
-    return false;
+  /* With Zvbb, this is just one instruction.  */
+  if (TARGET_ZVBB || TARGET_ZVKB)
+    {
+      rtx src = lowpart_subreg (swap_mode, d->op0, d->vmode);
+      rtx dest = lowpart_subreg (swap_mode, d->target, d->vmode);
+      rtx ops[] = {dest, src};
+      insn_code icode = code_for_pred_v (UNSPEC_VREV8, swap_mode);
+      emit_vlmax_insn (icode, UNARY_OP, ops);
+      return true;
+    }
 
   /* Step-1: Move op0 to src with VHI mode.  */
-  rtx src = gen_reg_rtx (vhi_mode);
-  emit_move_insn (src, gen_lowpart (vhi_mode, d->op0));
+  rtx src = gen_reg_rtx (swap_mode);
+  emit_move_insn (src, gen_lowpart (swap_mode, d->op0));
 
   /* Step-2: Shift right 8 bits to dest.  */
-  rtx dest = expand_binop (vhi_mode, lshr_optab, src, gen_int_mode (8, Pmode),
+  rtx dest = expand_binop (swap_mode, lshr_optab, src, gen_int_mode (8, Pmode),
                           NULL_RTX, 0, OPTAB_DIRECT);
 
   /* Step-3: Shift left 8 bits to src.  */
-  src = expand_binop (vhi_mode, ashl_optab, src, gen_int_mode (8, Pmode),
+  src = expand_binop (swap_mode, ashl_optab, src, gen_int_mode (8, Pmode),
                      NULL_RTX, 0, OPTAB_DIRECT);
 
   /* Step-4: Logic Or dest and src to dest.  */
-  dest = expand_binop (vhi_mode, ior_optab, dest, src,
+  dest = expand_binop (swap_mode, ior_optab, dest, src,
                       NULL_RTX, 0, OPTAB_DIRECT);
 
   /* Step-5: Move src to target with VQI mode.  */
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 12025181f17..f73dc7617ca 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -853,7 +853,7 @@ (define_attr "mode_idx" ""
                                
vfcvtitof,vfncvtitof,vfncvtftoi,vfncvtftof,vmalu,vmiota,vmidx,\
                                
vimovxv,vfmovfv,vslideup,vslidedown,vislide1up,vislide1down,vfslide1up,vfslide1down,\
                                
vgather,vcompress,vmov,vnclip,vnshift,vandn,vcpop,vclz,vctz,vrol,vror,\
-                               xt_vgmulxor,xt_vcrcfold,xt_vile,xt_vilo")
+                               
vbrev,vbrev8,vrev8,xt_vgmulxor,xt_vcrcfold,xt_vile,xt_vilo")
               (const_int 0)
 
               (eq_attr "type" "vimovvx,vfmovvf")
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-1.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-1.c
new file mode 100644
index 00000000000..217cdd38298
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile { target { ! riscv_abi_e } } } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvbb" } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model 
-fdump-tree-vect-details" } */
+
+#include "bswap-zvbb-template.h"
+
+/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 3 "vect" } } */
+/* { dg-final { scan-assembler-times {\tvrev8\.v} 3 } } */
+/* { dg-final { scan-assembler-not {\tvbrev8\.v} } } */
+/* { dg-final { scan-assembler-not {\tvrgather} } } */
+/* { dg-final { scan-assembler-not {\tvsll\.v} } } */
+/* { dg-final { scan-assembler-not {\tvsrl\.v} } } */
diff --git 
a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-1.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-1.c
new file mode 100644
index 00000000000..244e2c1027a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-1.c
@@ -0,0 +1,9 @@
+/* { dg-do compile { target { ! riscv_abi_e } } } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvbb" } */
+/* { dg-additional-options "-std=c99 -O2" } */
+
+#include "bswap-zvbb-perm-template.h"
+
+/* { dg-final { scan-assembler-times {\tvrev8\.v} 3 } } */
+/* { dg-final { scan-assembler-not {\tvbrev8\.v} } } */
diff --git 
a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-run.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-run.c
new file mode 100644
index 00000000000..066b68e340f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-run.c
@@ -0,0 +1,32 @@
+/* { dg-do run } */
+/* { dg-require-effective-target "riscv_zvbb_ok" } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvbb" } */
+/* { dg-additional-options "-std=c99 -O2" } */
+
+#include "bswap-zvbb-perm-template.h"
+
+#include <assert.h>
+
+#define CHECK(NAME, VT, ETYPE, N)                                              
\
+  {                                                                            
\
+    VT x;                                                                      
\
+    _Pragma ("GCC novector")                                                   
\
+    for (int i = 0; i < N; i++)                                                
\
+      x[i] = (ETYPE) (0x9e3779b97f4a7c15ull * (i + 1));                        
\
+    VT r = perm_##NAME (x);                                                    
\
+    _Pragma ("GCC novector")                                                   
\
+    for (int i = 0; i < N; i++)                                                
\
+      assert (r[i] == x[idx_##NAME[i]]);                                       
\
+  }
+
+int
+main ()
+{
+  CHECK (bswap16, v16qi, uint8_t, 16)
+  CHECK (bswap32, v16qi, uint8_t, 16)
+  CHECK (bswap64, v16qi, uint8_t, 16)
+  CHECK (reverse, v16qi, uint8_t, 16)
+  CHECK (swaphi, v16qi, uint8_t, 16)
+  CHECK (swappair, v8hi, uint16_t, 8)
+}
diff --git 
a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-template.h 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-template.h
new file mode 100644
index 00000000000..f626a56e848
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-perm-template.h
@@ -0,0 +1,28 @@
+#include <stdint-gcc.h>
+
+typedef uint8_t v16qi __attribute__ ((vector_size (16)));
+typedef uint16_t v8hi __attribute__ ((vector_size (16)));
+
+#define BSWAP16_QI 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14
+#define BSWAP32_QI 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
+#define BSWAP64_QI 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8
+#define REVERSE_QI 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+#define SWAPHI_QI 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13
+#define SWAPPAIR_HI 1, 0, 3, 2, 5, 4, 7, 6
+
+#define PERM(NAME, VT, IDX)                                                    
\
+  static const int idx_##NAME[] = { IDX };                                     
\
+  __attribute__ ((noipa)) VT perm_##NAME (VT x)                                
\
+  {                                                                            
\
+    return __builtin_shufflevector (x, x, IDX);                                
\
+  }
+
+#define TEST_ALL()                                                             
\
+  PERM (bswap16, v16qi, BSWAP16_QI)                                            
\
+  PERM (bswap32, v16qi, BSWAP32_QI)                                            
\
+  PERM (bswap64, v16qi, BSWAP64_QI)                                            
\
+  PERM (reverse, v16qi, REVERSE_QI)                                            
\
+  PERM (swaphi, v16qi, SWAPHI_QI)                                              
\
+  PERM (swappair, v8hi, SWAPPAIR_HI)
+
+TEST_ALL ()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-run.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-run.c
new file mode 100644
index 00000000000..e3465bfaf62
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-run.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-require-effective-target "riscv_zvbb_ok" } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvbb" } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model" } */
+
+#include "bswap-zvbb-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE, BITS)                                                        
\
+  {                                                                            
\
+    TYPE dst[SZ];                                                              
\
+    TYPE a[SZ];                                                                
\
+    for (int i = 0; i < SZ; i++)                                               
\
+      {                                                                        
\
+       dst[i] = 0;                                                            \
+       a[i] = (TYPE) (0x9e3779b97f4a7c15ull * (i + 1));                       \
+      }                                                                        
\
+    vbswap_##TYPE (dst, a, SZ);                                                
\
+    for (int i = 0; i < SZ; i++)                                               
\
+      {                                                                        
\
+       TYPE ref = 0;                                                          \
+       _Pragma ("GCC novector")                                               \
+       for (int j = 0; j < BITS / 8; j++)                                     \
+         ref |= (TYPE) ((a[i] >> (8 * j)) & 0xff) << (BITS - 8 - 8 * j);      \
+       assert (dst[i] == ref);                                                \
+      }                                                                        
\
+  }
+
+int
+main ()
+{
+  RUN (uint16_t, 16)
+  RUN (uint32_t, 32)
+  RUN (uint64_t, 64)
+}
diff --git 
a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-template.h 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-template.h
new file mode 100644
index 00000000000..3e3d848497f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/bswap-zvbb-template.h
@@ -0,0 +1,16 @@
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE, BITS)                                                  
\
+  __attribute__ ((noipa)) void vbswap_##TYPE (TYPE *restrict dst,              
\
+                                             TYPE *restrict a, int n)         \
+  {                                                                            
\
+    for (int i = 0; i < n; i++)                                                
\
+      dst[i] = __builtin_bswap##BITS (a[i]);                                   
\
+  }
+
+#define TEST_ALL()                                                             
\
+  TEST_TYPE (uint16_t, 16)                                                     
\
+  TEST_TYPE (uint32_t, 32)                                                     
\
+  TEST_TYPE (uint64_t, 64)
+
+TEST_ALL ()
-- 
2.56.0

Reply via email to