Port the `vabs` family of NEON intrinsics to the pragma-based framework,
and add assembly tests for every variant.

This also makes the `__builtin_aarch64_abs<mode>` builtin functions
obsolete, so they have been deleted too.

gcc/ChangeLog:

        * config/aarch64/aarch64-builtins.cc
        (aarch64_general_fold_builtin): Delete case to handle `abs`.
        * config/aarch64/aarch64-neon-builtins-base.cc (vabsd, vabsh,
        vabs, vabsq): New function bases.
        * config/aarch64/aarch64-neon-builtins-base.def (vabsd): (vabs):
        (vabsq): (vabsh): New function declarations.
        * config/aarch64/aarch64-simd-builtins.def: Delete `abs` builtin
        functions.
        * config/aarch64/aarch64-simd.md
        (aarch64_abs<mode><vczle><vczbe>): Replace UNSPEC_ABS with abs
        expression.
        (aarch64_abs_plus<mode>): Likewise.
        * config/aarch64/iterators.md (UNSPEC_ABS): Delete unspec.
        * config/aarch64/arm_neon.h (vabs_f32, vabs_f64, vabs_s8,
        vabs_s16, vabs_s32, vabs_s64, vabsq_f32, vabsq_f64, vabsq_s8,
        vabsq_s16, vabsq_s32, vabsq_s64, vabsd_s64, vabs_f16,
        vabsq_f16): Delete function definitions.
        * config/aarch64/arm_fp16.h (vabsh_f16): Use `__builtin_fabs`
        instead of `__builtin_aarch64_abshf` now that the latter has
        been deleted.

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/neon/vabs.c: New test.
        * gcc.target/aarch64/singleton_intrinsics_1.c: Mark `vabs_s64`
        test as `xfail` because of codegen regression.
        * gcc.target/aarch64/vabs_intrinsic_1.c: Fix test. The `asm
        volatile` trick for disabling constant folding stopped
        working. Replace with declaring variables `volatile`.
---
 gcc/config/aarch64/aarch64-builtins.cc        |   2 -
 .../aarch64/aarch64-neon-builtins-base.cc     |  23 ++++
 .../aarch64/aarch64-neon-builtins-base.def    |  11 ++
 gcc/config/aarch64/aarch64-simd-builtins.def  |   6 -
 gcc/config/aarch64/aarch64-simd.md            |  18 +--
 gcc/config/aarch64/arm_fp16.h                 |   2 +-
 gcc/config/aarch64/arm_neon.h                 | 112 -----------------
 gcc/config/aarch64/iterators.md               |   1 -
 gcc/testsuite/gcc.target/aarch64/neon/vabs.c  | 116 ++++++++++++++++++
 .../aarch64/singleton_intrinsics_1.c          |   2 +-
 .../gcc.target/aarch64/vabs_intrinsic_1.c     |   9 +-
 11 files changed, 157 insertions(+), 145 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/neon/vabs.c

diff --git a/gcc/config/aarch64/aarch64-builtins.cc 
b/gcc/config/aarch64/aarch64-builtins.cc
index 8cd1bc4b1a2..9be4e21a213 100644
--- a/gcc/config/aarch64/aarch64-builtins.cc
+++ b/gcc/config/aarch64/aarch64-builtins.cc
@@ -4503,8 +4503,6 @@ aarch64_general_fold_builtin (unsigned int fcode, tree 
type,
 {
   switch (fcode)
     {
-      BUILTIN_VDQF (UNOP, abs, 2, ALL)
-       return fold_build1 (ABS_EXPR, type, args[0]);
       VAR1 (UNOP, floatv2si, 2, ALL, v2sf)
       VAR1 (UNOP, floatv4si, 2, ALL, v4sf)
       VAR1 (UNOP, floatv2di, 2, ALL, v2df)
diff --git a/gcc/config/aarch64/aarch64-neon-builtins-base.cc 
b/gcc/config/aarch64/aarch64-neon-builtins-base.cc
index c9bfc8d8eff..ac9b27666a4 100644
--- a/gcc/config/aarch64/aarch64-neon-builtins-base.cc
+++ b/gcc/config/aarch64/aarch64-neon-builtins-base.cc
@@ -775,6 +775,24 @@ struct gimple_reinterpret : public gimple_function_base
   }
 };
 
+struct gimple_abs : public gimple_function_base
+{
+  gimple *fold (gimple_folder &f) const override
+  {
+    auto arg = gimple_call_arg (f.call, 0);
+    auto arg_type = TREE_TYPE (arg);
+    auto unsigned_type = unsigned_type_for (arg_type);
+
+    if (FLOAT_TYPE_P (arg_type))
+      return gimple_build_assign (f.lhs, fold_build1 (ABS_EXPR, arg_type, 
arg));
+    else
+      return gimple_build_assign (
+       f.lhs,
+       build_cast (arg_type,
+                   f.force_val (fold_build1 (ABSU_EXPR, unsigned_type, arg))));
+  }
+};
+
 // Reinterpret
 NEON_FUNCTION (vreinterpret,  gimple_reinterpret,)
 NEON_FUNCTION (vreinterpretq, gimple_reinterpret,)
@@ -827,6 +845,11 @@ NEON_FUNCTION (vnegd, gimple_arith, (NEGATE_EXPR))
 NEON_FUNCTION (vneg,  gimple_arith, (NEGATE_EXPR))
 NEON_FUNCTION (vnegq, gimple_arith, (NEGATE_EXPR))
 
+// Absolute value
+NEON_FUNCTION (vabsd, gimple_abs,)
+NEON_FUNCTION (vabs,  gimple_abs,)
+NEON_FUNCTION (vabsq, gimple_abs,)
+
 // Bitwise operations
 NEON_FUNCTION (vand,   gimple_expr,    (BIT_AND_EXPR))
 NEON_FUNCTION (vandq,  gimple_expr,    (BIT_AND_EXPR))
diff --git a/gcc/config/aarch64/aarch64-neon-builtins-base.def 
b/gcc/config/aarch64/aarch64-neon-builtins-base.def
index dc8653ac05b..3dd7763a67d 100644
--- a/gcc/config/aarch64/aarch64-neon-builtins-base.def
+++ b/gcc/config/aarch64/aarch64-neon-builtins-base.def
@@ -93,6 +93,13 @@ DEF_NEON_FUNCTION (vneg,  all_signed, ("D0,D0"))
 DEF_NEON_FUNCTION (vnegq, all_signed, ("Q0,Q0"))
 DEF_NEON_FUNCTION (vneg,  sd_float,   ("D0,D0"))
 DEF_NEON_FUNCTION (vnegq, sd_float,   ("Q0,Q0"))
+
+// Absolute value
+DEF_NEON_FUNCTION (vabsd, d_signed,   ("s0,s0"))
+DEF_NEON_FUNCTION (vabs,  all_signed, ("D0,D0"))
+DEF_NEON_FUNCTION (vabsq, all_signed, ("Q0,Q0"))
+DEF_NEON_FUNCTION (vabs,  sd_float,   ("D0,D0"))
+DEF_NEON_FUNCTION (vabsq, sd_float,   ("Q0,Q0"))
 #undef REQUIRED_EXTENSIONS
 
 // Lanewise arithmetic (FP16)
@@ -116,6 +123,10 @@ DEF_NEON_FUNCTION (vdivq, h_float, ("Q0,Q0,Q0"))
 // Negation
 DEF_NEON_FUNCTION (vneg,  h_float, ("D0,D0"))
 DEF_NEON_FUNCTION (vnegq, h_float, ("Q0,Q0"))
+
+// Absolute value
+DEF_NEON_FUNCTION (vabs,  h_float, ("D0,D0"))
+DEF_NEON_FUNCTION (vabsq, h_float, ("Q0,Q0"))
 #undef REQUIRED_EXTENSIONS
 
 // Bitwise operations
diff --git a/gcc/config/aarch64/aarch64-simd-builtins.def 
b/gcc/config/aarch64/aarch64-simd-builtins.def
index 9c61cc05a05..ff6ced34deb 100644
--- a/gcc/config/aarch64/aarch64-simd-builtins.def
+++ b/gcc/config/aarch64/aarch64-simd-builtins.def
@@ -668,12 +668,6 @@
   BUILTIN_VHSDF (UNOP, frecpe, 0, FP)
   BUILTIN_VHSDF_HSDF (BINOP, frecps, 0, FP)
 
-  /* Implemented by a mixture of abs2 patterns.  Note the DImode builtin is
-     only ever used for the int64x1_t intrinsic, there is no scalar version.  
*/
-  BUILTIN_VSDQ_I_DI (UNOP, abs, 0, QUIET)
-  BUILTIN_VHSDF (UNOP, abs, 2, QUIET)
-  VAR1 (UNOP, abs, 2, QUIET, hf)
-
   BUILTIN_VQ_HSF (UNOP, vec_unpacks_hi_, 10, FP)
   VAR1 (BINOP, float_truncate_hi_, 0, FP, v4sf)
   VAR1 (BINOP, float_truncate_hi_, 0, FP, v8hf)
diff --git a/gcc/config/aarch64/aarch64-simd.md 
b/gcc/config/aarch64/aarch64-simd.md
index e91692ce486..26e1214928b 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -974,19 +974,6 @@ (define_insn "abs<mode>2<vczle><vczbe>"
   [(set_attr "type" "neon_abs<q>")]
 )
 
-;; The intrinsic version of integer ABS must not be allowed to
-;; combine with any operation with an integrated ABS step, such
-;; as SABD.
-(define_insn "aarch64_abs<mode><vczle><vczbe>"
-  [(set (match_operand:VSDQ_I_DI 0 "register_operand" "=w")
-         (unspec:VSDQ_I_DI
-           [(match_operand:VSDQ_I_DI 1 "register_operand" "w")]
-          UNSPEC_ABS))]
-  "TARGET_SIMD"
-  "abs\t%<v>0<Vmtype>, %<v>1<Vmtype>"
-  [(set_attr "type" "neon_abs<q>")]
-)
-
 ;; It's tempting to represent SABD as ABS (MINUS op1 op2).
 ;; This isn't accurate as ABS treats always its input as a signed value.
 ;; So (ABS:QI (minus:QI 64 -128)) == (ABS:QI (192 or -64 signed)) == 64.
@@ -1303,9 +1290,8 @@ (define_insn "aarch64_<su>aba<mode><vczle><vczbe>"
 (define_insn_and_split "*aarch64_abs_plus<mode>"
   [(set (match_operand:VDQ_BHSI 0 "register_operand" "=&w")
        (plus:VDQ_BHSI
-         (unspec:VDQ_BHSI
-           [(match_operand:VDQ_BHSI 1 "register_operand" "w")]
-           UNSPEC_ABS)
+         (abs:VDQ_BHSI
+           (match_operand:VDQ_BHSI 1 "register_operand" "w"))
          (match_operand:VDQ_BHSI 2 "register_operand" "w")))]
   "TARGET_SIMD && can_create_pseudo_p ()"
   "#"
diff --git a/gcc/config/aarch64/arm_fp16.h b/gcc/config/aarch64/arm_fp16.h
index c6356fdc78b..f67a9e19988 100644
--- a/gcc/config/aarch64/arm_fp16.h
+++ b/gcc/config/aarch64/arm_fp16.h
@@ -40,7 +40,7 @@ __extension__ extern __inline float16_t
 __attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
 vabsh_f16 (float16_t __a)
 {
-  return __builtin_aarch64_abshf (__a);
+  return __builtin_fabs (__a);
 }
 
 __extension__ extern __inline uint16_t
diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h
index 5c1a145f72e..b4ce93f8219 100644
--- a/gcc/config/aarch64/arm_neon.h
+++ b/gcc/config/aarch64/arm_neon.h
@@ -4901,104 +4901,6 @@ vabdq_f64 (float64x2_t __a, float64x2_t __b)
   return __builtin_aarch64_fabdv2df (__a, __b);
 }
 
-/* vabs  */
-
-__extension__ extern __inline float32x2_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabs_f32 (float32x2_t __a)
-{
-  return __builtin_aarch64_absv2sf (__a);
-}
-
-__extension__ extern __inline float64x1_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabs_f64 (float64x1_t __a)
-{
-  return (float64x1_t) {__builtin_fabs (__a[0])};
-}
-
-__extension__ extern __inline int8x8_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabs_s8 (int8x8_t __a)
-{
-  return __builtin_aarch64_absv8qi (__a);
-}
-
-__extension__ extern __inline int16x4_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabs_s16 (int16x4_t __a)
-{
-  return __builtin_aarch64_absv4hi (__a);
-}
-
-__extension__ extern __inline int32x2_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabs_s32 (int32x2_t __a)
-{
-  return __builtin_aarch64_absv2si (__a);
-}
-
-__extension__ extern __inline int64x1_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabs_s64 (int64x1_t __a)
-{
-  return (int64x1_t) {__builtin_aarch64_absdi (__a[0])};
-}
-
-__extension__ extern __inline float32x4_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabsq_f32 (float32x4_t __a)
-{
-  return __builtin_aarch64_absv4sf (__a);
-}
-
-__extension__ extern __inline float64x2_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabsq_f64 (float64x2_t __a)
-{
-  return __builtin_aarch64_absv2df (__a);
-}
-
-__extension__ extern __inline int8x16_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabsq_s8 (int8x16_t __a)
-{
-  return __builtin_aarch64_absv16qi (__a);
-}
-
-__extension__ extern __inline int16x8_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabsq_s16 (int16x8_t __a)
-{
-  return __builtin_aarch64_absv8hi (__a);
-}
-
-__extension__ extern __inline int32x4_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabsq_s32 (int32x4_t __a)
-{
-  return __builtin_aarch64_absv4si (__a);
-}
-
-__extension__ extern __inline int64x2_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabsq_s64 (int64x2_t __a)
-{
-  return __builtin_aarch64_absv2di (__a);
-}
-
-/* Try to avoid moving between integer and vector registers.
-   For why the cast to unsigned is needed check the vnegd_s64 intrinsic.
-   There is a testcase related to this issue:
-   gcc.target/aarch64/vabsd_s64.c.  */
-
-__extension__ extern __inline int64_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabsd_s64 (int64_t __a)
-{
-  return __a < 0 ? - (uint64_t) __a : __a;
-}
-
 /* vaddv */
 
 __extension__ extern __inline int8_t
@@ -19356,20 +19258,6 @@ vuqaddd_s64 (int64_t __a, uint64_t __b)
 
 /* ARMv8.2-A FP16 one operand vector intrinsics.  */
 
-__extension__ extern __inline float16x4_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabs_f16 (float16x4_t __a)
-{
-  return __builtin_aarch64_absv4hf (__a);
-}
-
-__extension__ extern __inline float16x8_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vabsq_f16 (float16x8_t __a)
-{
-  return __builtin_aarch64_absv8hf (__a);
-}
-
 __extension__ extern __inline uint16x4_t
 __attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
 vceqz_f16 (float16x4_t __a)
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 1bc20d6151c..859f7a5b45a 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -868,7 +868,6 @@ (define_c_enum "unspec"
  [
     UNSPEC_ASHIFT_SIGNED       ; Used in aarch-simd.md.
     UNSPEC_ASHIFT_UNSIGNED     ; Used in aarch64-simd.md.
-    UNSPEC_ABS         ; Used in aarch64-simd.md.
     UNSPEC_FCVTN_FP8   ; Used in aarch64-simd.md.
     UNSPEC_FCVTN2_FP8  ; Used in aarch64-builtins.cc.
     UNSPEC_F1CVTL_FP8  ; Used in aarch64-simd.md.
diff --git a/gcc/testsuite/gcc.target/aarch64/neon/vabs.c 
b/gcc/testsuite/gcc.target/aarch64/neon/vabs.c
new file mode 100644
index 00000000000..3c9db51fdf0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/neon/vabs.c
@@ -0,0 +1,116 @@
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "arm_neon_test.h"
+
+/*
+** test_vabs_f32:
+** fabs        v0\.2s, v0\.2s
+** ret
+*/
+TEST_UNIFORM_UNARY (vabs_f32, float32x2_t)
+
+/*
+** test_vabs_f64:
+** fabs        d0, d0
+** ret
+*/
+TEST_UNIFORM_UNARY (vabs_f64, float64x1_t)
+
+/*
+** test_vabs_s8:
+** abs v0\.8b, v0\.8b
+** ret
+*/
+TEST_UNIFORM_UNARY (vabs_s8, int8x8_t)
+
+/*
+** test_vabs_s16:
+** abs v0\.4h, v0\.4h
+** ret
+*/
+TEST_UNIFORM_UNARY (vabs_s16, int16x4_t)
+
+/*
+** test_vabs_s32:
+** abs v0\.2s, v0\.2s
+** ret
+*/
+TEST_UNIFORM_UNARY (vabs_s32, int32x2_t)
+
+// FIXME: Performs abs in scalar register, even though it requires extra moves:
+// fmov        x31, d0
+// cmp x31, #?0
+// csneg       x31, x31, x31, ge
+// fmov        d0, x31
+
+/*
+** test_vabs_s64: { xfail *-*-* }
+** abs d0, d0
+** ret
+*/
+TEST_UNIFORM_UNARY (vabs_s64, int64x1_t)
+
+/*
+** test_vabsd_s64:
+** cmp x0, #?0
+** csneg       x0, x0, x0, ge
+** ret
+*/
+TEST_UNIFORM_UNARY (vabsd_s64, int64_t)
+
+/*
+** test_vabsq_f32:
+** fabs        v0\.4s, v0\.4s
+** ret
+*/
+TEST_UNIFORM_UNARY (vabsq_f32, float32x4_t)
+
+/*
+** test_vabsq_f64:
+** fabs        v0\.2d, v0\.2d
+** ret
+*/
+TEST_UNIFORM_UNARY (vabsq_f64, float64x2_t)
+
+/*
+** test_vabsq_s8:
+** abs v0\.16b, v0\.16b
+** ret
+*/
+TEST_UNIFORM_UNARY (vabsq_s8, int8x16_t)
+
+/*
+** test_vabsq_s16:
+** abs v0\.8h, v0\.8h
+** ret
+*/
+TEST_UNIFORM_UNARY (vabsq_s16, int16x8_t)
+
+/*
+** test_vabsq_s32:
+** abs v0\.4s, v0\.4s
+** ret
+*/
+TEST_UNIFORM_UNARY (vabsq_s32, int32x4_t)
+
+/*
+** test_vabsq_s64:
+** abs v0\.2d, v0\.2d
+** ret
+*/
+TEST_UNIFORM_UNARY (vabsq_s64, int64x2_t)
+
+/*
+** test_vabs_f16:
+** fabs        v0\.4h, v0\.4h
+** ret
+*/
+TEST_UNIFORM_UNARY (vabs_f16, float16x4_t)
+
+/*
+** test_vabsq_f16:
+** fabs        v0\.8h, v0\.8h
+** ret
+*/
+TEST_UNIFORM_UNARY (vabsq_f16, float16x8_t)
diff --git a/gcc/testsuite/gcc.target/aarch64/singleton_intrinsics_1.c 
b/gcc/testsuite/gcc.target/aarch64/singleton_intrinsics_1.c
index 27360150b58..afa07c9c5fb 100644
--- a/gcc/testsuite/gcc.target/aarch64/singleton_intrinsics_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/singleton_intrinsics_1.c
@@ -19,7 +19,7 @@ test_vadd_s64 (int64x1_t a, int64x1_t b)
   return vadd_s64 (a, b);
 }
 
-/* { dg-final { scan-assembler-times "\\tabs\\td\[0-9\]+, d\[0-9\]+" 1 } } */
+/* { dg-final { scan-assembler-times "\\tabs\\td\[0-9\]+, d\[0-9\]+" 1 } { 
xfail *-*-* } } */
 
 int64x1_t
 test_vabs_s64 (int64x1_t a)
diff --git a/gcc/testsuite/gcc.target/aarch64/vabs_intrinsic_1.c 
b/gcc/testsuite/gcc.target/aarch64/vabs_intrinsic_1.c
index b18db7ec641..f21771bfe89 100644
--- a/gcc/testsuite/gcc.target/aarch64/vabs_intrinsic_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/vabs_intrinsic_1.c
@@ -13,8 +13,9 @@ static void                                                   
\
 test_vabs##q##_##size (ETYPE (size) * res,                     \
                        const ETYPE (size) *in1)                \
 {                                                              \
-  VTYPE (size, lanes) a = vld1##q##_s##size (res);             \
-  VTYPE (size, lanes) b = vld1##q##_s##size (in1);             \
+  /* Use volatile to prevent constant folding.  */             \
+  volatile VTYPE (size, lanes) a = vld1##q##_s##size (res);    \
+  volatile VTYPE (size, lanes) b = vld1##q##_s##size (in1);    \
   a = vabs##q##_s##size (b);                                   \
   vst1##q##_s##size (res, a);                                  \
 }
@@ -54,15 +55,11 @@ test_##size (void)                                          
\
   ETYPE (size) res2[lanes_128] = {0};                          \
   ETYPE (size) expected2[lanes_128] = EXPECTED##lanes_128;     \
                                                                \
-  /* Forcefully avoid optimization.  */                                \
-  asm volatile ("" : : : "memory");                            \
   test_vabs_##size (res1, pool1);                              \
   for (i = 0; i < lanes_64; i++)                               \
     if (res1[i] != expected1[i])                               \
       abort ();                                                        \
                                                                \
-  /* Forcefully avoid optimization.  */                                \
-  asm volatile ("" : : : "memory");                            \
   test_vabsq_##size (res2, pool2);                             \
   for (i = 0; i < lanes_128; i++)                              \
     if (res2[i] != expected2[i])                               \
-- 
2.51.0

Reply via email to