> 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


Reply via email to