> On 10 Sep 2026, at 19:51, Dominic P <[email protected]> wrote: > > aarch64_<sra_op>rshr_n<mode><vczle><vczbe>_insn and > aarch64_<sra_op>rsra_n<mode>_insn model the rounding add and the shift in > <V2XWIDE>, as SRSHR/URSHR and SRSRA/URSRA do, but take the shift amount > as a vector in <MODE>. Only their own expanders build that, so nothing > but the RTL they emit themselves can ever match them: they are reachable > from the ACLE and from nothing else. The same operation written in C > reaches combine with the shift amount in the mode of the shift, so it > fails to match and comes out as movi + uaddw + shrn. > > Take the shift amount in <V2XWIDE> in both patterns and build it there in > both expanders. The accepted range is unchanged; it comes from > aarch64_simd_shift_imm_<vec_or_offset>_<Vel>, which is keyed on <MODE>. > The two have to move together, because combine turns an add of a rounding > shift into SRSRA and folds SRSRA against a zero accumulator back into > SRSHR, so converting one alone would cost that fusion. > > The widened shape is the only correct one: the source-width spelling > (x + (1 << (n - 1))) >> n is a different operation and is deliberately not > matched, since under qemu vrshrq_n_s32 (INT_MAX, 8) is 8388608 where the > C expression is -8388608. Only the 64-bit-result forms become reachable > from C; srshr v.16b, v.8h and v.4s stay intrinsic-only because their > <V2XWIDE> modes are V16HI, V8SI and V4DI, which the vectoriser does not > use. The RSHRN, RSHRN2 and SQRSHRUN recognisers keep the same > construction and stay ACLE-only for the same reason; 1/2 gives the RSHRN > pair source-width companions instead, which the saturating forms cannot > have. > > For an eight-byte uint8_t block at -O2, movi + ldr + uaddw + shrn + str > becomes ldr + urshr + str. > > Cross-tested aarch64-linux-gnu under qemu-aarch64 (aarch64.exp, simd.exp, > advsimd-intrinsics.exp, vect.exp, like for like against the same tree > unpatched) and bootstrapped on x86_64-pc-linux-gnu. > Ok. Thanks, Kyrill > Assisted-by: Claude Opus 5 (Anthropic) > > gcc/ChangeLog: > > * config/aarch64/aarch64-simd.md > (aarch64_<sra_op>rsra_n<mode>_insn): Take the shift amount in > <V2XWIDE> mode. > (aarch64_<sra_op>rsra_n<mode>): Build the shift amount vector in > that mode. > (aarch64_<sra_op>rshr_n<mode><vczle><vczbe>_insn): Take the shift > amount in <V2XWIDE> mode. > (aarch64_<sra_op>rshr_n<mode>): Build the shift amount vector in > that mode. > > gcc/testsuite/ChangeLog: > > * gcc.target/aarch64/simd_srshr_1.c: New test. > * gcc.target/aarch64/simd_srshr_2.c: New test. > > Signed-off-by: Dominic P <[email protected]> > --- > gcc/config/aarch64/aarch64-simd.md | 10 ++- > .../gcc.target/aarch64/simd_srshr_1.c | 90 +++++++++++++++++++ > .../gcc.target/aarch64/simd_srshr_2.c | 62 +++++++++++++ > 3 files changed, 158 insertions(+), 4 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/aarch64/simd_srshr_1.c > create mode 100644 gcc/testsuite/gcc.target/aarch64/simd_srshr_2.c > > diff --git a/gcc/config/aarch64/aarch64-simd.md > b/gcc/config/aarch64/aarch64-simd.md > index a07e43d91d3..451ea9ff1a5 100644 > --- a/gcc/config/aarch64/aarch64-simd.md > +++ b/gcc/config/aarch64/aarch64-simd.md > @@ -1635,7 +1635,8 @@ > (<SHIFTEXTEND>:<V2XWIDE> > (match_operand:VSDQ_I_DI 2 "register_operand" "w")) > (match_operand:<V2XWIDE> 4 "aarch64_int_rnd_operand")) > - (match_operand:VSDQ_I_DI 3 > "aarch64_simd_shift_imm_<vec_or_offset>_<Vel>"))) > + (match_operand:<V2XWIDE> 3 > + "aarch64_simd_shift_imm_<vec_or_offset>_<Vel>"))) > (match_operand:VSDQ_I_DI 1 "register_operand" "0")))] > "TARGET_SIMD > && aarch64_const_vec_rnd_cst_p (operands[4], operands[3])" > @@ -1674,7 +1675,7 @@ > rtx rnd = immed_wide_int_const (rnd_wi, GET_MODE_INNER (<V2XWIDE>mode)); > if (VECTOR_MODE_P (<MODE>mode)) > { > - shft = gen_const_vec_duplicate (<MODE>mode, shft); > + shft = gen_const_vec_duplicate (<V2XWIDE>mode, shft); > rnd = gen_const_vec_duplicate (<V2XWIDE>mode, rnd); > } > > @@ -7393,7 +7394,8 @@ > (<SHIFTEXTEND>:<V2XWIDE> > (match_operand:VSDQ_I_DI 1 "register_operand" "w")) > (match_operand:<V2XWIDE> 3 "aarch64_int_rnd_operand")) > - (match_operand:VSDQ_I_DI 2 > "aarch64_simd_shift_imm_<vec_or_offset>_<Vel>"))))] > + (match_operand:<V2XWIDE> 2 > + "aarch64_simd_shift_imm_<vec_or_offset>_<Vel>"))))] > "TARGET_SIMD > && aarch64_const_vec_rnd_cst_p (operands[3], operands[2])" > "<sra_op>rshr\t%<v>0<Vmtype>, %<v>1<Vmtype>, %2" > @@ -7416,7 +7418,7 @@ > rtx rnd = immed_wide_int_const (rnd_wi, GET_MODE_INNER (<V2XWIDE>mode)); > if (VECTOR_MODE_P (<MODE>mode)) > { > - shft = gen_const_vec_duplicate (<MODE>mode, shft); > + shft = gen_const_vec_duplicate (<V2XWIDE>mode, shft); > rnd = gen_const_vec_duplicate (<V2XWIDE>mode, rnd); > } > > diff --git a/gcc/testsuite/gcc.target/aarch64/simd_srshr_1.c > b/gcc/testsuite/gcc.target/aarch64/simd_srshr_1.c > new file mode 100644 > index 00000000000..aec88349ccd > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/simd_srshr_1.c > @@ -0,0 +1,90 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -march=armv8-a" } */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > +#include <stdint.h> > + > +typedef int8_t v8qi __attribute__((vector_size (8))); > +typedef int16_t v8hi __attribute__((vector_size (16))); > +typedef uint8_t v8uqi __attribute__((vector_size (8))); > +typedef uint16_t v8uhi __attribute__((vector_size (16))); > +typedef int16_t v4hi __attribute__((vector_size (8))); > +typedef int32_t v4si __attribute__((vector_size (16))); > +typedef uint16_t v4uhi __attribute__((vector_size (8))); > +typedef uint32_t v4usi __attribute__((vector_size (16))); > + > +/* > +** s8: > +** srshr v0\.8b, v0\.8b, 3 > +** ret > +*/ > +v8qi > +s8 (v8qi x) > +{ > + v8hi w = __builtin_convertvector (x, v8hi); > + return __builtin_convertvector ((w + 4) >> 3, v8qi); > +} > + > +/* > +** u8: > +** urshr v0\.8b, v0\.8b, 3 > +** ret > +*/ > +v8uqi > +u8 (v8uqi x) > +{ > + v8uhi w = __builtin_convertvector (x, v8uhi); > + return __builtin_convertvector ((w + 4) >> 3, v8uqi); > +} > + > +/* > +** s16: > +** srshr v0\.4h, v0\.4h, 6 > +** ret > +*/ > +v4hi > +s16 (v4hi x) > +{ > + v4si w = __builtin_convertvector (x, v4si); > + return __builtin_convertvector ((w + 32) >> 6, v4hi); > +} > + > +/* > +** u16: > +** urshr v0\.4h, v0\.4h, 6 > +** ret > +*/ > +v4uhi > +u16 (v4uhi x) > +{ > + v4usi w = __builtin_convertvector (x, v4usi); > + return __builtin_convertvector ((w + 32) >> 6, v4uhi); > +} > + > +/* > +** loop_s8: > +** ldr d31, \[x1\] > +** srshr v31\.8b, v31\.8b, 3 > +** str d31, \[x0\] > +** ret > +*/ > +void > +loop_s8 (int8_t *__restrict d, const int8_t *__restrict s) > +{ > + for (int i = 0; i < 8; i++) > + d[i] = (int8_t) ((s[i] + 4) >> 3); > +} > + > +/* > +** loop_u8: > +** ldr d31, \[x1\] > +** urshr v31\.8b, v31\.8b, 3 > +** str d31, \[x0\] > +** ret > +*/ > +void > +loop_u8 (uint8_t *__restrict d, const uint8_t *__restrict s) > +{ > + for (int i = 0; i < 8; i++) > + d[i] = (uint8_t) ((s[i] + 4) >> 3); > +} > diff --git a/gcc/testsuite/gcc.target/aarch64/simd_srshr_2.c > b/gcc/testsuite/gcc.target/aarch64/simd_srshr_2.c > new file mode 100644 > index 00000000000..51129fdd165 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/simd_srshr_2.c > @@ -0,0 +1,62 @@ > +/* { dg-do run } */ > +/* { dg-options "-O2 -march=armv8-a" } */ > + > +#include <stdint.h> > + > +typedef int8_t v8qi __attribute__((vector_size (8))); > +typedef int16_t v8hi __attribute__((vector_size (16))); > +typedef uint8_t v8uqi __attribute__((vector_size (8))); > +typedef uint16_t v8uhi __attribute__((vector_size (16))); > +typedef int16_t v4hi __attribute__((vector_size (8))); > +typedef int32_t v4si __attribute__((vector_size (16))); > +typedef uint16_t v4uhi __attribute__((vector_size (8))); > +typedef uint32_t v4usi __attribute__((vector_size (16))); > + > +#define ROUND(NAME, NARROW, WIDE, ELT, WELT, LANES, N) \ > + __attribute__((noipa)) static NARROW \ > + NAME (NARROW x) \ > + { \ > + WIDE w = __builtin_convertvector (x, WIDE); \ > + return __builtin_convertvector ((w + (1 << (N - 1))) >> N, NARROW); \ > + } \ > + __attribute__((noipa)) static void \ > + NAME##_check (void) \ > + { \ > + NARROW x, r; \ > + for (int rep = 0; rep < 4096; rep++) \ > + { \ > + for (int i = 0; i < LANES; i++) \ > + x[i] = (ELT) rnd (); \ > + r = NAME (x); \ > + for (int i = 0; i < LANES; i++) \ > + { \ > + WELT w = (WELT) x[i] + (1 << (N - 1)); \ > + if (r[i] != (ELT) (w >> N)) \ > + __builtin_abort (); \ > + } \ > + } \ > + } > + > +static uint64_t seed = 0x123456789abcdefULL; > + > +static uint64_t > +rnd (void) > +{ > + seed = seed * 6364136223846793005ULL + 1442695040888963407ULL; > + return seed >> 11; > +} > + > +ROUND (s8, v8qi, v8hi, int8_t, int16_t, 8, 3) > +ROUND (u8, v8uqi, v8uhi, uint8_t, uint16_t, 8, 3) > +ROUND (s16, v4hi, v4si, int16_t, int32_t, 4, 6) > +ROUND (u16, v4uhi, v4usi, uint16_t, uint32_t, 4, 6) > + > +int > +main (void) > +{ > + s8_check (); > + u8_check (); > + s16_check (); > + u16_check (); > + return 0; > +} > -- > 2.55.0 >
