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

Reply via email to