(root)/
glibc-2.38/
sysdeps/
loongarch/
math_private.h
       1  /* Internal math stuff.
       2     Copyright (C) 2022-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 LOONGARCH_MATH_PRIVATE_H
      20  #define LOONGARCH_MATH_PRIVATE_H 1
      21  
      22  /* Inline functions to speed up the math library implementation.  The
      23     default versions of these routines are in generic/math_private.h
      24     and call fesetround, feholdexcept, etc.  These routines use inlined
      25     code instead.  */
      26  
      27  #ifdef __loongarch_hard_float
      28  
      29  #include <fenv.h>
      30  #include <fenv_libc.h>
      31  #include <fpu_control.h>
      32  
      33  #define _FPU_MASK_ALL \
      34    (_FPU_MASK_V | _FPU_MASK_Z | _FPU_MASK_O | _FPU_MASK_U | _FPU_MASK_I \
      35     | FE_ALL_EXCEPT)
      36  
      37  static __always_inline void
      38  libc_feholdexcept_loongarch (fenv_t *envp)
      39  {
      40    fpu_control_t cw;
      41  
      42    /* Save the current state.  */
      43    _FPU_GETCW (cw);
      44    envp->__fp_control_register = cw;
      45  
      46    /* Clear all exception enable bits and flags.  */
      47    cw &= ~(_FPU_MASK_ALL);
      48    _FPU_SETCW (cw);
      49  }
      50  #define libc_feholdexcept libc_feholdexcept_loongarch
      51  #define libc_feholdexceptf libc_feholdexcept_loongarch
      52  #define libc_feholdexceptl libc_feholdexcept_loongarch
      53  
      54  static __always_inline void
      55  libc_fesetround_loongarch (int round)
      56  {
      57    fpu_control_t cw;
      58  
      59    /* Get current state.  */
      60    _FPU_GETCW (cw);
      61  
      62    /* Set rounding bits.  */
      63    cw &= ~_FPU_RC_MASK;
      64    cw |= round;
      65  
      66    /* Set new state.  */
      67    _FPU_SETCW (cw);
      68  }
      69  #define libc_fesetround libc_fesetround_loongarch
      70  #define libc_fesetroundf libc_fesetround_loongarch
      71  #define libc_fesetroundl libc_fesetround_loongarch
      72  
      73  static __always_inline void
      74  libc_feholdexcept_setround_loongarch (fenv_t *envp, int round)
      75  {
      76    fpu_control_t cw;
      77  
      78    /* Save the current state.  */
      79    _FPU_GETCW (cw);
      80    envp->__fp_control_register = cw;
      81  
      82    /* Clear all exception enable bits and flags.  */
      83    cw &= ~(_FPU_MASK_ALL);
      84  
      85    /* Set rounding bits.  */
      86    cw &= ~_FPU_RC_MASK;
      87    cw |= round;
      88  
      89    /* Set new state.  */
      90    _FPU_SETCW (cw);
      91  }
      92  #define libc_feholdexcept_setround libc_feholdexcept_setround_loongarch
      93  #define libc_feholdexcept_setroundf libc_feholdexcept_setround_loongarch
      94  #define libc_feholdexcept_setroundl libc_feholdexcept_setround_loongarch
      95  
      96  #define libc_feholdsetround libc_feholdexcept_setround_loongarch
      97  #define libc_feholdsetroundf libc_feholdexcept_setround_loongarch
      98  #define libc_feholdsetroundl libc_feholdexcept_setround_loongarch
      99  
     100  static __always_inline void
     101  libc_fesetenv_loongarch (fenv_t *envp)
     102  {
     103    fpu_control_t cw __attribute__ ((unused));
     104  
     105    /* Read current state to flush fpu pipeline.  */
     106    _FPU_GETCW (cw);
     107  
     108    _FPU_SETCW (envp->__fp_control_register);
     109  }
     110  #define libc_fesetenv libc_fesetenv_loongarch
     111  #define libc_fesetenvf libc_fesetenv_loongarch
     112  #define libc_fesetenvl libc_fesetenv_loongarch
     113  
     114  static __always_inline int
     115  libc_feupdateenv_test_loongarch (fenv_t *envp, int excepts)
     116  {
     117    /* int ret = fetestexcept (excepts); feupdateenv (envp); return ret; */
     118    int cw, temp;
     119  
     120    /* Get current control word.  */
     121    _FPU_GETCW (cw);
     122  
     123    /* Set flag bits (which are accumulative), and *also* set the
     124       cause bits.  The setting of the cause bits is what actually causes
     125       the hardware to generate the exception, if the corresponding enable
     126       bit is set as well.  */
     127    temp = cw & FE_ALL_EXCEPT;
     128    temp |= envp->__fp_control_register | (temp << CAUSE_SHIFT);
     129  
     130    /* Set new state.  */
     131    _FPU_SETCW (temp);
     132  
     133    return cw & excepts & FE_ALL_EXCEPT;
     134  }
     135  #define libc_feupdateenv_test libc_feupdateenv_test_loongarch
     136  #define libc_feupdateenv_testf libc_feupdateenv_test_loongarch
     137  #define libc_feupdateenv_testl libc_feupdateenv_test_loongarch
     138  
     139  static __always_inline void
     140  libc_feupdateenv_loongarch (fenv_t *envp)
     141  {
     142    libc_feupdateenv_test_loongarch (envp, 0);
     143  }
     144  #define libc_feupdateenv libc_feupdateenv_loongarch
     145  #define libc_feupdateenvf libc_feupdateenv_loongarch
     146  #define libc_feupdateenvl libc_feupdateenv_loongarch
     147  
     148  #define libc_feresetround libc_feupdateenv_loongarch
     149  #define libc_feresetroundf libc_feupdateenv_loongarch
     150  #define libc_feresetroundl libc_feupdateenv_loongarch
     151  
     152  static __always_inline int
     153  libc_fetestexcept_loongarch (int excepts)
     154  {
     155    int cw;
     156  
     157    /* Get current control word.  */
     158    _FPU_GETCW (cw);
     159  
     160    return cw & excepts & FE_ALL_EXCEPT;
     161  }
     162  #define libc_fetestexcept libc_fetestexcept_loongarch
     163  #define libc_fetestexceptf libc_fetestexcept_loongarch
     164  #define libc_fetestexceptl libc_fetestexcept_loongarch
     165  
     166  /*  Enable support for rounding mode context.  */
     167  #define HAVE_RM_CTX 1
     168  
     169  static __always_inline void
     170  libc_feholdexcept_setround_loongarch_ctx (struct rm_ctx *ctx, int round)
     171  {
     172    fpu_control_t old, new;
     173  
     174    /* Save the current state.  */
     175    _FPU_GETCW (old);
     176    ctx->env.__fp_control_register = old;
     177  
     178    /* Clear all exception enable bits and flags.  */
     179    new = old & ~(_FPU_MASK_ALL);
     180  
     181    /* Set rounding bits.  */
     182    new = (new & ~_FPU_RC_MASK) | round;
     183  
     184    if (__glibc_unlikely (new != old))
     185      {
     186        _FPU_SETCW (new);
     187        ctx->updated_status = true;
     188      }
     189    else
     190      ctx->updated_status = false;
     191  }
     192  #define libc_feholdexcept_setround_ctx libc_feholdexcept_setround_loongarch_ctx
     193  #define libc_feholdexcept_setroundf_ctx \
     194    libc_feholdexcept_setround_loongarch_ctx
     195  #define libc_feholdexcept_setroundl_ctx \
     196    libc_feholdexcept_setround_loongarch_ctx
     197  
     198  static __always_inline void
     199  libc_fesetenv_loongarch_ctx (struct rm_ctx *ctx)
     200  {
     201    libc_fesetenv_loongarch (&ctx->env);
     202  }
     203  #define libc_fesetenv_ctx libc_fesetenv_loongarch_ctx
     204  #define libc_fesetenvf_ctx libc_fesetenv_loongarch_ctx
     205  #define libc_fesetenvl_ctx libc_fesetenv_loongarch_ctx
     206  
     207  static __always_inline void
     208  libc_feupdateenv_loongarch_ctx (struct rm_ctx *ctx)
     209  {
     210    if (__glibc_unlikely (ctx->updated_status))
     211      libc_feupdateenv_test_loongarch (&ctx->env, 0);
     212  }
     213  #define libc_feupdateenv_ctx libc_feupdateenv_loongarch_ctx
     214  #define libc_feupdateenvf_ctx libc_feupdateenv_loongarch_ctx
     215  #define libc_feupdateenvl_ctx libc_feupdateenv_loongarch_ctx
     216  #define libc_feresetround_ctx libc_feupdateenv_loongarch_ctx
     217  #define libc_feresetroundf_ctx libc_feupdateenv_loongarch_ctx
     218  #define libc_feresetroundl_ctx libc_feupdateenv_loongarch_ctx
     219  
     220  static __always_inline void
     221  libc_feholdsetround_loongarch_ctx (struct rm_ctx *ctx, int round)
     222  {
     223    fpu_control_t old, new;
     224  
     225    /* Save the current state.  */
     226    _FPU_GETCW (old);
     227    ctx->env.__fp_control_register = old;
     228  
     229    /* Set rounding bits.  */
     230    new = (old & ~_FPU_RC_MASK) | round;
     231  
     232    if (__glibc_unlikely (new != old))
     233      {
     234        _FPU_SETCW (new);
     235        ctx->updated_status = true;
     236      }
     237    else
     238      ctx->updated_status = false;
     239  }
     240  #define libc_feholdsetround_ctx libc_feholdsetround_loongarch_ctx
     241  #define libc_feholdsetroundf_ctx libc_feholdsetround_loongarch_ctx
     242  #define libc_feholdsetroundl_ctx libc_feholdsetround_loongarch_ctx
     243  
     244  #endif
     245  
     246  #include_next <math_private.h>
     247  
     248  #endif