(root)/
glibc-2.38/
sysdeps/
s390/
fpu/
fenv_private.h
       1  /* Private floating point rounding and exceptions handling.  390/s390x version.
       2     Copyright (C) 2019-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 S390_FENV_PRIVATE_H
      20  #define S390_FENV_PRIVATE_H 1
      21  
      22  #include <fenv.h>
      23  #include <fenv_libc.h>
      24  #include <fpu_control.h>
      25  
      26  static __always_inline void
      27  libc_feholdexcept_s390 (fenv_t *envp)
      28  {
      29    fpu_control_t fpc, fpc_new;
      30  
      31    /* Store the environment.  */
      32    _FPU_GETCW (fpc);
      33    envp->__fpc = fpc;
      34  
      35    /* Clear the current exception flags and dxc field.
      36       Hold from generating fpu exceptions temporarily.  */
      37    fpc_new = fpc & ~(FPC_FLAGS_MASK | FPC_DXC_MASK | FPC_EXCEPTION_MASK);
      38  
      39    /* Only set new environment if it has changed.  */
      40    if (fpc_new != fpc)
      41      _FPU_SETCW (fpc_new);
      42  }
      43  
      44  #define libc_feholdexcept  libc_feholdexcept_s390
      45  #define libc_feholdexceptf libc_feholdexcept_s390
      46  #define libc_feholdexceptl libc_feholdexcept_s390
      47  
      48  static __always_inline void
      49  libc_fesetround_s390 (int round)
      50  {
      51    __asm__ __volatile__ ("srnm 0(%0)" : : "a" (round));
      52  }
      53  
      54  #define libc_fesetround  libc_fesetround_s390
      55  #define libc_fesetroundf libc_fesetround_s390
      56  #define libc_fesetroundl libc_fesetround_s390
      57  
      58  static __always_inline void
      59  libc_feholdexcept_setround_s390 (fenv_t *envp, int r)
      60  {
      61    fpu_control_t fpc, fpc_new;
      62  
      63    _FPU_GETCW (fpc);
      64    envp->__fpc = fpc;
      65  
      66    /* Clear the current exception flags and dxc field.
      67       Hold from generating fpu exceptions temporarily.
      68       Reset rounding mode bits.  */
      69    fpc_new = fpc & ~(FPC_FLAGS_MASK | FPC_DXC_MASK | FPC_EXCEPTION_MASK
      70  		    | FPC_RM_MASK);
      71  
      72    /* Set new rounding mode.  */
      73    fpc_new |= (r & FPC_RM_MASK);
      74  
      75    /* Only set new environment if it has changed.  */
      76    if (fpc_new != fpc)
      77      _FPU_SETCW (fpc_new);
      78  }
      79  
      80  #define libc_feholdexcept_setround  libc_feholdexcept_setround_s390
      81  #define libc_feholdexcept_setroundf libc_feholdexcept_setround_s390
      82  #define libc_feholdexcept_setroundl libc_feholdexcept_setround_s390
      83  
      84  static __always_inline int
      85  libc_fetestexcept_s390 (int excepts)
      86  {
      87    int res;
      88    fexcept_t fpc;
      89  
      90    _FPU_GETCW (fpc);
      91  
      92    /* Get current exceptions.  */
      93    res = (fpc >> FPC_FLAGS_SHIFT) & FE_ALL_EXCEPT;
      94    if ((fpc & FPC_NOT_FPU_EXCEPTION) == 0)
      95      /* Bits 6, 7 of dxc-byte are zero,
      96         thus bits 0-5 of dxc-byte correspond to the flag-bits.
      97         Evaluate flags and last dxc-exception-code.  */
      98      res |= (fpc >> FPC_DXC_SHIFT) & FE_ALL_EXCEPT;
      99  
     100    return res & excepts;
     101  }
     102  
     103  #define libc_fetestexcept  libc_fetestexcept_s390
     104  #define libc_fetestexceptf libc_fetestexcept_s390
     105  #define libc_fetestexceptl libc_fetestexcept_s390
     106  
     107  static __always_inline void
     108  libc_fesetenv_s390 (const fenv_t *envp)
     109  {
     110    _FPU_SETCW (envp->__fpc);
     111  }
     112  
     113  #define libc_fesetenv  libc_fesetenv_s390
     114  #define libc_fesetenvf libc_fesetenv_s390
     115  #define libc_fesetenvl libc_fesetenv_s390
     116  
     117  static __always_inline int
     118  libc_feupdateenv_test_s390 (const fenv_t *envp, int ex)
     119  {
     120    /* Get the currently raised exceptions.  */
     121    int excepts;
     122    fexcept_t fpc_old;
     123  
     124    _FPU_GETCW (fpc_old);
     125  
     126    /* Get current exceptions.  */
     127    excepts = (fpc_old >> FPC_FLAGS_SHIFT) & FE_ALL_EXCEPT;
     128    if ((fpc_old & FPC_NOT_FPU_EXCEPTION) == 0)
     129      /* Bits 6, 7 of dxc-byte are zero,
     130         thus bits 0-5 of dxc-byte correspond to the flag-bits.
     131         Evaluate flags and last dxc-exception-code.  */
     132      excepts |= (fpc_old >> FPC_DXC_SHIFT) & FE_ALL_EXCEPT;
     133  
     134    /* Merge the currently raised exceptions with those in envp.  */
     135    fpu_control_t fpc_new = envp->__fpc;
     136    fpc_new |= excepts << FPC_FLAGS_SHIFT;
     137  
     138    /* Install the new fpc from envp.  */
     139    if (fpc_new != fpc_old)
     140      _FPU_SETCW (fpc_new);
     141  
     142    /* Raise the exceptions if enabled in new fpc.  */
     143    if (__glibc_unlikely ((fpc_new >> FPC_EXCEPTION_MASK_SHIFT) & excepts))
     144      __feraiseexcept (excepts);
     145  
     146    return excepts & ex;
     147  }
     148  
     149  #define libc_feupdateenv_test  libc_feupdateenv_test_s390
     150  #define libc_feupdateenv_testf libc_feupdateenv_test_s390
     151  #define libc_feupdateenv_testl libc_feupdateenv_test_s390
     152  
     153  static __always_inline void
     154  libc_feupdateenv_s390 (const fenv_t *envp)
     155  {
     156    libc_feupdateenv_test_s390 (envp, 0);
     157  }
     158  
     159  #define libc_feupdateenv  libc_feupdateenv_s390
     160  #define libc_feupdateenvf libc_feupdateenv_s390
     161  #define libc_feupdateenvl libc_feupdateenv_s390
     162  
     163  static __always_inline fenv_t
     164  libc_handle_user_fenv_s390 (const fenv_t *envp)
     165  {
     166    fenv_t env;
     167    if (envp == FE_DFL_ENV)
     168      {
     169        env.__fpc = _FPU_DEFAULT;
     170      }
     171    else if (envp == FE_NOMASK_ENV)
     172      {
     173        env.__fpc = FPC_EXCEPTION_MASK;
     174      }
     175    else
     176      env = (*envp);
     177  
     178    return env;
     179  }
     180  
     181  /* We have support for rounding mode context.  */
     182  #define HAVE_RM_CTX 1
     183  
     184  static __always_inline void
     185  libc_feholdsetround_s390_ctx (struct rm_ctx *ctx, int r)
     186  {
     187    fpu_control_t fpc;
     188    int round;
     189  
     190    _FPU_GETCW (fpc);
     191    ctx->env.__fpc = fpc;
     192  
     193    /* Check whether rounding modes are different.  */
     194    round = fpc & FPC_RM_MASK;
     195  
     196    /* Set the rounding mode if changed.  */
     197    if (__glibc_unlikely (round != r))
     198      {
     199        ctx->updated_status = true;
     200        libc_fesetround_s390 (r);
     201      }
     202    else
     203      ctx->updated_status = false;
     204  }
     205  
     206  #define libc_feholdsetround_ctx		libc_feholdsetround_s390_ctx
     207  #define libc_feholdsetroundf_ctx	libc_feholdsetround_s390_ctx
     208  #define libc_feholdsetroundl_ctx	libc_feholdsetround_s390_ctx
     209  
     210  static __always_inline void
     211  libc_feresetround_s390_ctx (struct rm_ctx *ctx)
     212  {
     213    /* Restore the rounding mode if updated.  */
     214    if (__glibc_unlikely (ctx->updated_status))
     215      {
     216        fpu_control_t fpc;
     217        _FPU_GETCW (fpc);
     218        fpc = ctx->env.__fpc | (fpc & FPC_FLAGS_MASK);
     219        _FPU_SETCW (fpc);
     220      }
     221  }
     222  
     223  #define libc_feresetround_ctx		libc_feresetround_s390_ctx
     224  #define libc_feresetroundf_ctx		libc_feresetround_s390_ctx
     225  #define libc_feresetroundl_ctx		libc_feresetround_s390_ctx
     226  
     227  static __always_inline void
     228  libc_feholdsetround_noex_s390_ctx (struct rm_ctx *ctx, int r)
     229  {
     230    libc_feholdexcept_setround_s390 (&ctx->env, r);
     231  }
     232  
     233  #define libc_feholdsetround_noex_ctx	libc_feholdsetround_noex_s390_ctx
     234  #define libc_feholdsetround_noexf_ctx	libc_feholdsetround_noex_s390_ctx
     235  #define libc_feholdsetround_noexl_ctx	libc_feholdsetround_noex_s390_ctx
     236  
     237  static __always_inline void
     238  libc_feresetround_noex_s390_ctx (struct rm_ctx *ctx)
     239  {
     240    /* Restore exception flags and rounding mode.  */
     241    libc_fesetenv_s390 (&ctx->env);
     242  }
     243  
     244  #define libc_feresetround_noex_ctx	libc_feresetround_noex_s390_ctx
     245  #define libc_feresetround_noexf_ctx	libc_feresetround_noex_s390_ctx
     246  #define libc_feresetround_noexl_ctx	libc_feresetround_noex_s390_ctx
     247  
     248  #include_next <fenv_private.h>
     249  
     250  #endif