> On 28 Aug 2026, at 11:41, Richard Sandiford <[email protected]> > wrote: > > Richard Sandiford <[email protected]> writes: >> <[email protected]> writes: >>> From: Kyrylo Tkachov <[email protected]> >>> >>> REDUC_MAX, REDUC_MIN, REDUC_AND and REDUC_IOR are idempotent. A >>> reduction of a nonempty duplicate vector with one of these operations is >>> the duplicated element: >>> >>> v = [vec_duplicate_expr] x; >>> res = .REDUC_MAX (v); >>> >>> becomes: >>> >>> res = x; >>> >>> For example, the new SVE test contains: >>> >>> int __GIMPLE () >>> reduc_max (int x) >>> { >>> svint32_t v; >>> int res; >>> >>> v = svdup_s32 (x); >>> res = .REDUC_MAX (v); >>> return res; >>> } >>> >>> With -O2 -fgimple -march=armv8.2-a+sve, the code changes from: >>> >>> reduc_max: >>> mov z31.s, w0 >>> ptrue p7.b, all >>> smaxv s31, p7, z31.s >>> fmov w0, s31 >>> ret >>> >>> to: >>> >>> reduc_max: >>> ret >>> >>> An XOR reduction of a duplicate vector is zero when the number of lanes >>> is even. GCC permits variable-length vectors whose lane count has >>> unknown parity, such as [1, 1]. Fold REDUC_XOR only when multiple_p >>> proves that every possible lane count has the required parity. >>> >>> Use the same two paths as IFN_VEC_EXTRACT and IFN_VEC_SHL_INSERT. Match >>> a nonconstant VEC_DUPLICATE_EXPR directly in match.pd. Handle a >>> VECTOR_CST in fold_const_reduction. >>> >>> Start constant folding with the explicitly encoded elements for both >>> fixed-length and variable-length vectors. A non-stepped encoding can be >>> used for an idempotent reduction when every encoded element is guaranteed >>> to be present. For XOR, require the remaining encoded copies to cancel >>> in pairs. Process two periods of a duplicate encoding, or the foreground >>> and background of a two-element-per-pattern encoding. Use the exact >>> element count as a fallback when it is known. >>> >>> Keep REDUC_MAX and REDUC_MIN when a shortened reduction could return a >>> signaling NaN directly. The full reduction can quiet the NaN and raise an >>> invalid-operation exception. >>> >>> These folds also let the constant reduction in the PR 127039 rule >>> simplify for scalable constants. The scalar result cannot match the >>> inverse reduction-pair rule, so the nontermination cycle stays blocked. >>> >>> Bootstrapped and tested on aarch64-none-linunx-gnu. >>> Ok for trunk? >>> Thanks, >>> Kyrill >>> >>> gcc/ChangeLog: >>> >>> PR tree-optimization/127039 >>> * fold-const-call.cc (fold_const_reduction): Fold non-stepped constants >>> when the available lane-count information determines the result. >>> * match.pd (reduction of a vector duplicate): New simplifications to >>> the duplicated element or zero. >>> >>> gcc/testsuite/ChangeLog: >>> >>> PR tree-optimization/127039 >>> * gcc.target/aarch64/sve/vec-reduc-dup-1.c: New test. >>> * gcc.target/aarch64/sve/vec-reduc-pattern-1.c: New test. >>> * gcc.target/aarch64/sve/vec-reduc-snan-1.c: New test. >>> * gcc.target/aarch64/sve/vec-reduc-uniform-1.c: New test. >>> * gcc.target/riscv/rvv/base/reduc-xor-uniform-1.c: New test. >>> >>> Signed-off-by: Kyrylo Tkachov <[email protected]> >>> --- >>> gcc/fold-const-call.cc | 36 +++- >>> gcc/match.pd | 14 ++ >>> .../gcc.target/aarch64/sve/vec-reduc-dup-1.c | 63 +++++++ >>> .../aarch64/sve/vec-reduc-pattern-1.c | 156 ++++++++++++++++++ >>> .../gcc.target/aarch64/sve/vec-reduc-snan-1.c | 65 ++++++++ >>> .../aarch64/sve/vec-reduc-uniform-1.c | 71 ++++++++ >>> .../riscv/rvv/base/reduc-xor-uniform-1.c | 47 ++++++ >>> 7 files changed, 449 insertions(+), 3 deletions(-) >>> create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/vec-reduc-dup-1.c >>> create mode 100644 >>> gcc/testsuite/gcc.target/aarch64/sve/vec-reduc-pattern-1.c >>> create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/vec-reduc-snan-1.c >>> create mode 100644 >>> gcc/testsuite/gcc.target/aarch64/sve/vec-reduc-uniform-1.c >>> create mode 100644 >>> gcc/testsuite/gcc.target/riscv/rvv/base/reduc-xor-uniform-1.c >>> >>> diff --git a/gcc/fold-const-call.cc b/gcc/fold-const-call.cc >>> index c483b80e704..342a65f4217 100644 >>> --- a/gcc/fold-const-call.cc >>> +++ b/gcc/fold-const-call.cc >>> @@ -622,9 +622,39 @@ fold_const_builtin_nan (tree type, tree arg, bool >>> quiet) >>> static tree >>> fold_const_reduction (tree type, tree arg, tree_code code) >>> { >>> - unsigned HOST_WIDE_INT nelts; >>> - if (TREE_CODE (arg) != VECTOR_CST >>> - || !VECTOR_CST_NELTS (arg).is_constant (&nelts)) >>> + if (TREE_CODE (arg) != VECTOR_CST) >>> + return NULL_TREE; >>> + >>> + bool idempotent_p = (code == MAX_EXPR >>> + || code == MIN_EXPR >>> + || code == BIT_AND_EXPR >>> + || code == BIT_IOR_EXPR); >>> + >>> + unsigned HOST_WIDE_INT nelts = vector_cst_encoded_nelts (arg); >>> + bool singleton_snan_p >>> + = (nelts == 1 >>> + && tree_expr_maybe_signaling_nan_p (VECTOR_CST_ELT (arg, 0))); >>> + >>> + if (idempotent_p >>> + && !VECTOR_CST_STEPPED_P (arg) >>> + && multiple_p (VECTOR_CST_NELTS (arg), nelts) >>> + && !singleton_snan_p) >> >> I don't understand why the singleton_snan_p exception is needed. >> Doesn't that imply that we mishandle that situation below? >> >> The condition seems to mean that a 128-bit SVE vector will be handled >> differently for -msve-vector-bits=128 and -msve-vector-bits=scalable, >> despite the behaviour being the same at runtime. > > Sorry, I get it now. Doubling nelts to force an operation would > unnecessarily penalise folds of known single-element vectors, > which really don't raise an exception. >
Yeah, that’s the idea. > So yeah, I suppose this is probably the best way to handle it. > Thanks, can I take this as an ok for the patch? Kyrill > Richard
