]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: Implement even-odd shuffles with vnsrl
authorBohan Lei <garthlei@linux.alibaba.com>
Wed, 15 Apr 2026 07:42:20 +0000 (15:42 +0800)
committerBohan Lei <garthlei@linux.alibaba.com>
Fri, 8 May 2026 07:24:46 +0000 (15:24 +0800)
This patch tries to implement some even-odd shuffles with vnsrl instead
of vcompress, which is inspired by the current behavior of LLVM.  Since
vcompress is slower than vnsrl on many implementations, and that
vcompress needs a mask load, using vnsrl seems to be more desirable.

gcc/ChangeLog:

* config/riscv/riscv-v.cc (shuffle_even_odd_patterns): Use vnsrl
when possible.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/rvv/autovec/vls-vlmax/shuffle-evenodd.c:
Match vnsrl patterns.

gcc/config/riscv/riscv-v.cc
gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/shuffle-evenodd.c

index eabc792f8b7d7c1d93b694cf8259bc49e9f9778d..3b9f685e7708b2574ec20b1c41b70bf1f341c7f5 100644 (file)
@@ -4052,8 +4052,9 @@ shuffle_interleave_patterns (struct expand_vec_perm_d *d)
 }
 
 
-/* Recognize even/odd patterns like [0 2 4 6].  We use two compress
-   and one slideup.  */
+/* Recognize even/odd patterns like [0 2 4 6].  We try to use two narrow shifts
+   and one slideup when possible.  Otherwise, we use two compress and one
+   slideup.  */
 
 static bool
 shuffle_even_odd_patterns (struct expand_vec_perm_d *d)
@@ -4087,6 +4088,41 @@ shuffle_even_odd_patterns (struct expand_vec_perm_d *d)
   if (d->testing_p)
     return true;
 
+  /* When the element width is smaller than the greatest ELEN, we can use two
+     vnsrl instructions, each extracting the even/odd elements of one source,
+     and a vslideup instruction to merge them into one vector.
+
+     PR target/124996: VLS mode subregs larger than what
+     riscv_regmode_natural_size allows cause a memory roundtrip.  Therefore, for
+     now, we only do this when the mode size is no greater than the natural size
+     of the register.  Once this is fixed, the condition should be replaced by
+     the ELEN condition.  */
+  if (known_le (GET_MODE_SIZE (vmode), riscv_regmode_natural_size (vmode)))
+    {
+      unsigned int elen = GET_MODE_BITSIZE (GET_MODE_INNER (vmode));
+      unsigned int elen2x = elen * 2;
+      scalar_int_mode smode_elen2x = int_mode_for_size (elen2x, 0).require ();
+      scalar_int_mode smode = int_mode_for_size (elen, 0).require ();
+      machine_mode vmode_elen2x
+       = get_vector_mode (smode_elen2x, vlen / 2).require ();
+      machine_mode vmode_half = get_vector_mode (smode, vlen / 2).require ();
+      unsigned int shift_amt = even ? 0 : elen;
+      insn_code icode = code_for_pred_narrow_scalar (LSHIFTRT, vmode_elen2x);
+      rtx tmp = gen_reg_rtx (vmode);
+      rtx ops_shift1[]
+       = {gen_lowpart (vmode_half, d->target),
+          gen_lowpart (vmode_elen2x, d->op0), gen_int_mode (shift_amt, Pmode)};
+      rtx ops_shift2[]
+       = {gen_lowpart (vmode_half, tmp), gen_lowpart (vmode_elen2x, d->op1),
+          gen_int_mode (shift_amt, Pmode)};
+      emit_vlmax_insn (icode, BINARY_OP, ops_shift1);
+      emit_vlmax_insn (icode, BINARY_OP, ops_shift2);
+      rtx ops[] = {d->target, d->target, tmp, gen_int_mode (vlen / 2, Pmode)};
+      icode = code_for_pred_slide (UNSPEC_VSLIDEUP, vmode);
+      emit_vlmax_insn (icode, SLIDEUP_OP_MERGE, ops);
+      return true;
+    }
+
   machine_mode mask_mode = get_mask_mode (vmode);
   rvv_builder builder (mask_mode, vlen, 1);
   int bit = even ? 0 : 1;
index 6db4c5ab3862bdaa2ea938afad6d6567b20cd108..ba1131b1f16689c494e8c1c8bf81e10b053943ec 100644 (file)
@@ -65,4 +65,5 @@ TEST_ALL (PERMUTE1)
 TEST_ALL (PERMUTE2)
 
 /* { dg-final { scan-assembler-times "vslideup" 48 } } */
-/* { dg-final { scan-assembler-times "vcompress" 96 } } */
+/* { dg-final { scan-assembler-times "vcompress" 84 } } */
+/* { dg-final { scan-assembler-times "vnsrl" 12 } } */