From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2153) id 83275386EC0B; Mon, 28 Sep 2020 09:15:13 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 83275386EC0B Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Jakub Jelinek To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/vendors/redhat/heads/gcc-8-branch)] [AArch64] Implement new intrinsics vabsd_s64 and vnegd_s64. X-Act-Checkin: gcc X-Git-Author: Vlad Lazar X-Git-Refname: refs/vendors/redhat/heads/gcc-8-branch X-Git-Oldrev: d78c0aebb2c1a9661177b6b1f1901f523c612114 X-Git-Newrev: bb9d137611b1099a86fc68aed4d0f66b723ebd95 Message-Id: <20200928091513.83275386EC0B@sourceware.org> Date: Mon, 28 Sep 2020 09:15:13 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Sep 2020 09:15:13 -0000 https://gcc.gnu.org/g:bb9d137611b1099a86fc68aed4d0f66b723ebd95 commit bb9d137611b1099a86fc68aed4d0f66b723ebd95 Author: Vlad Lazar Date: Fri Aug 31 15:00:54 2018 +0000 [AArch64] Implement new intrinsics vabsd_s64 and vnegd_s64. gcc/ 2018-08-31 Vlad Lazar PR target/71233 * config/aarch64/arm_neon.h (vabsd_s64): New. (vnegd_s64): Likewise. gcc/testsuite/ 2018-08-31 Vlad Lazar PR target/71233 * gcc.target/aarch64/scalar_intrinsics.c (test_vnegd_s64): New. * gcc.target/aarch64/vneg_s.c (RUN_TEST_SCALAR): New. (test_vnegd_s64): Likewise. * gcc.target/aarch64/vnegd_s64.c: New. * gcc.target/aarch64/vabsd_s64.c: New. (cherry picked from commit 66da5b53107962a1c115a9686f2220de27f276f7) Diff: --- gcc/config/aarch64/arm_neon.h | 31 +++++++++++++++++ .../gcc.target/aarch64/scalar_intrinsics.c | 8 +++++ .../gcc.target/aarch64/vabs_intrinsic_3.c | 39 ++++++++++++++++++++++ gcc/testsuite/gcc.target/aarch64/vabsd_s64.c | 34 +++++++++++++++++++ gcc/testsuite/gcc.target/aarch64/vneg_s.c | 34 ++++++++++++++++++- gcc/testsuite/gcc.target/aarch64/vnegd_s64.c | 36 ++++++++++++++++++++ 6 files changed, 181 insertions(+), 1 deletion(-) diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h index dd53e243b52..7bcd1e1c844 100644 --- a/gcc/config/aarch64/arm_neon.h +++ b/gcc/config/aarch64/arm_neon.h @@ -11822,6 +11822,18 @@ 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; +} + /* vadd */ __extension__ extern __inline int64_t @@ -23189,6 +23201,25 @@ 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) diff --git a/gcc/testsuite/gcc.target/aarch64/scalar_intrinsics.c b/gcc/testsuite/gcc.target/aarch64/scalar_intrinsics.c index ea29066e369..d943989768d 100644 --- a/gcc/testsuite/gcc.target/aarch64/scalar_intrinsics.c +++ b/gcc/testsuite/gcc.target/aarch64/scalar_intrinsics.c @@ -627,6 +627,14 @@ test_vqabss_s32 (int32_t a) return vqabss_s32 (a); } +/* { dg-final { scan-assembler-times "\\tneg\\tx\[0-9\]+" 1 } } */ + +int64_t +test_vnegd_s64 (int64_t a) +{ + return vnegd_s64 (a); +} + /* { dg-final { scan-assembler-times "\\tsqneg\\tb\[0-9\]+" 1 } } */ int8_t diff --git a/gcc/testsuite/gcc.target/aarch64/vabs_intrinsic_3.c b/gcc/testsuite/gcc.target/aarch64/vabs_intrinsic_3.c new file mode 100644 index 00000000000..cf4e7ae4679 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/vabs_intrinsic_3.c @@ -0,0 +1,39 @@ +/* Test the vabsd_s64 intrinsic. */ + +/* { dg-do run } */ +/* { dg-options "--save-temps -O2" } */ + +#include +#include + +extern void abort (void); + +#define force_simd(V1) asm volatile ("mov %d0, %1.d[0]" \ + : "=w"(V1) \ + : "w"(V1) \ + : /* No clobbers */); + +#define RUN_TEST(test, answ) \ +{ \ + force_simd (test); \ + force_simd (answ); \ + int64_t res = vabsd_s64 (test); \ + force_simd (res); \ + if (res != answ) \ + abort (); \ +} + +int64_t input[] = {INT64_MAX, 10, 0, -10, INT64_MIN + 1, INT64_MIN}; +int64_t expected[] = {INT64_MAX, 10, 0, 10, INT64_MAX, INT64_MIN}; + +int main (void) +{ + RUN_TEST (input[0], expected[0]); + RUN_TEST (input[1], expected[1]); + RUN_TEST (input[2], expected[2]); + RUN_TEST (input[3], expected[3]); + RUN_TEST (input[4], expected[4]); + RUN_TEST (input[5], expected[5]); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/vabsd_s64.c b/gcc/testsuite/gcc.target/aarch64/vabsd_s64.c new file mode 100644 index 00000000000..a0f88ee12c3 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/vabsd_s64.c @@ -0,0 +1,34 @@ +/* Check that the compiler does not optimise the vabsd_s64 call out. + We need to check for this because there is a mismatch in semantics + between the ACLE, which states that he absolute value of the minimum + (signed) value is itself, and C, where this is undefined behaviour. */ + +/* { dg-do run } */ +/* { dg-options "--save-temps -fno-inline -O2" } */ + +#include +#include + +extern void abort (void); + +int +bar (int64_t x) +{ + if (x < (int64_t) 0) + return vabsd_s64 (x) < (int64_t) 0; + else + return -1; +} + +int +main (void) +{ + int ans = 1; + int res_abs = bar (INT64_MIN); + + if (res_abs != ans) + abort (); + + return 0; +} + diff --git a/gcc/testsuite/gcc.target/aarch64/vneg_s.c b/gcc/testsuite/gcc.target/aarch64/vneg_s.c index 911054053ea..e7f20f2831f 100644 --- a/gcc/testsuite/gcc.target/aarch64/vneg_s.c +++ b/gcc/testsuite/gcc.target/aarch64/vneg_s.c @@ -75,6 +75,18 @@ extern void abort (void); } \ } +#define RUN_TEST_SCALAR(test_val, answ_val, a, b) \ + { \ + int64_t res; \ + INHIB_OPTIMIZATION; \ + a = test_val; \ + b = answ_val; \ + force_simd (b); \ + force_simd (a); \ + res = vnegd_s64 (a); \ + force_simd (res); \ + } + int test_vneg_s8 () { @@ -177,7 +189,24 @@ test_vneg_s64 () return 0; } -/* { dg-final { scan-assembler-times "neg\\td\[0-9\]+, d\[0-9\]+" 8 } } */ +int +test_vnegd_s64 () +{ + int64_t a, b; + + RUN_TEST_SCALAR (TEST0, ANSW0, a, b); + RUN_TEST_SCALAR (TEST1, ANSW1, a, b); + RUN_TEST_SCALAR (TEST2, ANSW2, a, b); + RUN_TEST_SCALAR (TEST3, ANSW3, a, b); + RUN_TEST_SCALAR (TEST4, ANSW4, a, b); + RUN_TEST_SCALAR (TEST5, ANSW5, a, b); + RUN_TEST_SCALAR (LLONG_MAX, LLONG_MIN + 1, a, b); + RUN_TEST_SCALAR (LLONG_MIN, LLONG_MIN, a, b); + + return 0; +} + +/* { dg-final { scan-assembler-times "neg\\td\[0-9\]+, d\[0-9\]+" 16 } } */ int test_vnegq_s8 () @@ -283,6 +312,9 @@ main (int argc, char **argv) if (test_vneg_s64 ()) abort (); + if (test_vnegd_s64 ()) + abort (); + if (test_vnegq_s8 ()) abort (); diff --git a/gcc/testsuite/gcc.target/aarch64/vnegd_s64.c b/gcc/testsuite/gcc.target/aarch64/vnegd_s64.c new file mode 100644 index 00000000000..73d478ff49d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/vnegd_s64.c @@ -0,0 +1,36 @@ +/* Check that the compiler does not optimise the negation out. + We need to check for this because there is a mismatch in semantics + between the ACLE, which states that he negative of the minimum + (signed) value is itself and C, where this is undefined behaviour. */ + +/* { dg-do run } */ +/* { dg-options "--save-temps -O2" } */ + +#include +#include + +extern void abort (void); + +int +foo (int64_t x) +{ + if (x < (int64_t) 0) + return vnegd_s64 (x) < (int64_t) 0; + else + return -1; +} + +/* { dg-final { scan-assembler-times {neg\tx[0-9]+, x[0-9]+} 1 } } */ + +int +main (void) +{ + int ans = 1; + int res = foo (INT64_MIN); + + if (res != ans) + abort (); + + return 0; +} +