From: Kyrylo Tkachov <[email protected]>

REDUC_MAX, REDUC_MIN, REDUC_AND and REDUC_IOR are idempotent.  Reducing
a nonempty uniform vector with one of these operations gives the element
that the vector contains.  Fold this form to that element:

  v = _Literal (v4si) { x, x, x, x };
  res = .REDUC_MAX (v);
  return res;

to:

  return x;

An XOR reduction of a uniform 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 is even:

  v = _Literal (v4si) { x, x, x, x };
  res = .REDUC_XOR (v);
  return res;

to:

  return 0;

Use vec_same_elem_p to match the uniform vector and
ssa_uniform_vector_p to get its element.  Keep a floating-point
reduction when the element can be a signaling NaN because the reduction
can quiet the NaN and raise an exception.

These folds also let the constant reduction in the PR 127039 rule
simplify for scalable uniform constants.  The scalar result cannot match
the inverse reduction-pair rule, so the nontermination cycle stays
blocked.

The assembly comparison uses this function from the new test:

  typedef int v4si __attribute__ ((vector_size (16)));

  int __GIMPLE ()
  reduc_max (int x)
  {
    v4si v;
    int res;

    v = _Literal (v4si) { x, x, x, x };
    res = .REDUC_MAX (v);
    return res;
  }

With -O2 -fgimple on AArch64, the code changes from:

  reduc_max:
          dup     v31.4s, w0
          smaxv   s31, v31.4s
          fmov    w0, s31
          ret

to:

  reduc_max:
          ret

Bootstrapped and tested on aarch64-unknown-linux-gnu.
Ok for trunk?
Thanks,
Kyrill

gcc/ChangeLog:

        PR tree-optimization/127039
        * match.pd (reduction of a uniform vector): New simplifications to
        the splatted element or zero.

gcc/testsuite/ChangeLog:

        PR tree-optimization/127039
        * gcc.dg/tree-ssa/vec-reduc-splat-1.c: New test.
        * gcc.target/aarch64/sve/vec-reduc-uniform-1.c: New test.
        * gcc.target/aarch64/vec-reduc-splat-float-1.c: New test.
        * gcc.target/riscv/rvv/base/reduc-xor-uniform-1.c: New test.

Signed-off-by: Kyrylo Tkachov <[email protected]>
---
 gcc/match.pd                                  | 17 +++++
 .../gcc.dg/tree-ssa/vec-reduc-splat-1.c       | 69 ++++++++++++++++++
 .../aarch64/sve/vec-reduc-uniform-1.c         | 71 +++++++++++++++++++
 .../aarch64/vec-reduc-splat-float-1.c         | 31 ++++++++
 .../riscv/rvv/base/reduc-xor-uniform-1.c      | 47 ++++++++++++
 5 files changed, 235 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vec-reduc-splat-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/vec-reduc-uniform-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/vec-reduc-splat-float-1.c
 create mode 100644 
gcc/testsuite/gcc.target/riscv/rvv/base/reduc-xor-uniform-1.c

diff --git a/gcc/match.pd b/gcc/match.pd
index c7841cab459..529e3d5ff60 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -12536,6 +12536,23 @@ and,
    (if (elem)
     { build_vector_from_val (type, elem); }))))
 
+/* A reduction of a uniform vector with an idempotent operation is the
+   element it is a splat of.  */
+(for reduc (IFN_REDUC_MAX IFN_REDUC_MIN IFN_REDUC_AND IFN_REDUC_IOR)
+ (simplify
+  (reduc vec_same_elem_p@0)
+  (with { tree elem = ssa_uniform_vector_p (@0); }
+   (if (elem
+       && types_match (type, TREE_TYPE (elem))
+       && !tree_expr_maybe_signaling_nan_p (elem))
+    { elem; }))))
+
+/* Fold an XOR reduction of an even-length uniform vector to zero.  */
+(simplify
+ (IFN_REDUC_XOR vec_same_elem_p@0)
+ (if (multiple_p (TYPE_VECTOR_SUBPARTS (TREE_TYPE (@0)), 2))
+  { build_zero_cst (type); }))
+
 /* Push VEC_PERM earlier if that may help FMA perception (PR101895).  */
 (simplify
  (plus:c (vec_perm:s (mult:c@0 @1 vec_same_elem_p@2) @0 @3) @4)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vec-reduc-splat-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/vec-reduc-splat-1.c
new file mode 100644
index 00000000000..2ad23472a06
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vec-reduc-splat-1.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fgimple -Wno-psabi -fdump-tree-forwprop1" } */
+
+/* Check reductions of a variable splat.  */
+
+typedef int v4si __attribute__ ((vector_size (16)));
+
+int __GIMPLE ()
+reduc_max (int x)
+{
+  v4si v;
+  int res;
+
+  v = _Literal (v4si) { x, x, x, x };
+  res = .REDUC_MAX (v);
+  return res;
+}
+
+int __GIMPLE ()
+reduc_min (int x)
+{
+  v4si v;
+  int res;
+
+  v = _Literal (v4si) { x, x, x, x };
+  res = .REDUC_MIN (v);
+  return res;
+}
+
+int __GIMPLE ()
+reduc_and (int x)
+{
+  v4si v;
+  int res;
+
+  v = _Literal (v4si) { x, x, x, x };
+  res = .REDUC_AND (v);
+  return res;
+}
+
+int __GIMPLE ()
+reduc_ior (int x)
+{
+  v4si v;
+  int res;
+
+  v = _Literal (v4si) { x, x, x, x };
+  res = .REDUC_IOR (v);
+  return res;
+}
+
+int __GIMPLE ()
+reduc_xor_even (int x)
+{
+  v4si v;
+  int res;
+
+  v = _Literal (v4si) { x, x, x, x };
+  res = .REDUC_XOR (v);
+  return res;
+}
+
+/* { dg-final { scan-tree-dump-not {\.REDUC_MAX} "forwprop1" } } */
+/* { dg-final { scan-tree-dump-not {\.REDUC_MIN} "forwprop1" } } */
+/* { dg-final { scan-tree-dump-not {\.REDUC_AND} "forwprop1" } } */
+/* { dg-final { scan-tree-dump-not {\.REDUC_IOR} "forwprop1" } } */
+/* { dg-final { scan-tree-dump-not {\.REDUC_XOR} "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times {return x_} 4 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times {return 0;} 1 "forwprop1" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vec-reduc-uniform-1.c 
b/gcc/testsuite/gcc.target/aarch64/sve/vec-reduc-uniform-1.c
new file mode 100644
index 00000000000..9830511b18d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/vec-reduc-uniform-1.c
@@ -0,0 +1,71 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -msve-vector-bits=scalable -mautovec-preference=sve-only 
-fvect-cost-model=unlimited --param=vect-partial-vector-usage=0 
-fdump-tree-vect-details -fdump-tree-forwprop4" } */
+
+/* Check reductions of scalable uniform vector constants.  */
+
+char c1, c2, c3, c4, c5;
+short d1, d2, d3, d4, d5;
+int rmax, rmin, r_and, r_ior, r_xor;
+unsigned n;
+
+__attribute__ ((noipa)) void
+max_uniform (void)
+{
+  for (short i = 0; i < n; i += 3)
+    {
+      c1 ^= d1;
+      rmax = rmax > 17 ? rmax : 17;
+    }
+}
+
+__attribute__ ((noipa)) void
+min_uniform (void)
+{
+  for (short i = 0; i < n; i += 3)
+    {
+      c2 ^= d2;
+      rmin = rmin < -19 ? rmin : -19;
+    }
+}
+
+__attribute__ ((noipa)) void
+and_uniform (void)
+{
+  for (short i = 0; i < n; i += 3)
+    {
+      c3 ^= d3;
+      r_and &= 1431655765;
+    }
+}
+
+__attribute__ ((noipa)) void
+ior_uniform (void)
+{
+  for (short i = 0; i < n; i += 3)
+    {
+      c4 ^= d4;
+      r_ior |= 572662306;
+    }
+}
+
+__attribute__ ((noipa)) void
+xor_uniform (void)
+{
+  for (short i = 0; i < n; i += 3)
+    {
+      c5 ^= d5;
+      r_xor ^= 858993459;
+    }
+}
+
+/* { dg-final { scan-tree-dump-times {LOOP VECTORIZED} 5 "vect" } } */
+/* { dg-final { scan-tree-dump-times {\.REDUC_MAX} 1 "forwprop4" } } */
+/* { dg-final { scan-tree-dump-times {\.REDUC_MIN} 1 "forwprop4" } } */
+/* { dg-final { scan-tree-dump-times {\.REDUC_AND} 1 "forwprop4" } } */
+/* { dg-final { scan-tree-dump-times {\.REDUC_IOR} 1 "forwprop4" } } */
+/* { dg-final { scan-tree-dump-times {\.REDUC_MAX \(vect_rmax_lsm} 1 
"forwprop4" } } */
+/* { dg-final { scan-tree-dump-times {\.REDUC_MIN \(vect_rmin_lsm} 1 
"forwprop4" } } */
+/* { dg-final { scan-tree-dump-times {\.REDUC_AND \(vect_r_and_lsm} 1 
"forwprop4" } } */
+/* { dg-final { scan-tree-dump-times {\.REDUC_IOR \(vect_r_ior_lsm} 1 
"forwprop4" } } */
+/* { dg-final { scan-tree-dump-times {\.REDUC_XOR} 5 "forwprop4" } } */
+/* { dg-final { scan-tree-dump-not {\.REDUC_XOR \(\{ 0, \.\.\. \}\)} 
"forwprop4" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/vec-reduc-splat-float-1.c 
b/gcc/testsuite/gcc.target/aarch64/vec-reduc-splat-float-1.c
new file mode 100644
index 00000000000..ca0764997a0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/vec-reduc-splat-float-1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fgimple -fsignaling-nans -fdump-tree-forwprop1" } */
+
+/* Keep reductions of a splat that can contain a signaling NaN.  */
+
+typedef float v4sf __attribute__ ((vector_size (16)));
+
+float __GIMPLE ()
+reduc_max (float x)
+{
+  v4sf v;
+  float res;
+
+  v = _Literal (v4sf) { x, x, x, x };
+  res = .REDUC_MAX (v);
+  return res;
+}
+
+float __GIMPLE ()
+reduc_min (float x)
+{
+  v4sf v;
+  float res;
+
+  v = _Literal (v4sf) { x, x, x, x };
+  res = .REDUC_MIN (v);
+  return res;
+}
+
+/* { dg-final { scan-tree-dump-times {\.REDUC_MAX} 1 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times {\.REDUC_MIN} 1 "forwprop1" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/reduc-xor-uniform-1.c 
b/gcc/testsuite/gcc.target/riscv/rvv/base/reduc-xor-uniform-1.c
new file mode 100644
index 00000000000..54339490fd8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/reduc-xor-uniform-1.c
@@ -0,0 +1,47 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fgimple -march=rv64im_zve64f -mabi=lp64 
-fdump-tree-forwprop1" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "riscv_vector.h"
+
+/*
+** reduc_xor_even:
+**     li      a0,0
+**     ret
+*/
+long __GIMPLE ()
+reduc_xor_even (void)
+{
+  vbool32_t mask;
+  vint64m2_t ones;
+  long res;
+
+  mask = _Literal (vint64m2_t) 0 == _Literal (vint64m2_t) 0;
+  ones = .VEC_CONVERT (mask);
+  res = .REDUC_XOR (ones);
+  return res;
+}
+
+/*
+** reduc_xor_unknown:
+**     vsetvli [a-x0-9]+,zero,e64,m1,ta,ma
+**     ...
+**     vredxor\.vs     v[0-9]+,v[0-9]+,v[0-9]+
+**     ...
+**     ret
+*/
+long __GIMPLE ()
+reduc_xor_unknown (void)
+{
+  vbool64_t mask;
+  vint64m1_t ones;
+  long res;
+
+  mask = _Literal (vint64m1_t) 0 == _Literal (vint64m1_t) 0;
+  ones = .VEC_CONVERT (mask);
+  res = .REDUC_XOR (ones);
+  return res;
+}
+
+/* { dg-final { scan-tree-dump-times {\.REDUC_XOR} 1 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times {return 0;} 1 "forwprop1" } } */
-- 
2.50.1 (Apple Git-155)

Reply via email to