https://gcc.gnu.org/g:1dc037ec42169fe28715dc3fa8181506046dab1c
commit r17-4673-g1dc037ec42169fe28715dc3fa8181506046dab1c Author: Dominic P <[email protected]> Date: Thu Sep 10 01:30:25 2026 +0100 aarch64: Make the rounding shift-right pair reachable from generic code 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; the preceding commit 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. 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]> Diff: --- gcc/config/aarch64/aarch64-simd.md | 10 +-- gcc/testsuite/gcc.target/aarch64/simd_srshr_1.c | 90 +++++++++++++++++++++++++ gcc/testsuite/gcc.target/aarch64/simd_srshr_2.c | 62 +++++++++++++++++ 3 files changed, 158 insertions(+), 4 deletions(-) diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md index 517b74d8f1a8..98c2da034c55 100644 --- a/gcc/config/aarch64/aarch64-simd.md +++ b/gcc/config/aarch64/aarch64-simd.md @@ -1650,7 +1650,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])" @@ -1689,7 +1690,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); } @@ -7418,7 +7419,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" @@ -7441,7 +7443,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 000000000000..aec88349ccde --- /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 000000000000..51129fdd165c --- /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; +}
