https://gcc.gnu.org/g:47f2a222ceda5f9834e0840a14cc6155f7d15190
commit r17-401-g47f2a222ceda5f9834e0840a14cc6155f7d15190 Author: Bohan Lei <[email protected]> Date: Wed Apr 15 15:42:20 2026 +0800 RISC-V: Implement even-odd shuffles with vnsrl 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. Diff: --- gcc/config/riscv/riscv-v.cc | 40 ++++++++++++++++++++-- .../riscv/rvv/autovec/vls-vlmax/shuffle-evenodd.c | 3 +- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index eabc792f8b7d..3b9f685e7708 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -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; diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/shuffle-evenodd.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/shuffle-evenodd.c index 6db4c5ab3862..ba1131b1f166 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/shuffle-evenodd.c +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/shuffle-evenodd.c @@ -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 } } */
