(root)/
glibc-2.38/
sysdeps/
aarch64/
fpu/
s_lrint.c
       1  /* Copyright (C) 1996-2023 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
      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)