(root)/
glibc-2.38/
sysdeps/
generic/
fenv_private.h
       1  /* Optimized inline fenv.h functions for libm.  Generic version.
       2     Copyright (C) 2011-2023 Free Software Foundation, Inc.
       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  #ifndef _FENV_PRIVATE_H
      20  #define _FENV_PRIVATE_H 1
      21  
      22  #include <fenv.h>
      23  #include <get-rounding-mode.h>
      24  
      25  /* The standards only specify one variant of the fenv.h interfaces.
      26     But at least for some architectures we can be more efficient if we
      27     know what operations are going to be performed.  Therefore we
      28     define additional interfaces.  By default they refer to the normal
      29     interfaces.  */
      30  
      31  static __always_inline void
      32  default_libc_feholdexcept (fenv_t *e)
      33  {
      34    (void) __feholdexcept (e);
      35  }
      36  
      37  #ifndef libc_feholdexcept
      38  # define libc_feholdexcept  default_libc_feholdexcept
      39  #endif
      40  #ifndef libc_feholdexceptf
      41  # define libc_feholdexceptf default_libc_feholdexcept
      42  #endif
      43  #ifndef libc_feholdexceptl
      44  # define libc_feholdexceptl default_libc_feholdexcept
      45  #endif
      46  
      47  static __always_inline void
      48  default_libc_fesetround (int r)
      49  {
      50    (void) __fesetround (r);
      51  }
      52  
      53  #ifndef libc_fesetround
      54  # define libc_fesetround  default_libc_fesetround
      55  #endif
      56  #ifndef libc_fesetroundf
      57  # define libc_fesetroundf default_libc_fesetround
      58  #endif
      59  #ifndef libc_fesetroundl
      60  # define libc_fesetroundl default_libc_fesetround
      61  #endif
      62  
      63  static __always_inline void
      64  default_libc_feholdexcept_setround (fenv_t *e, int r)
      65  {
      66    __feholdexcept (e);
      67    __fesetround (r);
      68  }
      69  
      70  #ifndef libc_feholdexcept_setround
      71  # define libc_feholdexcept_setround  default_libc_feholdexcept_setround
      72  #endif
      73  #ifndef libc_feholdexcept_setroundf
      74  # define libc_feholdexcept_setroundf default_libc_feholdexcept_setround
      75  #endif
      76  #ifndef libc_feholdexcept_setroundl
      77  # define libc_feholdexcept_setroundl default_libc_feholdexcept_setround
      78  #endif
      79  
      80  #ifndef libc_feholdsetround_53bit
      81  # define libc_feholdsetround_53bit libc_feholdsetround
      82  #endif
      83  
      84  #ifndef libc_fetestexcept
      85  # define libc_fetestexcept  fetestexcept
      86  #endif
      87  #ifndef libc_fetestexceptf
      88  # define libc_fetestexceptf fetestexcept
      89  #endif
      90  #ifndef libc_fetestexceptl
      91  # define libc_fetestexceptl fetestexcept
      92  #endif
      93  
      94  static __always_inline void
      95  default_libc_fesetenv (fenv_t *e)
      96  {
      97    (void) __fesetenv (e);
      98  }
      99  
     100  #ifndef libc_fesetenv
     101  # define libc_fesetenv  default_libc_fesetenv
     102  #endif
     103  #ifndef libc_fesetenvf
     104  # define libc_fesetenvf default_libc_fesetenv
     105  #endif
     106  #ifndef libc_fesetenvl
     107  # define libc_fesetenvl default_libc_fesetenv
     108  #endif
     109  
     110  static __always_inline void
     111  default_libc_feupdateenv (fenv_t *e)
     112  {
     113    (void) __feupdateenv (e);
     114  }
     115  
     116  #ifndef libc_feupdateenv
     117  # define libc_feupdateenv  default_libc_feupdateenv
     118  #endif
     119  #ifndef libc_feupdateenvf
     120  # define libc_feupdateenvf default_libc_feupdateenv
     121  #endif
     122  #ifndef libc_feupdateenvl
     123  # define libc_feupdateenvl default_libc_feupdateenv
     124  #endif
     125  
     126  #ifndef libc_feresetround_53bit
     127  # define libc_feresetround_53bit libc_feresetround
     128  #endif
     129  
     130  static __always_inline int
     131  default_libc_feupdateenv_test (fenv_t *e, int ex)
     132  {
     133    int ret = fetestexcept (ex);
     134    __feupdateenv (e);
     135    return ret;
     136  }
     137  
     138  #ifndef libc_feupdateenv_test
     139  # define libc_feupdateenv_test  default_libc_feupdateenv_test
     140  #endif
     141  #ifndef libc_feupdateenv_testf
     142  # define libc_feupdateenv_testf default_libc_feupdateenv_test
     143  #endif
     144  #ifndef libc_feupdateenv_testl
     145  # define libc_feupdateenv_testl default_libc_feupdateenv_test
     146  #endif
     147  
     148  /* Save and set the rounding mode.  The use of fenv_t to store the old mode
     149     allows a target-specific version of this function to avoid converting the
     150     rounding mode from the fpu format.  By default we have no choice but to
     151     manipulate the entire env.  */
     152  
     153  #ifndef libc_feholdsetround
     154  # define libc_feholdsetround  libc_feholdexcept_setround
     155  #endif
     156  #ifndef libc_feholdsetroundf
     157  # define libc_feholdsetroundf libc_feholdexcept_setroundf
     158  #endif
     159  #ifndef libc_feholdsetroundl
     160  # define libc_feholdsetroundl libc_feholdexcept_setroundl
     161  #endif
     162  
     163  /* ... and the reverse.  */
     164  
     165  #ifndef libc_feresetround
     166  # define libc_feresetround  libc_feupdateenv
     167  #endif
     168  #ifndef libc_feresetroundf
     169  # define libc_feresetroundf libc_feupdateenvf
     170  #endif
     171  #ifndef libc_feresetroundl
     172  # define libc_feresetroundl libc_feupdateenvl
     173  #endif
     174  
     175  /* ... and a version that also discards exceptions.  */
     176  
     177  #ifndef libc_feresetround_noex
     178  # define libc_feresetround_noex  libc_fesetenv
     179  #endif
     180  #ifndef libc_feresetround_noexf
     181  # define libc_feresetround_noexf libc_fesetenvf
     182  #endif
     183  #ifndef libc_feresetround_noexl
     184  # define libc_feresetround_noexl libc_fesetenvl
     185  #endif
     186  
     187  #ifndef HAVE_RM_CTX
     188  # define HAVE_RM_CTX 0
     189  #endif
     190  
     191  
     192  /* Default implementation using standard fenv functions.
     193     Avoid unnecessary rounding mode changes by first checking the
     194     current rounding mode.  Note the use of __glibc_unlikely is
     195     important for performance.  */
     196  
     197  static __always_inline void
     198  default_libc_feholdsetround_ctx (struct rm_ctx *ctx, int round)
     199  {
     200    ctx->updated_status = false;
     201  
     202    /* Update rounding mode only if different.  */
     203    if (__glibc_unlikely (round != get_rounding_mode ()))
     204      {
     205        ctx->updated_status = true;
     206        __fegetenv (&ctx->env);
     207        __fesetround (round);
     208      }
     209  }
     210  
     211  static __always_inline void
     212  default_libc_feresetround_ctx (struct rm_ctx *ctx)
     213  {
     214    /* Restore the rounding mode if updated.  */
     215    if (__glibc_unlikely (ctx->updated_status))
     216      __feupdateenv (&ctx->env);
     217  }
     218  
     219  static __always_inline void
     220  default_libc_feholdsetround_noex_ctx (struct rm_ctx *ctx, int round)
     221  {
     222    /* Save exception flags and rounding mode, and disable exception
     223       traps.  */
     224    __feholdexcept (&ctx->env);
     225  
     226    /* Update rounding mode only if different.  */
     227    if (__glibc_unlikely (round != get_rounding_mode ()))
     228      __fesetround (round);
     229  }
     230  
     231  static __always_inline void
     232  default_libc_feresetround_noex_ctx (struct rm_ctx *ctx)
     233  {
     234    /* Restore exception flags and rounding mode.  */
     235    __fesetenv (&ctx->env);
     236  }
     237  
     238  #if HAVE_RM_CTX
     239  /* Set/Restore Rounding Modes only when necessary.  If defined, these functions
     240     set/restore floating point state only if the state needed within the lexical
     241     block is different from the current state.  This saves a lot of time when
     242     the floating point unit is much slower than the fixed point units.  */
     243  
     244  # ifndef libc_feholdsetround_noex_ctx
     245  #   define libc_feholdsetround_noex_ctx  libc_feholdsetround_ctx
     246  # endif
     247  # ifndef libc_feholdsetround_noexf_ctx
     248  #   define libc_feholdsetround_noexf_ctx libc_feholdsetroundf_ctx
     249  # endif
     250  # ifndef libc_feholdsetround_noexl_ctx
     251  #   define libc_feholdsetround_noexl_ctx libc_feholdsetroundl_ctx
     252  # endif
     253  
     254  # ifndef libc_feresetround_noex_ctx
     255  #   define libc_feresetround_noex_ctx  libc_fesetenv_ctx
     256  # endif
     257  # ifndef libc_feresetround_noexf_ctx
     258  #   define libc_feresetround_noexf_ctx libc_fesetenvf_ctx
     259  # endif
     260  # ifndef libc_feresetround_noexl_ctx
     261  #   define libc_feresetround_noexl_ctx libc_fesetenvl_ctx
     262  # endif
     263  
     264  #else
     265  
     266  # define libc_feholdsetround_ctx      default_libc_feholdsetround_ctx
     267  # define libc_feresetround_ctx        default_libc_feresetround_ctx
     268  # define libc_feholdsetround_noex_ctx default_libc_feholdsetround_noex_ctx
     269  # define libc_feresetround_noex_ctx   default_libc_feresetround_noex_ctx
     270  
     271  # define libc_feholdsetroundf_ctx libc_feholdsetround_ctx
     272  # define libc_feholdsetroundl_ctx libc_feholdsetround_ctx
     273  # define libc_feresetroundf_ctx   libc_feresetround_ctx
     274  # define libc_feresetroundl_ctx   libc_feresetround_ctx
     275  
     276  # define libc_feholdsetround_noexf_ctx libc_feholdsetround_noex_ctx
     277  # define libc_feholdsetround_noexl_ctx libc_feholdsetround_noex_ctx
     278  # define libc_feresetround_noexf_ctx   libc_feresetround_noex_ctx
     279  # define libc_feresetround_noexl_ctx   libc_feresetround_noex_ctx
     280  
     281  #endif
     282  
     283  #ifndef libc_feholdsetround_53bit_ctx
     284  #  define libc_feholdsetround_53bit_ctx libc_feholdsetround_ctx
     285  #endif
     286  #ifndef libc_feresetround_53bit_ctx
     287  #  define libc_feresetround_53bit_ctx libc_feresetround_ctx
     288  #endif
     289  
     290  #define SET_RESTORE_ROUND_GENERIC(RM,ROUNDFUNC,CLEANUPFUNC) \
     291    struct rm_ctx ctx __attribute__((cleanup (CLEANUPFUNC ## _ctx))); \
     292    ROUNDFUNC ## _ctx (&ctx, (RM))
     293  
     294  /* Set the rounding mode within a lexical block.  Restore the rounding mode to
     295     the value at the start of the block.  The exception mode must be preserved.
     296     Exceptions raised within the block must be set in the exception flags.
     297     Non-stop mode may be enabled inside the block.  */
     298  
     299  #define SET_RESTORE_ROUND(RM) \
     300    SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround, libc_feresetround)
     301  #define SET_RESTORE_ROUNDF(RM) \
     302    SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetroundf, libc_feresetroundf)
     303  #define SET_RESTORE_ROUNDL(RM) \
     304    SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetroundl, libc_feresetroundl)
     305  
     306  /* Set the rounding mode within a lexical block.  Restore the rounding mode to
     307     the value at the start of the block.  The exception mode must be preserved.
     308     Exceptions raised within the block must be discarded, and exception flags
     309     are restored to the value at the start of the block.
     310     Non-stop mode must be enabled inside the block.  */
     311  
     312  #define SET_RESTORE_ROUND_NOEX(RM) \
     313    SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_noex, \
     314  			     libc_feresetround_noex)
     315  #define SET_RESTORE_ROUND_NOEXF(RM) \
     316    SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_noexf, \
     317  			     libc_feresetround_noexf)
     318  #define SET_RESTORE_ROUND_NOEXL(RM) \
     319    SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_noexl, \
     320  			     libc_feresetround_noexl)
     321  
     322  /* Like SET_RESTORE_ROUND, but also set rounding precision to 53 bits.  */
     323  #define SET_RESTORE_ROUND_53BIT(RM) \
     324    SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_53bit,	      \
     325  			     libc_feresetround_53bit)
     326  
     327  #endif /* fenv_private.h.  */