Ping.
https://gcc.gnu.org/pipermail/gcc-patches/2026-October/733603.html
Thanks,
Kyrill

> On 6 Oct 2026, at 16:15, [email protected] wrote:
> 
> From: Kyrylo Tkachov <[email protected]>
> 
> The 64-bit accumulator path in precompute_partition_info_sums_ from
> Xiph FLAC adds the absolute values of 32-bit residuals.
> The relevant statement in src/libFLAC/stream_encoder.c is:
> 
>  abs_residual_partition_sum64 += abs (residual[residual_sample]);
> 
> The vectorizer recognizes this as a widening sum.  The SVE2
> reduc_widen_ssum expander then emits SADDWB followed by SADDWT.  Both
> instructions add one half of the narrow vector to the same accumulator.
> SADALP performs the same pairwise widening accumulation in one
> instruction.  The unsigned widening sum has the same issue with UADDWB
> and UADDWT.
> 
> Emit the existing predicated SADALP and UADALP patterns from the SVE2
> widening-sum expanders.  Use an all-true predicate because the optab is
> unpredicated.  Keep the existing SVE2.1 and SME2 H-to-S dot-product case.
> 
> With:
> 
>  -O3 -mcpu=neoverse-v2 -mautovec-preference=sve-only
>  -msve-vector-bits=scalable
>  --param aarch64-vect-unroll-limit=1
>  --param vect-partial-vector-usage=0
> 
> the steady loop for the FLAC reduction changes from:
> 
>  .L4:
>          ld1w    z30.s, p7/z, [x0, x2, lsl 2]
>          mov     x4, x2
>          add     x2, x2, x5
>          abs     z30.s, p7/m, z30.s
>          saddwb  z31.d, z31.d, z30.s
>          saddwt  z31.d, z31.d, z30.s
>          cmp     w3, w2
>          bcs     .L4
> 
> to:
> 
>  .L4:
>          ld1w    z30.s, p7/z, [x0, x2, lsl 2]
>          mov     x4, x2
>          add     x2, x2, x5
>          abs     z30.s, p7/m, z30.s
>          sadalp  z31.d, p7/m, z30.s
>          cmp     w3, w2
>          bcs     .L4
> 
> Bootstrapped and tested on aarch64-none-linux-gnu.
> Ok for trunk?
> Thanks,
> Kyrill
> 
> Cc: Tamar Christina <[email protected]>
> 
> gcc/ChangeLog:
> 
> * config/aarch64/aarch64-sve2.md
> (reduc_widen_ssum<mode><Vnarrow>3): Emit cond_sadalp.
> (reduc_widen_usum<mode><Vnarrow>3): Emit cond_uadalp.
> (cond_<sve_int_op><mode>, *cond_<sve_int_op><mode>_2,
> *cond_<sve_int_op><mode>_z): Fix comments.
> 
> gcc/testsuite/ChangeLog:
> 
> * gcc.target/aarch64/sve2/pr122069_1.c: Expect UADALP.
> * gcc.target/aarch64/sve2/widen-sum-adalp-1.c: New test.
> * gcc.target/aarch64/sve2/widen-sum-adalp-run.c: Likewise.
> 
> Signed-off-by: Kyrylo Tkachov <[email protected]>
> ---
> gcc/config/aarch64/aarch64-sve2.md            |  47 +++----
> .../gcc.target/aarch64/sve2/pr122069_1.c      |   3 +-
> .../aarch64/sve2/widen-sum-adalp-1.c          |  38 ++++++
> .../aarch64/sve2/widen-sum-adalp-run.c        | 123 ++++++++++++++++++
> 4 files changed, 183 insertions(+), 28 deletions(-)
> create mode 100644 gcc/testsuite/gcc.target/aarch64/sve2/widen-sum-adalp-1.c
> create mode 100644 gcc/testsuite/gcc.target/aarch64/sve2/widen-sum-adalp-run.c
> 
> diff --git a/gcc/config/aarch64/aarch64-sve2.md 
> b/gcc/config/aarch64/aarch64-sve2.md
> index c33df283cc2..7d8504db304 100644
> --- a/gcc/config/aarch64/aarch64-sve2.md
> +++ b/gcc/config/aarch64/aarch64-sve2.md
> @@ -2563,18 +2563,11 @@
>   [(set_attr "sve_type" "sve_int_general")]
> )
> 
> -;; Define single step widening for reduc_widen_ssum using SADDWB and SADDWT
> +;; Define single step widening for reduc_widen_ssum using SADALP.
> (define_expand "reduc_widen_ssum<mode><Vnarrow>3"
> -  [(set (match_operand:SVE_FULL_HSDI 0 "register_operand")
> - (unspec:SVE_FULL_HSDI
> -  [(match_operand:SVE_FULL_HSDI 2 "register_operand")
> -   (match_operand:<VNARROW> 1 "register_operand")]
> -  UNSPEC_SADDWB))
> -   (set (match_dup 0)
> - (unspec:SVE_FULL_HSDI
> -  [(match_dup 0)
> -   (match_dup 1)]
> -  UNSPEC_SADDWT))]
> +  [(match_operand:SVE_FULL_HSDI 0 "register_operand")
> +   (match_operand:<VNARROW> 1 "register_operand")
> +   (match_operand:SVE_FULL_HSDI 2 "register_operand")]
>   "TARGET_SVE2"
> {
>   /* Use dot product to perform double widening sum reductions by
> @@ -2588,20 +2581,18 @@
>    ones, operands[2]));
>       DONE;
>     }
> +
> +  rtx pred = aarch64_ptrue_reg (<VPRED>mode);
> +  emit_insn (gen_cond_sadalp<mode> (operands[0], pred, operands[2],
> +    operands[1], operands[2]));
> +  DONE;
> })
> 
> -;; Define single step widening for reduc_widen_usum using UADDWB and UADDWT
> +;; Define single step widening for reduc_widen_usum using UADALP.
> (define_expand "reduc_widen_usum<mode><Vnarrow>3"
> -  [(set (match_operand:SVE_FULL_HSDI 0 "register_operand" "=w")
> - (unspec:SVE_FULL_HSDI
> -  [(match_operand:SVE_FULL_HSDI 2 "register_operand" "w")
> -   (match_operand:<VNARROW> 1 "register_operand" "w")]
> -  UNSPEC_UADDWB))
> -   (set (match_dup 0)
> - (unspec:SVE_FULL_HSDI
> -  [(match_dup 0)
> -   (match_dup 1)]
> -  UNSPEC_UADDWT))]
> +  [(match_operand:SVE_FULL_HSDI 0 "register_operand")
> +   (match_operand:<VNARROW> 1 "register_operand")
> +   (match_operand:SVE_FULL_HSDI 2 "register_operand")]
>   "TARGET_SVE2"
> {
>   if (TARGET_SVE2p1_OR_SME2
> @@ -2613,6 +2604,11 @@
>    ones, operands[2]));
>       DONE;
>     }
> +
> +  rtx pred = aarch64_ptrue_reg (<VPRED>mode);
> +  emit_insn (gen_cond_uadalp<mode> (operands[0], pred, operands[2],
> +    operands[1], operands[2]));
> +  DONE;
> })
> 
> ;; -------------------------------------------------------------------------
> @@ -3344,7 +3340,7 @@
> ;; - UADALP
> ;; -------------------------------------------------------------------------
> 
> -;; Predicated pairwise absolute difference and accumulate with merging.
> +;; Predicated add long pairwise and accumulate with merging.
> (define_expand "@cond_<sve_int_op><mode>"
>   [(set (match_operand:SVE_FULL_HSDI 0 "register_operand")
> (unspec:SVE_FULL_HSDI
> @@ -3364,8 +3360,7 @@
>      || CONSTANT_P (operands[4]));
> })
> 
> -;; Predicated pairwise absolute difference and accumulate, merging with
> -;; the first input.
> +;; Predicated add long pairwise and accumulate, merging with the first input.
> (define_insn_and_rewrite "*cond_<sve_int_op><mode>_2"
>   [(set (match_operand:SVE_FULL_HSDI 0 "register_operand")
> (unspec:SVE_FULL_HSDI
> @@ -3389,7 +3384,7 @@
>   [(set_attr "sve_type" "sve_int_accum")]
> )
> 
> -;; Predicated pairwise absolute difference and accumulate, merging with zero.
> +;; Predicated add long pairwise and accumulate, merging with zero.
> (define_insn_and_rewrite "*cond_<sve_int_op><mode>_z"
>   [(set (match_operand:SVE_FULL_HSDI 0 "register_operand")
> (unspec:SVE_FULL_HSDI
> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/pr122069_1.c 
> b/gcc/testsuite/gcc.target/aarch64/sve2/pr122069_1.c
> index 6a347072ae8..02e38f70b54 100644
> --- a/gcc/testsuite/gcc.target/aarch64/sve2/pr122069_1.c
> +++ b/gcc/testsuite/gcc.target/aarch64/sve2/pr122069_1.c
> @@ -24,8 +24,7 @@ int foo_int(unsigned char *x, unsigned char * restrict y) {
> ** foo2_int:
> ** ...
> ** add z[0-9]+.h, z[0-9]+.h, z[0-9]+.h
> -** uaddwb z[0-9]+.s, z[0-9]+.s, z[0-9]+.h
> -** uaddwt z[0-9]+.s, z[0-9]+.s, z[0-9]+.h
> +** uadalp z[0-9]+.s, p[0-7]/m, z[0-9]+.h
> ** ...
> */
> int foo2_int(unsigned short *x, unsigned short * restrict y) {
> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/widen-sum-adalp-1.c 
> b/gcc/testsuite/gcc.target/aarch64/sve2/widen-sum-adalp-1.c
> new file mode 100644
> index 00000000000..172d6ba645f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/sve2/widen-sum-adalp-1.c
> @@ -0,0 +1,38 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O3 -march=armv9-a+sve2 -mautovec-preference=sve-only 
> -msve-vector-bits=scalable --param aarch64-vect-unroll-limit=1 --param 
> vect-partial-vector-usage=0" } */
> +
> +#define DEF(NAME, INPUT, OUTPUT)                 \
> +  OUTPUT                                        \
> +  NAME (const INPUT *a, unsigned int n)         \
> +  {                                             \
> +    OUTPUT sum = 0;                             \
> +    for (unsigned int i = 0; i < n; ++i)        \
> +      sum += a[i];                              \
> +    return sum;                                 \
> +  }
> +
> +DEF (sum_s8_s16, signed char, short)
> +DEF (sum_u8_u16, unsigned char, unsigned short)
> +DEF (sum_s16_s32, short, int)
> +DEF (sum_u16_u32, unsigned short, unsigned int)
> +DEF (sum_s32_s64, int, long long)
> +DEF (sum_u32_u64, unsigned int, unsigned long long)
> +
> +unsigned long long
> +sum_abs_s32_u64 (const int *a, unsigned int n)
> +{
> +  unsigned long long sum = 0;
> +  for (unsigned int i = 0; i < n; ++i)
> +    sum += __builtin_abs (a[i]);
> +  return sum;
> +}
> +
> +/* { dg-final { scan-assembler-times {\tsadalp\tz[0-9]+\.h, p[0-7]/m, 
> z[0-9]+\.b\n} 1 } } */
> +/* { dg-final { scan-assembler-times {\tuadalp\tz[0-9]+\.h, p[0-7]/m, 
> z[0-9]+\.b\n} 1 } } */
> +/* { dg-final { scan-assembler-times {\tsadalp\tz[0-9]+\.s, p[0-7]/m, 
> z[0-9]+\.h\n} 1 } } */
> +/* { dg-final { scan-assembler-times {\tuadalp\tz[0-9]+\.s, p[0-7]/m, 
> z[0-9]+\.h\n} 1 } } */
> +/* { dg-final { scan-assembler-times {\tsadalp\tz[0-9]+\.d, p[0-7]/m, 
> z[0-9]+\.s\n} 2 } } */
> +/* { dg-final { scan-assembler-times {\tuadalp\tz[0-9]+\.d, p[0-7]/m, 
> z[0-9]+\.s\n} 1 } } */
> +/* { dg-final { scan-assembler-not {\tmovprfx\t} } } */
> +/* { dg-final { scan-assembler-not {\tsaddw[bt]\t} } } */
> +/* { dg-final { scan-assembler-not {\tuaddw[bt]\t} } } */
> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/widen-sum-adalp-run.c 
> b/gcc/testsuite/gcc.target/aarch64/sve2/widen-sum-adalp-run.c
> new file mode 100644
> index 00000000000..d064ed99d0c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/sve2/widen-sum-adalp-run.c
> @@ -0,0 +1,123 @@
> +/* { dg-do run { target aarch64_sve2_hw } } */
> +/* { dg-options "-O3 -march=armv9-a+sve2 -mautovec-preference=sve-only 
> -msve-vector-bits=scalable --param aarch64-vect-unroll-limit=1 --param 
> vect-partial-vector-usage=0" } */
> +
> +#include <arm_sve.h>
> +#include <limits.h>
> +#include <stdlib.h>
> +
> +#define DEF_SUMS(NAME, INPUT, OUTPUT)                           \
> +  __attribute__((noipa)) OUTPUT                                \
> +  NAME (const INPUT *a, unsigned int n)                        \
> +  {                                                            \
> +    OUTPUT sum = 0;                                            \
> +    for (unsigned int i = 0; i < n; ++i)                       \
> +      sum += a[i];                                             \
> +    return sum;                                                \
> +  }                                                            \
> +                                                               \
> +  __attribute__((noipa, optimize ("no-tree-vectorize"))) OUTPUT \
> +  ref_##NAME (const INPUT *a, unsigned int n)                  \
> +  {                                                            \
> +    OUTPUT sum = 0;                                            \
> +    for (unsigned int i = 0; i < n; ++i)                       \
> +      sum += a[i];                                             \
> +    return sum;                                                \
> +  }
> +
> +DEF_SUMS (sum_s8_s16, signed char, short)
> +DEF_SUMS (sum_u8_u16, unsigned char, unsigned short)
> +DEF_SUMS (sum_s16_s32, short, int)
> +DEF_SUMS (sum_u16_u32, unsigned short, unsigned int)
> +DEF_SUMS (sum_s32_s64, int, long long)
> +DEF_SUMS (sum_u32_u64, unsigned int, unsigned long long)
> +
> +__attribute__((noipa)) unsigned long long
> +sum_abs_s32_u64 (const int *a, unsigned int n)
> +{
> +  unsigned long long sum = 0;
> +  for (unsigned int i = 0; i < n; ++i)
> +    sum += __builtin_abs (a[i]);
> +  return sum;
> +}
> +
> +__attribute__((noipa, optimize ("no-tree-vectorize"))) unsigned long long
> +ref_abs_s32_u64 (const int *a, unsigned int n)
> +{
> +  unsigned long long sum = 0;
> +  for (unsigned int i = 0; i < n; ++i)
> +    sum += __builtin_abs (a[i]);
> +  return sum;
> +}
> +
> +int
> +main (void)
> +{
> +  unsigned int vl_b = svcntb ();
> +  unsigned int vl_h = svcnth ();
> +  unsigned int vl_w = svcntw ();
> +  unsigned int count = 4 * vl_b + 3;
> +  unsigned int allocation_count = count + 1;
> +  signed char *signed_char_values
> +    = (signed char *) __builtin_alloca (allocation_count
> +                                        * sizeof (signed char));
> +  unsigned char *unsigned_char_values
> +    = (unsigned char *) __builtin_alloca (allocation_count
> +                                          * sizeof (unsigned char));
> +  short *signed_short_values
> +    = (short *) __builtin_alloca (allocation_count * sizeof (short));
> +  unsigned short *unsigned_short_values
> +    = (unsigned short *) __builtin_alloca (allocation_count
> +                                           * sizeof (unsigned short));
> +  int *signed_int_values
> +    = (int *) __builtin_alloca (allocation_count * sizeof (int));
> +  unsigned int *unsigned_int_values
> +    = (unsigned int *) __builtin_alloca (allocation_count
> +                                         * sizeof (unsigned int));
> +
> +  for (unsigned int i = 0; i < allocation_count; ++i)
> +    {
> +      static const signed char signed_char_edges[] =
> +        { SCHAR_MIN, SCHAR_MAX, 1, 0, -1 };
> +      static const unsigned char unsigned_char_edges[] =
> +        { 0, 1, UCHAR_MAX, UCHAR_MAX - 1, 0x80 };
> +      static const short signed_short_edges[] =
> +        { SHRT_MIN, SHRT_MAX, 1, 0, -1 };
> +      static const unsigned short unsigned_short_edges[] =
> +        { 0, 1, USHRT_MAX, USHRT_MAX - 1, 0x8000 };
> +      static const int signed_int_edges[] =
> +        { INT_MIN + 1, INT_MAX, -1, 0, 1, -123456789, 123456789 };
> +      static const unsigned int unsigned_int_edges[] =
> +        { 0, 1, UINT_MAX, UINT_MAX - 1, 0x80000000U, 123456789U };
> +      signed_char_values[i] = signed_char_edges[i % 5];
> +      unsigned_char_values[i] = unsigned_char_edges[i % 5];
> +      signed_short_values[i] = signed_short_edges[i % 5];
> +      unsigned_short_values[i] = unsigned_short_edges[i % 5];
> +      signed_int_values[i] = signed_int_edges[i % 7];
> +      unsigned_int_values[i] = unsigned_int_edges[i % 6];
> +    }
> +
> +  unsigned int lengths[] =
> +    { 0, 1, vl_w - 1, vl_w, vl_w + 1, vl_h - 1, vl_h, vl_h + 1,
> +      vl_b - 1, vl_b, vl_b + 1, 2 * vl_b + 1, count };
> +  for (unsigned int i = 0; i < sizeof (lengths) / sizeof (lengths[0]); ++i)
> +    for (unsigned int offset = 0; offset <= 1; ++offset)
> +      {
> +        unsigned int n = lengths[i];
> +        if ((sum_s8_s16 (signed_char_values + offset, n)
> +             != ref_sum_s8_s16 (signed_char_values + offset, n))
> +            || (sum_u8_u16 (unsigned_char_values + offset, n)
> +                != ref_sum_u8_u16 (unsigned_char_values + offset, n))
> +            || (sum_s16_s32 (signed_short_values + offset, n)
> +                != ref_sum_s16_s32 (signed_short_values + offset, n))
> +            || (sum_u16_u32 (unsigned_short_values + offset, n)
> +                != ref_sum_u16_u32 (unsigned_short_values + offset, n))
> +            || (sum_s32_s64 (signed_int_values + offset, n)
> +                != ref_sum_s32_s64 (signed_int_values + offset, n))
> +            || (sum_u32_u64 (unsigned_int_values + offset, n)
> +                != ref_sum_u32_u64 (unsigned_int_values + offset, n))
> +            || (sum_abs_s32_u64 (signed_int_values + offset, n)
> +                != ref_abs_s32_u64 (signed_int_values + offset, n)))
> +          abort ();
> +      }
> +  return 0;
> +}
> -- 
> 2.50.1 (Apple Git-155)
> 

Reply via email to