Hi Kyrill,
> -----Original Message-----
> From: [email protected] <[email protected]>
> Sent: 17 August 2026 15:53
> To: [email protected]
> Cc: Tamar Christina <[email protected]>; [email protected]; Kyrylo
> Tkachov <[email protected]>
> Subject: [PATCH] middle-end: Try intermediate types for widening sums
> [PR122069]
>
> From: Kyrylo Tkachov <[email protected]>
>
> vect_recog_widen_sum_pattern currently queries the widening-sum optab
> only
> for the scalar input type in the source. This misses target patterns that
> start at an intermediate precision. For example, AArch64 SVE has a
> VNx2DI <- VNx8HI widening sum but no VNx2DI <- VNx8QI widening sum.
>
> Keep the exact input query and operand first. If the query fails, try
> successively wider full-element integer types up to half the accumulator
> width. Preserve the input signedness and use vect_convert_input to make the
> intermediate conversion. The recognized pattern can then use:
>
> patt_1 = (short int) byte;
> patt_2 = patt_1 w+ sum_0;
>
> For an unsigned byte-to-64-bit reduction on AArch64 SVE, the old main loop
> processes VL / 64 input bytes per iteration:
>
> cntd x3
> whilelo p7.d, xzr, x1
> movi d30, #0
> ptrue p6.b, all
> .L3:
> ld1b z29.d, p7/z, [x0, x2]
> add x2, x2, x3
> add z30.d, p7/m, z30.d, z29.d
> whilelo p7.d, x2, x1
> b.any .L3
> uaddv d31, p6, z30.d
>
> The new main loop processes VL / 16 input bytes per iteration:
>
> cnth x0
> movi d31, #0
> ptrue p7.b, all
> mov z29.h, #1
> .L4:
> ld1b z30.h, p7/z, [x3, x2]
> add x2, x2, x0
> udot z31.d, z30.h, z29.h
> cmp x4, x2
> bcs .L4
> uaddv d31, p7, z31.d
>
> For the same number of input bytes, the old main loop executes four times
> and
> issues four widened loads and four vector adds. The new loop executes once
> and issues one widened load and one dot product.
> The signed form similarly uses LD1SB and SDOT.
> Direct byte-to-32-bit dot products do not change.
>
> Bootstrapped and tested on aarch64-none-linux-gnu.
> Ok for trunk?
> Thanks,
> Kyrill
>
> gcc/ChangeLog:
>
> PR middle-end/122069
> * tree-vect-patterns.cc (vect_recog_widen_sum_pattern): Try wider
> intermediate input types.
>
> gcc/testsuite/ChangeLog:
>
> PR middle-end/122069
> * gcc.target/aarch64/sve/reduc_3_costly.c: Update the expected
> number
> of horizontal reductions.
> * gcc.target/aarch64/sve/widen_sum_1.c: New test.
>
> Signed-off-by: Kyrylo Tkachov <[email protected]>
> ---
> .../gcc.target/aarch64/sve/reduc_3_costly.c | 2 +-
> .../gcc.target/aarch64/sve/widen_sum_1.c | 84 +++++++++++++++++++
> gcc/tree-vect-patterns.cc | 28 ++++++-
> 3 files changed, 111 insertions(+), 3 deletions(-)
> create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/widen_sum_1.c
>
> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/reduc_3_costly.c
> b/gcc/testsuite/gcc.target/aarch64/sve/reduc_3_costly.c
> index 988459df8af..7cef352a9b7 100644
> --- a/gcc/testsuite/gcc.target/aarch64/sve/reduc_3_costly.c
> +++ b/gcc/testsuite/gcc.target/aarch64/sve/reduc_3_costly.c
> @@ -27,6 +27,6 @@ REDUC_PTR (float, _Float16)
> REDUC_PTR (double, float)
>
> /* { dg-final { scan-assembler-times {\tuaddv\td[0-9]+, p[0-7], z[0-9]+\.s\n}
> 2 } } */
> -/* { dg-final { scan-assembler-times {\tuaddv\td[0-9]+, p[0-7], z[0-9]+\.d\n}
> 3 } } */
> +/* { dg-final { scan-assembler-times {\tuaddv\td[0-9]+, p[0-7], z[0-9]+\.d\n}
> 4 } } */
> /* { dg-final { scan-assembler-times {\tfaddv\ts[0-9]+, p[0-7],
> z[0-9]+\.s\n} 1
> } } */
> /* { dg-final { scan-assembler-times {\tfaddv\td[0-9]+, p[0-7],
> z[0-9]+\.d\n} 1
> } } */
> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/widen_sum_1.c
> b/gcc/testsuite/gcc.target/aarch64/sve/widen_sum_1.c
> new file mode 100644
> index 00000000000..3ae9d14dafd
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/sve/widen_sum_1.c
> @@ -0,0 +1,84 @@
> +/* { dg-do compile } */
> +/* { dg-require-effective-target lp64 } */
> +/* { dg-options "-O3 -march=armv8-a+sve -mautovec-preference=sve-only --
> param vect-epilogues-nomask=0 -fdump-tree-vect-details" } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +#define DEF(NAME, INPUT, OUTPUT) \
> + OUTPUT \
> + NAME (const INPUT *a, long n) \
> + { \
> + OUTPUT sum = 0; \
> + for (long i = 0; i < n; ++i) \
> + sum += a[i]; \
> + return sum; \
> + }
> +
> +/*
> +** sum_u8_long:
> +** ...
> +** cnth x[0-9]+
> +** ...
> +** ptrue (p[0-7])\.b, all
> +** mov (z[0-9]+\.h), #1
> +** ...
> +** ld1b (z[0-9]+\.h), \1/z, \[[^]]*\]
> +** ...
> +** udot (z[0-9]+)\.d, \3, \2
> +** ...
> +** uaddv d[0-9]+, \1, \4\.d
> +** ...
> +*/
> +DEF (sum_u8_long, unsigned char, long)
> +
> +/*
> +** sum_s8_long:
> +** ...
> +** cnth x[0-9]+
> +** ...
> +** ptrue (p[0-7])\.b, all
> +** mov (z[0-9]+\.h), #1
> +** ...
> +** ld1sb (z[0-9]+\.h), \1/z, \[[^]]*\]
> +** ...
> +** sdot (z[0-9]+)\.d, \3, \2
> +** ...
> +** uaddv d[0-9]+, \1, \4\.d
> +** ...
> +*/
> +DEF (sum_s8_long, signed char, long)
> +
> +/*
> +** sum_u8_int:
> +** ...
> +** cntb x[0-9]+
> +** ...
> +** ptrue (p[0-7])\.b, all
> +** mov (z[0-9]+\.b), #1
> +** ...
> +** ld1b (z[0-9]+\.b), \1/z, \[[^]]*\]
> +** ...
> +** udot (z[0-9]+)\.s, \3, \2
> +** ...
> +** uaddv d[0-9]+, \1, \4\.s
> +** ...
> +*/
> +DEF (sum_u8_int, unsigned char, int)
> +
> +/*
> +** sum_s8_int:
> +** ...
> +** cntb x[0-9]+
> +** ...
> +** ptrue (p[0-7])\.b, all
> +** mov (z[0-9]+\.b), #1
> +** ...
> +** ld1b (z[0-9]+\.b), \1/z, \[[^]]*\]
> +** ...
> +** sdot (z[0-9]+)\.s, \3, \2
> +** ...
> +** uaddv d[0-9]+, \1, \4\.s
> +** ...
> +*/
> +DEF (sum_s8_int, signed char, int)
> +
> +/* { dg-final { scan-tree-dump-times "LOOP VECTORIZED" 4 "vect" } } */
> diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc
> index fd1232cc755..1ee96b9f225 100644
> --- a/gcc/tree-vect-patterns.cc
> +++ b/gcc/tree-vect-patterns.cc
> @@ -2570,12 +2570,36 @@ vect_recog_widen_sum_pattern (vec_info
> *vinfo,
>
> vect_pattern_detected ("vect_recog_widen_sum_pattern", last_stmt);
>
> + tree input = unprom0.op;
> if (!vect_supportable_conv_optab_p (vinfo, type, WIDEN_SUM_EXPR,
> unprom0.type, type_out))
> - return NULL;
> + {
> + /* Try widening the input to an intermediate type before adding it to
> + the accumulator. Start with the narrowest type in order to retain
> + the largest vectorization factor. */
> + tree input_type = unprom0.type;
> + tree input_vectype = NULL_TREE;
> + for (unsigned int precision
> + = vect_element_precision (TYPE_PRECISION (input_type) + 1);
> + precision <= TYPE_PRECISION (type) / 2;
> + precision *= 2)
> + {
> + input_type = build_nonstandard_integer_type
> + (precision, TYPE_UNSIGNED (unprom0.type));
> + if (vect_supportable_conv_optab_p (vinfo, type, WIDEN_SUM_EXPR,
> + input_type, type_out,
> &input_vectype))
> + break;
> + }
> +
> + if (!input_vectype)
> + return NULL;
> +
> + input = vect_convert_input (vinfo, stmt_vinfo, input_type, &unprom0,
> + input_vectype);
> + }
Patch itself is OK but I think we can simplify this code a bit, what about:
tree input_type = unprom0.type;
tree input_vectype = NULL_TREE;
while (!vect_supportable_conv_optab_p (vinfo, type, WIDEN_SUM_EXPR,
input_type, type_out, &input_vectype))
{
unsigned int precision
= vect_element_precision (TYPE_PRECISION (input_type) + 1);
if (precision > TYPE_PRECISION (type) / 2)
return NULL;
input_type = build_nonstandard_integer_type
(precision, TYPE_UNSIGNED (unprom0.type));
}
tree input = vect_convert_input (vinfo, stmt_vinfo, input_type, &unprom0,
input_vectype);
instead?
OK with that change.
Thanks,
Tamar
>
> var = vect_recog_temp_ssa_var (type, NULL);
> - pattern_stmt = gimple_build_assign (var, WIDEN_SUM_EXPR, unprom0.op,
> oprnd1);
> + pattern_stmt = gimple_build_assign (var, WIDEN_SUM_EXPR, input,
> oprnd1);
>
> return pattern_stmt;
> }
> --
> 2.50.1 (Apple Git-155)