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

gcc/ChangeLog:

        * config/aarch64/aarch64-neon-builtins-base.cc (vnegd, vnegh,
        vneg, vnegq): New function bases.
        * config/aarch64/aarch64-neon-builtins-base.def
        (vnegd, vneg, vnegq, vnegh): New function declarations.
        * config/aarch64/aarch64-acle-builtins.h (TYPES_d_signed): New
        type array.
        * config/aarch64/arm_neon.h (vneg_f32, vneg_f64, vneg_s8,
        vneg_s16, vneg_s32, vneg_s64, vnegd_s64, vnegq_f32, vnegq_f64,
        vnegq_s8, vnegq_s16, vnegq_s32, vnegq_s64, vneg_f16,
        vnegq_f16): Delete function definitions.

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/neon/vneg.c: New test.
        * gcc.target/aarch64/signbit-2.c: Fix test.
        This is a codegen regression: since `vneg` on `INT_MIN` is no
        longer UB, it is not correct to replace a `vneg` and a `vshr_n`
        with a `vcgt` comparison.
---
 gcc/config/aarch64/aarch64-acle-builtins.h    |   5 +
 .../aarch64/aarch64-neon-builtins-base.cc     |   5 +
 .../aarch64/aarch64-neon-builtins-base.def    |  11 ++
 gcc/config/aarch64/arm_neon.h                 | 119 ------------------
 gcc/testsuite/gcc.target/aarch64/neon/vneg.c  | 109 ++++++++++++++++
 gcc/testsuite/gcc.target/aarch64/signbit-2.c  |   2 +-
 6 files changed, 131 insertions(+), 120 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/neon/vneg.c

diff --git a/gcc/config/aarch64/aarch64-acle-builtins.h 
b/gcc/config/aarch64/aarch64-acle-builtins.h
index 8dd5e138719..bbdfd7cb230 100644
--- a/gcc/config/aarch64/aarch64-acle-builtins.h
+++ b/gcc/config/aarch64/aarch64-acle-builtins.h
@@ -1439,6 +1439,10 @@ function_expander::result_mode () const
 #define TYPES_d_float(S, D, T) \
   S (f64)
 
+/* _s64.  */
+#define TYPES_d_signed(S, D, T) \
+  S (s64)
+
 /* _u64.  */
 #define TYPES_d_unsigned(S, D, T) \
   S (u64)
@@ -2046,6 +2050,7 @@ DEF_SVE_TYPES_ARRAY (sd_integer);
 DEF_SVE_TYPES_ARRAY (sd_data);
 DEF_SVE_TYPES_ARRAY (all_float_and_sd_integer);
 DEF_SVE_TYPES_ARRAY (d_float);
+DEF_SVE_TYPES_ARRAY (d_signed);
 DEF_SVE_TYPES_ARRAY (d_unsigned);
 DEF_SVE_TYPES_ARRAY (d_integer);
 DEF_SVE_TYPES_ARRAY (d_data);
diff --git a/gcc/config/aarch64/aarch64-neon-builtins-base.cc 
b/gcc/config/aarch64/aarch64-neon-builtins-base.cc
index c367ed7a937..c9bfc8d8eff 100644
--- a/gcc/config/aarch64/aarch64-neon-builtins-base.cc
+++ b/gcc/config/aarch64/aarch64-neon-builtins-base.cc
@@ -822,6 +822,11 @@ NEON_FUNCTION (vmulq, gimple_arith, (MULT_EXPR))
 NEON_FUNCTION (vdiv,  gimple_arith, (RDIV_EXPR))
 NEON_FUNCTION (vdivq, gimple_arith, (RDIV_EXPR))
 
+// Negation
+NEON_FUNCTION (vnegd, gimple_arith, (NEGATE_EXPR))
+NEON_FUNCTION (vneg,  gimple_arith, (NEGATE_EXPR))
+NEON_FUNCTION (vnegq, gimple_arith, (NEGATE_EXPR))
+
 // 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 828dd0c7e80..dc8653ac05b 100644
--- a/gcc/config/aarch64/aarch64-neon-builtins-base.def
+++ b/gcc/config/aarch64/aarch64-neon-builtins-base.def
@@ -86,6 +86,13 @@ DEF_NEON_FUNCTION (vmulq, sd_float,    ("Q0,Q0,Q0"))
 // Division
 DEF_NEON_FUNCTION (vdiv,  sd_float, ("D0,D0,D0"))
 DEF_NEON_FUNCTION (vdivq, sd_float, ("Q0,Q0,Q0"))
+
+// Negation
+DEF_NEON_FUNCTION (vnegd, d_signed,   ("s0,s0"))
+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"))
 #undef REQUIRED_EXTENSIONS
 
 // Lanewise arithmetic (FP16)
@@ -105,6 +112,10 @@ DEF_NEON_FUNCTION (vmulq, h_float, ("Q0,Q0,Q0"))
 // Division
 DEF_NEON_FUNCTION (vdiv,  h_float, ("D0,D0,D0"))
 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"))
 #undef REQUIRED_EXTENSIONS
 
 // Bitwise operations
diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h
index b896fed7e3f..5c1a145f72e 100644
--- a/gcc/config/aarch64/arm_neon.h
+++ b/gcc/config/aarch64/arm_neon.h
@@ -13406,111 +13406,6 @@ vmulq_n_u32 (uint32x4_t __a, uint32_t __b)
   return __a * __b;
 }
 
-/* vneg  */
-
-__extension__ extern __inline float32x2_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vneg_f32 (float32x2_t __a)
-{
-  return -__a;
-}
-
-__extension__ extern __inline float64x1_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vneg_f64 (float64x1_t __a)
-{
-  return -__a;
-}
-
-__extension__ extern __inline int8x8_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vneg_s8 (int8x8_t __a)
-{
-  return -__a;
-}
-
-__extension__ extern __inline int16x4_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vneg_s16 (int16x4_t __a)
-{
-  return -__a;
-}
-
-__extension__ extern __inline int32x2_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vneg_s32 (int32x2_t __a)
-{
-  return -__a;
-}
-
-__extension__ extern __inline int64x1_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vneg_s64 (int64x1_t __a)
-{
-  return -__a;
-}
-
-/* According to the ACLE, the negative of the minimum (signed)
-   value is itself.  This leads to a semantics mismatch, as this is
-   undefined behaviour in C.  The value range predictor is not
-   aware that the negation of a negative number can still be negative
-   and it may try to fold the expression.  See the test in
-   gcc.target/aarch64/vnegd_s64.c for an example.
-
-   The cast below tricks the value range predictor to include
-   INT64_MIN in the range it computes.  So for x in the range
-   [INT64_MIN, y] the range prediction after vnegd_s64 (x) will
-   be ~[INT64_MIN + 1, y].  */
-
-__extension__ extern __inline int64_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vnegd_s64 (int64_t __a)
-{
-  return - (uint64_t) __a;
-}
-
-__extension__ extern __inline float32x4_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vnegq_f32 (float32x4_t __a)
-{
-  return -__a;
-}
-
-__extension__ extern __inline float64x2_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vnegq_f64 (float64x2_t __a)
-{
-  return -__a;
-}
-
-__extension__ extern __inline int8x16_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vnegq_s8 (int8x16_t __a)
-{
-  return -__a;
-}
-
-__extension__ extern __inline int16x8_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vnegq_s16 (int16x8_t __a)
-{
-  return -__a;
-}
-
-__extension__ extern __inline int32x4_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vnegq_s32 (int32x4_t __a)
-{
-  return -__a;
-}
-
-__extension__ extern __inline int64x2_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vnegq_s64 (int64x2_t __a)
-{
-  return -__a;
-}
-
 /* vpadd  */
 
 __extension__ extern __inline float32x2_t
@@ -19713,20 +19608,6 @@ vcvtpq_u16_f16 (float16x8_t __a)
   return __builtin_aarch64_lceiluv8hfv8hi_us (__a);
 }
 
-__extension__ extern __inline float16x4_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vneg_f16 (float16x4_t __a)
-{
-  return -__a;
-}
-
-__extension__ extern __inline float16x8_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vnegq_f16 (float16x8_t __a)
-{
-  return -__a;
-}
-
 __extension__ extern __inline float16x4_t
 __attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
 vrecpe_f16 (float16x4_t __a)
diff --git a/gcc/testsuite/gcc.target/aarch64/neon/vneg.c 
b/gcc/testsuite/gcc.target/aarch64/neon/vneg.c
new file mode 100644
index 00000000000..018925438ff
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/neon/vneg.c
@@ -0,0 +1,109 @@
+/* { dg-do compile } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "arm_neon_test.h"
+
+/*
+** test_vneg_f32:
+** fneg        v0\.2s, v0\.2s
+** ret
+*/
+TEST_UNIFORM_UNARY (vneg_f32, float32x2_t)
+
+/*
+** test_vneg_f64:
+** fneg        d0, d0
+** ret
+*/
+TEST_UNIFORM_UNARY (vneg_f64, float64x1_t)
+
+/*
+** test_vneg_s8:
+** neg v0\.8b, v0\.8b
+** ret
+*/
+TEST_UNIFORM_UNARY (vneg_s8, int8x8_t)
+
+/*
+** test_vneg_s16:
+** neg v0\.4h, v0\.4h
+** ret
+*/
+TEST_UNIFORM_UNARY (vneg_s16, int16x4_t)
+
+/*
+** test_vneg_s32:
+** neg v0\.2s, v0\.2s
+** ret
+*/
+TEST_UNIFORM_UNARY (vneg_s32, int32x2_t)
+
+/*
+** test_vneg_s64:
+** neg d0, d0
+** ret
+*/
+TEST_UNIFORM_UNARY (vneg_s64, int64x1_t)
+
+/*
+** test_vnegd_s64:
+** neg x0, x0
+** ret
+*/
+TEST_UNIFORM_UNARY (vnegd_s64, int64_t)
+
+/*
+** test_vnegq_f32:
+** fneg        v0\.4s, v0\.4s
+** ret
+*/
+TEST_UNIFORM_UNARY (vnegq_f32, float32x4_t)
+
+/*
+** test_vnegq_f64:
+** fneg        v0\.2d, v0\.2d
+** ret
+*/
+TEST_UNIFORM_UNARY (vnegq_f64, float64x2_t)
+
+/*
+** test_vnegq_s8:
+** neg v0\.16b, v0\.16b
+** ret
+*/
+TEST_UNIFORM_UNARY (vnegq_s8, int8x16_t)
+
+/*
+** test_vnegq_s16:
+** neg v0\.8h, v0\.8h
+** ret
+*/
+TEST_UNIFORM_UNARY (vnegq_s16, int16x8_t)
+
+/*
+** test_vnegq_s32:
+** neg v0\.4s, v0\.4s
+** ret
+*/
+TEST_UNIFORM_UNARY (vnegq_s32, int32x4_t)
+
+/*
+** test_vnegq_s64:
+** neg v0\.2d, v0\.2d
+** ret
+*/
+TEST_UNIFORM_UNARY (vnegq_s64, int64x2_t)
+
+/*
+** test_vneg_f16:
+** fneg        v0\.4h, v0\.4h
+** ret
+*/
+TEST_UNIFORM_UNARY (vneg_f16, float16x4_t)
+
+/*
+** test_vnegq_f16:
+** fneg        v0\.8h, v0\.8h
+** ret
+*/
+TEST_UNIFORM_UNARY (vnegq_f16, float16x8_t)
diff --git a/gcc/testsuite/gcc.target/aarch64/signbit-2.c 
b/gcc/testsuite/gcc.target/aarch64/signbit-2.c
index e4e9afc8543..70f6ae29096 100644
--- a/gcc/testsuite/gcc.target/aarch64/signbit-2.c
+++ b/gcc/testsuite/gcc.target/aarch64/signbit-2.c
@@ -33,4 +33,4 @@ int8x8_t foo6 (int8x8_t a)
   return vshr_n_s8 (vneg_s8 (a), 7);
 }
 
-/* { dg-final { scan-assembler-times {\tcmgt\t} 6 } } */
+/* { dg-final { scan-assembler-times {\tcmlt\t} 6 } } */
-- 
2.51.0

Reply via email to