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