summaryrefslogtreecommitdiff
path: root/sysdeps/aarch64/fpu/s_lrint.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/aarch64/fpu/s_lrint.c')
-rw-r--r--sysdeps/aarch64/fpu/s_lrint.c82
1 files changed, 59 insertions, 23 deletions
diff --git a/sysdeps/aarch64/fpu/s_lrint.c b/sysdeps/aarch64/fpu/s_lrint.c
index e51de0fc2d..d6ef066e45 100644
--- a/sysdeps/aarch64/fpu/s_lrint.c
+++ b/sysdeps/aarch64/fpu/s_lrint.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2016 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -17,37 +17,73 @@
<http://www.gnu.org/licenses/>. */
#include <math.h>
+#include <get-rounding-mode.h>
+#include <stdint.h>
+#include <math-barriers.h>
+#include <math_private.h>
+#include <libm-alias-double.h>
-#ifndef FUNC
-# define FUNC lrint
-#endif
+# define IREG_SIZE 64
+
+# ifdef __ILP32__
+# define OREG_SIZE 32
+# else
+# define OREG_SIZE 64
+# endif
-#ifndef ITYPE
-# define ITYPE double
# define IREGS "d"
+
+#if OREG_SIZE == 32
+# define OREGS "w"
#else
-# ifndef IREGS
-# error IREGS not defined
-# endif
+# define OREGS "x"
#endif
-#ifndef OTYPE
-# define OTYPE long int
+
+long int
+__lrint (double x)
+{
+
+#if IREG_SIZE == 64 && OREG_SIZE == 32
+ long int result;
+
+ if (__builtin_fabs (x) > INT32_MAX)
+ {
+ /* Converting large values to a 32 bit int may cause the frintx/fcvtza
+ sequence to set both FE_INVALID and FE_INEXACT. To avoid this
+ check the rounding mode and do a single instruction with the
+ appropriate rounding mode. */
+
+ switch (get_rounding_mode ())
+ {
+ case FE_TONEAREST:
+ asm volatile ("fcvtns" "\t%" OREGS "0, %" IREGS "1"
+ : "=r" (result) : "w" (x));
+ break;
+ case FE_UPWARD:
+ asm volatile ("fcvtps" "\t%" OREGS "0, %" IREGS "1"
+ : "=r" (result) : "w" (x));
+ break;
+ case FE_DOWNWARD:
+ asm volatile ("fcvtms" "\t%" OREGS "0, %" IREGS "1"
+ : "=r" (result) : "w" (x));
+ break;
+ case FE_TOWARDZERO:
+ default:
+ asm volatile ("fcvtzs" "\t%" OREGS "0, %" IREGS "1"
+ : "=r" (result) : "w" (x));
+ }
+ return result;
+ }
#endif
-#define OREGS "x"
+ double r = __builtin_rint (x);
-#define __CONCATX(a,b) __CONCAT(a,b)
+ /* Prevent gcc from calling lrint directly when compiled with
+ -fno-math-errno by inserting a barrier. */
-OTYPE
-__CONCATX(__,FUNC) (ITYPE x)
-{
- OTYPE result;
- ITYPE temp;
- asm ( "frintx" "\t%" IREGS "1, %" IREGS "2\n\t"
- "fcvtzs" "\t%" OREGS "0, %" IREGS "1"
- : "=r" (result), "=w" (temp) : "w" (x) );
- return result;
+ math_opt_barrier (r);
+ return r;
}
-weak_alias (__CONCATX(__,FUNC), FUNC)
+libm_alias_double (__lrint, lrint)