Hi,

Attached is the respun version of the patch,

> >>
> >> Wouldn't a target need to re-check if lanes are NaN or denormal if
> >> after a SFmode lane operation a DFmode lane operation follows?  IIRC
> >> that is what usually makes punning "integer" vectors as FP vectors costly.

I don't believe this is a problem, due to NANs not being a single value and
according to the standard the sign bit doesn't change the meaning of a NAN.

That's why specifically for negates generally no check is performed and it's
Assumed that if a value is a NaN going in, it's a NaN coming out, and this
Optimization doesn't change that.  Also under fast-math we don't guarantee
a stable representation for NaN (or zeros, etc) afaik.

So if that is still a concern I could add && !HONORS_NAN () to the constraints.

Bootstrapped Regtested on aarch64-none-linux-gnu and no issues.

Ok for master?

Thanks,
Tamar

gcc/ChangeLog:

        * match.pd: Add fneg/fadd rule.

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/simd/addsub_1.c: New test.
        * gcc.target/aarch64/sve/addsub_1.c: New test.

--- inline version of patch ---

diff --git a/gcc/match.pd b/gcc/match.pd
index 
1bb936fc4010f98f24bb97671350e8432c55b347..2617d56091dfbd41ae49f980ee0af3757f5ec1cf
 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -7916,6 +7916,59 @@ and,
   (simplify (reduc (op @0 VECTOR_CST@1))
     (op (reduc:type @0) (reduc:type @1))))
 
+/* Simplify vector floating point operations of alternating sub/add pairs
+   into using an fneg of a wider element type followed by a normal add.
+   under IEEE 754 the fneg of the wider type will negate every even entry
+   and when doing an add we get a sub of the even and add of every odd
+   elements.  */
+(simplify
+ (vec_perm (plus:c @0 @1) (minus @0 @1) VECTOR_CST@2)
+ (if (!VECTOR_INTEGER_TYPE_P (type) && !BYTES_BIG_ENDIAN)
+  (with
+   {
+     /* Build a vector of integers from the tree mask.  */
+     vec_perm_builder builder;
+     if (!tree_to_vec_perm_builder (&builder, @2))
+       return NULL_TREE;
+
+     /* Create a vec_perm_indices for the integer vector.  */
+     poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (type);
+     vec_perm_indices sel (builder, 2, nelts);
+   }
+   (if (sel.series_p (0, 2, 0, 2))
+    (with
+     {
+       machine_mode vec_mode = TYPE_MODE (type);
+       auto elem_mode = GET_MODE_INNER (vec_mode);
+       auto nunits = exact_div (GET_MODE_NUNITS (vec_mode), 2);
+       tree stype;
+       switch (elem_mode)
+        {
+        case E_HFmode:
+          stype = float_type_node;
+          break;
+        case E_SFmode:
+          stype = double_type_node;
+          break;
+        default:
+          return NULL_TREE;
+        }
+       tree ntype = build_vector_type (stype, nunits);
+       if (!ntype)
+        return NULL_TREE;
+
+       /* The format has to have a simple sign bit.  */
+       const struct real_format *fmt = FLOAT_MODE_FORMAT (vec_mode);
+       if (fmt == NULL)
+        return NULL_TREE;
+     }
+     (if (fmt->signbit_rw == GET_MODE_UNIT_BITSIZE (vec_mode) - 1
+         && fmt->signbit_rw == fmt->signbit_ro
+         && targetm.can_change_mode_class (TYPE_MODE (ntype), TYPE_MODE 
(type), ALL_REGS)
+         && (optimize_vectors_before_lowering_p ()
+             || target_supports_op_p (ntype, NEGATE_EXPR, optab_vector)))
+      (plus (view_convert:type (negate (view_convert:ntype @1))) @0)))))))
+
 (simplify
  (vec_perm @0 @1 VECTOR_CST@2)
  (with
diff --git a/gcc/testsuite/gcc.target/aarch64/simd/addsub_1.c 
b/gcc/testsuite/gcc.target/aarch64/simd/addsub_1.c
new file mode 100644
index 
0000000000000000000000000000000000000000..1fb91a34c421bbd2894faa0dbbf1b47ad43310c4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/simd/addsub_1.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_v8_2a_fp16_neon_ok } */
+/* { dg-options "-Ofast" } */
+/* { dg-add-options arm_v8_2a_fp16_neon } */
+/* { dg-final { check-function-bodies "**" "" "" { target { le } } } } */
+
+#pragma GCC target "+nosve"
+
+/* 
+** f1:
+** ...
+**     fneg    v[0-9]+.2d, v[0-9]+.2d
+**     fadd    v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s
+** ...
+*/
+void f1 (float *restrict a, float *restrict b, float *res, int n)
+{
+   for (int i = 0; i < (n & -4); i+=2)
+    {
+      res[i+0] = a[i+0] + b[i+0];
+      res[i+1] = a[i+1] - b[i+1];
+    }
+}
+
+/* 
+** d1:
+** ...
+**     fneg    v[0-9]+.4s, v[0-9]+.4s
+**     fadd    v[0-9]+.8h, v[0-9]+.8h, v[0-9]+.8h
+** ...
+*/
+void d1 (_Float16 *restrict a, _Float16 *restrict b, _Float16 *res, int n)
+{
+   for (int i = 0; i < (n & -8); i+=2)
+    {
+      res[i+0] = a[i+0] + b[i+0];
+      res[i+1] = a[i+1] - b[i+1];
+    }
+}
+
+/* 
+** e1:
+** ...
+**     fadd    v[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d
+**     fsub    v[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d
+**     ins     v[0-9]+.d\[1\], v[0-9]+.d\[1\]
+** ...
+*/
+void e1 (double *restrict a, double *restrict b, double *res, int n)
+{
+   for (int i = 0; i < (n & -4); i+=2)
+    {
+      res[i+0] = a[i+0] + b[i+0];
+      res[i+1] = a[i+1] - b[i+1];
+    }
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/addsub_1.c 
b/gcc/testsuite/gcc.target/aarch64/sve/addsub_1.c
new file mode 100644
index 
0000000000000000000000000000000000000000..ea7f9d9db2c8c9a3efe5c7951a314a29b7a7a922
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/addsub_1.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-Ofast" } */
+/* { dg-final { check-function-bodies "**" "" "" { target { le } } } } */
+
+/*
+** f1:
+** ...
+**     fneg    z[0-9]+.d, p[0-9]+/m, z[0-9]+.d
+**     fadd    z[0-9]+.s, z[0-9]+.s, z[0-9]+.s
+** ...
+*/
+void f1 (float *restrict a, float *restrict b, float *res, int n)
+{
+   for (int i = 0; i < (n & -4); i+=2)
+    {
+      res[i+0] = a[i+0] + b[i+0];
+      res[i+1] = a[i+1] - b[i+1];
+    }
+}
+
+/* 
+** d1:
+** ...
+**     fneg    z[0-9]+.s, p[0-9]+/m, z[0-9]+.s
+**     fadd    z[0-9]+.h, z[0-9]+.h, z[0-9]+.h
+** ...
+*/ 
+void d1 (_Float16 *restrict a, _Float16 *restrict b, _Float16 *res, int n)
+{
+   for (int i = 0; i < (n & -8); i+=2)
+    {
+      res[i+0] = a[i+0] + b[i+0];
+      res[i+1] = a[i+1] - b[i+1];
+    }
+}
+
+/*
+** e1:
+** ...
+**     fsub    z[0-9]+.d, z[0-9]+.d, z[0-9]+.d
+**     movprfx z[0-9]+.d, p[0-9]+/m, z[0-9]+.d
+**     fadd    z[0-9]+.d, p[0-9]+/m, z[0-9]+.d, z[0-9]+.d
+** ...
+*/
+void e1 (double *restrict a, double *restrict b, double *res, int n)
+{
+   for (int i = 0; i < (n & -4); i+=2)
+    {
+      res[i+0] = a[i+0] + b[i+0];
+      res[i+1] = a[i+1] - b[i+1];
+    }
+}

Attachment: rb15819.patch
Description: rb15819.patch

Reply via email to