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