(root)/
glibc-2.38/
sysdeps/
aarch64/
fpu/
fenv_private.h
       1  /* Private floating point rounding and exceptions handling.  AArch64 version.
       2     Copyright (C) 2014-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 AARCH64_FENV_PRIVATE_H
      20  #define AARCH64_FENV_PRIVATE_H 1
      21  
      22  #include <fenv.h>
      23  #include <fpu_control.h>
      24  
      25  static __always_inline void
      26  libc_feholdexcept_aarch64 (fenv_t *envp)
      27  {
      28    fpu_control_t fpcr;
      29    fpu_control_t new_fpcr;
      30    fpu_fpsr_t fpsr;
      31    fpu_fpsr_t new_fpsr;
      32  
      33    _FPU_GETCW (fpcr);
      34    _FPU_GETFPSR (fpsr);
      35    envp->__fpcr = fpcr;
      36    envp->__fpsr = fpsr;
      37  
      38    /* Clear exception flags and set all exceptions to non-stop.  */
      39    new_fpcr = fpcr & ~(FE_ALL_EXCEPT << FE_EXCEPT_SHIFT);
      40    new_fpsr = fpsr & ~FE_ALL_EXCEPT;
      41  
      42    if (__glibc_unlikely (new_fpcr != fpcr))
      43      _FPU_SETCW (new_fpcr);
      44  
      45    if (new_fpsr != fpsr)
      46      _FPU_SETFPSR (new_fpsr);
      47  }
      48  
      49  #define libc_feholdexcept  libc_feholdexcept_aarch64
      50  #define libc_feholdexceptf libc_feholdexcept_aarch64
      51  #define libc_feholdexceptl libc_feholdexcept_aarch64
      52  
      53  static __always_inline void
      54  libc_fesetround_aarch64 (int round)
      55  {
      56    fpu_control_t fpcr;
      57  
      58    _FPU_GETCW (fpcr);
      59  
      60    /* Check whether rounding modes are different.  */
      61    round = (fpcr ^ round) & _FPU_FPCR_RM_MASK;
      62  
      63    /* Set new rounding mode if different.  */
      64    if (__glibc_unlikely (round != 0))
      65      _FPU_SETCW (fpcr ^ round);
      66  }
      67  
      68  #define libc_fesetround  libc_fesetround_aarch64
      69  #define libc_fesetroundf libc_fesetround_aarch64
      70  #define libc_fesetroundl libc_fesetround_aarch64
      71  
      72  static __always_inline void
      73  libc_feholdexcept_setround_aarch64 (fenv_t *envp, int round)
      74  {
      75    fpu_control_t fpcr;
      76    fpu_control_t new_fpcr;
      77    fpu_fpsr_t fpsr;
      78    fpu_fpsr_t new_fpsr;
      79  
      80    _FPU_GETCW (fpcr);
      81    _FPU_GETFPSR (fpsr);
      82    envp->__fpcr = fpcr;
      83    envp->__fpsr = fpsr;
      84  
      85    /* Clear exception flags, set all exceptions to non-stop,
      86       and set new rounding mode.  */
      87    new_fpcr = fpcr & ~((FE_ALL_EXCEPT << FE_EXCEPT_SHIFT) | _FPU_FPCR_RM_MASK);
      88    new_fpcr |= round;
      89    new_fpsr = fpsr & ~FE_ALL_EXCEPT;
      90  
      91    if (__glibc_unlikely (new_fpcr != fpcr))
      92      _FPU_SETCW (new_fpcr);
      93  
      94    if (new_fpsr != fpsr)
      95      _FPU_SETFPSR (new_fpsr);
      96  }
      97  
      98  #define libc_feholdexcept_setround  libc_feholdexcept_setround_aarch64
      99  #define libc_feholdexcept_setroundf libc_feholdexcept_setround_aarch64
     100  #define libc_feholdexcept_setroundl libc_feholdexcept_setround_aarch64
     101  
     102  static __always_inline int
     103  libc_fetestexcept_aarch64 (int ex)
     104  {
     105    fpu_fpsr_t fpsr;
     106  
     107    _FPU_GETFPSR (fpsr);
     108    return fpsr & ex & FE_ALL_EXCEPT;
     109  }
     110  
     111  #define libc_fetestexcept  libc_fetestexcept_aarch64
     112  #define libc_fetestexceptf libc_fetestexcept_aarch64
     113  #define libc_fetestexceptl libc_fetestexcept_aarch64
     114  
     115  static __always_inline void
     116  libc_fesetenv_aarch64 (const fenv_t *envp)
     117  {
     118    fpu_control_t fpcr;
     119    fpu_control_t new_fpcr;
     120  
     121    _FPU_GETCW (fpcr);
     122    new_fpcr = envp->__fpcr;
     123  
     124    if (__glibc_unlikely (fpcr != new_fpcr))
     125      _FPU_SETCW (new_fpcr);
     126  
     127    _FPU_SETFPSR (envp->__fpsr);
     128  }
     129  
     130  #define libc_fesetenv  libc_fesetenv_aarch64
     131  #define libc_fesetenvf libc_fesetenv_aarch64
     132  #define libc_fesetenvl libc_fesetenv_aarch64
     133  #define libc_feresetround_noex  libc_fesetenv_aarch64
     134  #define libc_feresetround_noexf libc_fesetenv_aarch64
     135  #define libc_feresetround_noexl libc_fesetenv_aarch64
     136  
     137  static __always_inline int
     138  libc_feupdateenv_test_aarch64 (const fenv_t *envp, int ex)
     139  {
     140    fpu_control_t fpcr;
     141    fpu_control_t new_fpcr;
     142    fpu_fpsr_t fpsr;
     143    fpu_fpsr_t new_fpsr;
     144    int excepts;
     145  
     146    _FPU_GETCW (fpcr);
     147    _FPU_GETFPSR (fpsr);
     148  
     149    /* Merge current exception flags with the saved fenv.  */
     150    excepts = fpsr & FE_ALL_EXCEPT;
     151    new_fpcr = envp->__fpcr;
     152    new_fpsr = envp->__fpsr | excepts;
     153  
     154    if (__glibc_unlikely (fpcr != new_fpcr))
     155      _FPU_SETCW (new_fpcr);
     156  
     157    if (fpsr != new_fpsr)
     158      _FPU_SETFPSR (new_fpsr);
     159  
     160    /* Raise the exceptions if enabled in the new FP state.  */
     161    if (__glibc_unlikely (excepts & (new_fpcr >> FE_EXCEPT_SHIFT)))
     162      __feraiseexcept (excepts);
     163  
     164    return excepts & ex;
     165  }
     166  
     167  #define libc_feupdateenv_test  libc_feupdateenv_test_aarch64
     168  #define libc_feupdateenv_testf libc_feupdateenv_test_aarch64
     169  #define libc_feupdateenv_testl libc_feupdateenv_test_aarch64
     170  
     171  static __always_inline void
     172  libc_feupdateenv_aarch64 (const fenv_t *envp)
     173  {
     174    libc_feupdateenv_test_aarch64 (envp, 0);
     175  }
     176  
     177  #define libc_feupdateenv  libc_feupdateenv_aarch64
     178  #define libc_feupdateenvf libc_feupdateenv_aarch64
     179  #define libc_feupdateenvl libc_feupdateenv_aarch64
     180  
     181  static __always_inline void
     182  libc_feholdsetround_aarch64 (fenv_t *envp, int round)
     183  {
     184    fpu_control_t fpcr;
     185    fpu_fpsr_t fpsr;
     186  
     187    _FPU_GETCW (fpcr);
     188    _FPU_GETFPSR (fpsr);
     189    envp->__fpcr = fpcr;
     190    envp->__fpsr = fpsr;
     191  
     192    /* Check whether rounding modes are different.  */
     193    round = (fpcr ^ round) & _FPU_FPCR_RM_MASK;
     194  
     195    /* Set new rounding mode if different.  */
     196    if (__glibc_unlikely (round != 0))
     197      _FPU_SETCW (fpcr ^ round);
     198  }
     199  
     200  #define libc_feholdsetround  libc_feholdsetround_aarch64
     201  #define libc_feholdsetroundf libc_feholdsetround_aarch64
     202  #define libc_feholdsetroundl libc_feholdsetround_aarch64
     203  
     204  static __always_inline void
     205  libc_feresetround_aarch64 (fenv_t *envp)
     206  {
     207    fpu_control_t fpcr;
     208    int round;
     209  
     210    _FPU_GETCW (fpcr);
     211  
     212    /* Check whether rounding modes are different.  */
     213    round = (envp->__fpcr ^ fpcr) & _FPU_FPCR_RM_MASK;
     214  
     215    /* Restore the rounding mode if it was changed.  */
     216    if (__glibc_unlikely (round != 0))
     217      _FPU_SETCW (fpcr ^ round);
     218  }
     219  
     220  #define libc_feresetround  libc_feresetround_aarch64
     221  #define libc_feresetroundf libc_feresetround_aarch64
     222  #define libc_feresetroundl libc_feresetround_aarch64
     223  
     224  /* We have support for rounding mode context.  */
     225  #define HAVE_RM_CTX 1
     226  
     227  static __always_inline void
     228  libc_feholdsetround_aarch64_ctx (struct rm_ctx *ctx, int r)
     229  {
     230    fpu_control_t fpcr;
     231    int round;
     232  
     233    _FPU_GETCW (fpcr);
     234    ctx->env.__fpcr = fpcr;
     235  
     236    /* Check whether rounding modes are different.  */
     237    round = (fpcr ^ r) & _FPU_FPCR_RM_MASK;
     238    ctx->updated_status = round != 0;
     239  
     240    /* Set the rounding mode if changed.  */
     241    if (__glibc_unlikely (round != 0))
     242      _FPU_SETCW (fpcr ^ round);
     243  }
     244  
     245  #define libc_feholdsetround_ctx		libc_feholdsetround_aarch64_ctx
     246  #define libc_feholdsetroundf_ctx	libc_feholdsetround_aarch64_ctx
     247  #define libc_feholdsetroundl_ctx	libc_feholdsetround_aarch64_ctx
     248  
     249  static __always_inline void
     250  libc_feresetround_aarch64_ctx (struct rm_ctx *ctx)
     251  {
     252    /* Restore the rounding mode if updated.  */
     253    if (__glibc_unlikely (ctx->updated_status))
     254      _FPU_SETCW (ctx->env.__fpcr);
     255  }
     256  
     257  #define libc_feresetround_ctx		libc_feresetround_aarch64_ctx
     258  #define libc_feresetroundf_ctx		libc_feresetround_aarch64_ctx
     259  #define libc_feresetroundl_ctx		libc_feresetround_aarch64_ctx
     260  
     261  static __always_inline void
     262  libc_feholdsetround_noex_aarch64_ctx (struct rm_ctx *ctx, int r)
     263  {
     264    fpu_control_t fpcr;
     265    fpu_fpsr_t fpsr;
     266    int round;
     267  
     268    _FPU_GETCW (fpcr);
     269    _FPU_GETFPSR (fpsr);
     270    ctx->env.__fpcr = fpcr;
     271    ctx->env.__fpsr = fpsr;
     272  
     273    /* Check whether rounding modes are different.  */
     274    round = (fpcr ^ r) & _FPU_FPCR_RM_MASK;
     275    ctx->updated_status = round != 0;
     276  
     277    /* Set the rounding mode if changed.  */
     278    if (__glibc_unlikely (round != 0))
     279      _FPU_SETCW (fpcr ^ round);
     280  }
     281  
     282  #define libc_feholdsetround_noex_ctx	libc_feholdsetround_noex_aarch64_ctx
     283  #define libc_feholdsetround_noexf_ctx	libc_feholdsetround_noex_aarch64_ctx
     284  #define libc_feholdsetround_noexl_ctx	libc_feholdsetround_noex_aarch64_ctx
     285  
     286  static __always_inline void
     287  libc_feresetround_noex_aarch64_ctx (struct rm_ctx *ctx)
     288  {
     289    /* Restore the rounding mode if updated.  */
     290    if (__glibc_unlikely (ctx->updated_status))
     291      _FPU_SETCW (ctx->env.__fpcr);
     292  
     293    /* Write new FPSR to restore exception flags.  */
     294    _FPU_SETFPSR (ctx->env.__fpsr);
     295  }
     296  
     297  #define libc_feresetround_noex_ctx	libc_feresetround_noex_aarch64_ctx
     298  #define libc_feresetround_noexf_ctx	libc_feresetround_noex_aarch64_ctx
     299  #define libc_feresetround_noexl_ctx	libc_feresetround_noex_aarch64_ctx
     300  
     301  #include_next <fenv_private.h>
     302  
     303  #endif