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. So yeah, I suppose this is probably the best way to handle it. Richard
