1 /* Copyright (C) 1996-2021 Free Software Foundation, Inc.
2 
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <math.h>
20 #include <get-rounding-mode.h>
21 #include <stdint.h>
22 #include <math-barriers.h>
23 #include <libm-alias-double.h>
24 
25 # define IREG_SIZE 64
26 
27 # ifdef __ILP32__
28 #  define OREG_SIZE 32
29 # else
30 #  define OREG_SIZE 64
31 # endif
32 
33 # define IREGS "d"
34 
35 #if OREG_SIZE == 32
36 # define OREGS "w"
37 #else
38 # define OREGS "x"
39 #endif
40 
41 
42 long int
__lrint(double x)43 __lrint (double x)
44 {
45 
46 #if IREG_SIZE == 64 && OREG_SIZE == 32
47   long int result;
48 
49   if (__builtin_fabs (x) > INT32_MAX)
50     {
51       /* Converting large values to a 32 bit int may cause the frintx/fcvtza
52 	 sequence to set both FE_INVALID and FE_INEXACT.  To avoid this
53 	 check the rounding mode and do a single instruction with the
54 	 appropriate rounding mode.  */
55 
56       switch (get_rounding_mode ())
57 	{
58 	case FE_TONEAREST:
59 	  asm volatile ("fcvtns" "\t%" OREGS "0, %" IREGS "1"
60 			: "=r" (result) : "w" (x));
61 	  break;
62 	case FE_UPWARD:
63 	  asm volatile ("fcvtps" "\t%" OREGS "0, %" IREGS "1"
64 			: "=r" (result) : "w" (x));
65 	  break;
66 	case FE_DOWNWARD:
67 	  asm volatile ("fcvtms" "\t%" OREGS "0, %" IREGS "1"
68 			: "=r" (result) : "w" (x));
69 	  break;
70 	case FE_TOWARDZERO:
71 	default:
72 	  asm volatile ("fcvtzs" "\t%" OREGS "0, %" IREGS "1"
73 			: "=r" (result) : "w" (x));
74 	}
75       return result;
76     }
77 #endif
78 
79   double r =  __builtin_rint (x);
80 
81   /* Prevent gcc from calling lrint directly when compiled with
82      -fno-math-errno by inserting a barrier.  */
83 
84   math_opt_barrier (r);
85   return r;
86 }
87 
88 libm_alias_double (__lrint, lrint)
89