(root)/
glibc-2.38/
sysdeps/
powerpc/
fpu/
fenv_private.h
       1  /* Private floating point rounding and exceptions handling. PowerPC version.
       2     Copyright (C) 2013-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 POWERPC_FENV_PRIVATE_H
      20  #define POWERPC_FENV_PRIVATE_H 1
      21  
      22  #include <fenv.h>
      23  #include <fenv_libc.h>
      24  #include <fpu_control.h>
      25  
      26  #ifdef _ARCH_PWR8
      27  /* There is no performance advantage to non-stop mode.  */
      28  /* The odd syntax here is to innocuously reference the given variables
      29     to prevent warnings about unused variables.  */
      30  #define __TEST_AND_BEGIN_NON_STOP(old, new) do {} while ((old) * (new) * 0 != 0)
      31  #define __TEST_AND_END_NON_STOP(old, new) do {} while ((old) * (new) * 0 != 0)
      32  #else
      33  #define __TEST_AND_BEGIN_NON_STOP __TEST_AND_ENTER_NON_STOP
      34  #define __TEST_AND_END_NON_STOP __TEST_AND_EXIT_NON_STOP
      35  #endif
      36  
      37  static __always_inline void
      38  libc_feholdexcept_setround_ppc (fenv_t *envp, int r)
      39  {
      40    fenv_union_t old, new;
      41  
      42    old.fenv = *envp = fegetenv_register ();
      43  
      44    __TEST_AND_BEGIN_NON_STOP (old.l, 0ULL);
      45  
      46    /* Clear everything and set the rounding mode.  */
      47    new.l = r;
      48    fesetenv_register (new.fenv);
      49  }
      50  
      51  static __always_inline unsigned long long
      52  __libc_femergeenv_ppc (const fenv_t *envp, unsigned long long old_mask,
      53  	unsigned long long new_mask)
      54  {
      55    fenv_union_t old, new;
      56  
      57    new.fenv = *envp;
      58    old.fenv = fegetenv_register ();
      59  
      60    /* Merge bits while masking unwanted bits from new and old env.  */
      61    new.l = (old.l & old_mask) | (new.l & new_mask);
      62  
      63    __TEST_AND_END_NON_STOP (old.l, new.l);
      64    __TEST_AND_BEGIN_NON_STOP (old.l, new.l);
      65  
      66    /* If requesting to keep status, replace control, and merge exceptions,
      67       and exceptions haven't changed, we can just set new control instead
      68       of the whole FPSCR.  */
      69    if ((old_mask & (FPSCR_CONTROL_MASK|FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK))
      70        == (FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK) &&
      71        (new_mask & (FPSCR_CONTROL_MASK|FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK))
      72        == (FPSCR_CONTROL_MASK|FPSCR_EXCEPTIONS_MASK) &&
      73        (old.l & FPSCR_EXCEPTIONS_MASK) == (new.l & FPSCR_EXCEPTIONS_MASK))
      74    {
      75      fesetenv_control (new.fenv);
      76    }
      77    else
      78      /* Atomically enable and raise (if appropriate) exceptions set in `new'.  */
      79      fesetenv_register (new.fenv);
      80  
      81    return old.l;
      82  }
      83  
      84  static __always_inline void
      85  libc_fesetenv_ppc (const fenv_t *envp)
      86  {
      87    /* Replace the entire environment.  */
      88    __libc_femergeenv_ppc (envp, 0LL, -1LL);
      89  }
      90  
      91  static __always_inline void
      92  libc_feresetround_ppc (fenv_t *envp)
      93  {
      94    fenv_union_t new = { .fenv = *envp };
      95    fegetenv_and_set_rn (new.l & FPSCR_RN_MASK);
      96  }
      97  
      98  static __always_inline int
      99  libc_feupdateenv_test_ppc (fenv_t *envp, int ex)
     100  {
     101    return __libc_femergeenv_ppc (envp, ~FPSCR_CONTROL_MASK,
     102  				~FPSCR_STATUS_MASK) & ex;
     103  }
     104  
     105  static __always_inline void
     106  libc_feupdateenv_ppc (fenv_t *e)
     107  {
     108    libc_feupdateenv_test_ppc (e, 0);
     109  }
     110  
     111  #define libc_feholdexceptf           libc_feholdexcept_ppc
     112  #define libc_feholdexcept            libc_feholdexcept_ppc
     113  #define libc_feholdexcept_setroundf  libc_feholdexcept_setround_ppc
     114  #define libc_feholdexcept_setround   libc_feholdexcept_setround_ppc
     115  #define libc_fetestexceptf           libc_fetestexcept_ppc
     116  #define libc_fetestexcept            libc_fetestexcept_ppc
     117  #define libc_fesetroundf             libc_fesetround_ppc
     118  #define libc_fesetround              libc_fesetround_ppc
     119  #define libc_fesetenvf               libc_fesetenv_ppc
     120  #define libc_fesetenv                libc_fesetenv_ppc
     121  #define libc_feupdateenv_testf       libc_feupdateenv_test_ppc
     122  #define libc_feupdateenv_test        libc_feupdateenv_test_ppc
     123  #define libc_feupdateenvf            libc_feupdateenv_ppc
     124  #define libc_feupdateenv             libc_feupdateenv_ppc
     125  #define libc_feholdsetroundf         libc_feholdsetround_ppc
     126  #define libc_feholdsetround          libc_feholdsetround_ppc
     127  #define libc_feresetroundf           libc_feresetround_ppc
     128  #define libc_feresetround            libc_feresetround_ppc
     129  
     130  
     131  /* We have support for rounding mode context.  */
     132  #define HAVE_RM_CTX 1
     133  
     134  static __always_inline void
     135  libc_feholdsetround_ppc_ctx (struct rm_ctx *ctx, int r)
     136  {
     137    fenv_union_t old;
     138  
     139    ctx->env = old.fenv = fegetenv_and_set_rn (r);
     140    ctx->updated_status = (r != (old.l & FPSCR_RN_MASK));
     141  }
     142  
     143  static __always_inline void
     144  libc_feholdsetround_noex_ppc_ctx (struct rm_ctx *ctx, int r)
     145  {
     146    fenv_union_t old, new;
     147  
     148    old.fenv = fegetenv_register ();
     149  
     150    new.l = (old.l & ~(FPSCR_ENABLES_MASK|FPSCR_RN_MASK)) | r;
     151  
     152    ctx->env = old.fenv;
     153    if (__glibc_unlikely (new.l != old.l))
     154      {
     155        __TEST_AND_BEGIN_NON_STOP (old.l, 0ULL);
     156        fesetenv_control (new.fenv);
     157        ctx->updated_status = true;
     158      }
     159    else
     160      ctx->updated_status = false;
     161  }
     162  
     163  static __always_inline void
     164  libc_fesetenv_ppc_ctx (struct rm_ctx *ctx)
     165  {
     166    libc_fesetenv_ppc (&ctx->env);
     167  }
     168  
     169  static __always_inline void
     170  libc_feupdateenv_ppc_ctx (struct rm_ctx *ctx)
     171  {
     172    if (__glibc_unlikely (ctx->updated_status))
     173      libc_feresetround_ppc (&ctx->env);
     174  }
     175  
     176  static __always_inline void
     177  libc_feresetround_ppc_ctx (struct rm_ctx *ctx)
     178  {
     179    if (__glibc_unlikely (ctx->updated_status))
     180      libc_feresetround_ppc (&ctx->env);
     181  }
     182  
     183  #define libc_fesetenv_ctx                libc_fesetenv_ppc_ctx
     184  #define libc_fesetenvf_ctx               libc_fesetenv_ppc_ctx
     185  #define libc_fesetenvl_ctx               libc_fesetenv_ppc_ctx
     186  #define libc_feholdsetround_ctx          libc_feholdsetround_ppc_ctx
     187  #define libc_feholdsetroundf_ctx         libc_feholdsetround_ppc_ctx
     188  #define libc_feholdsetroundl_ctx         libc_feholdsetround_ppc_ctx
     189  #define libc_feholdsetround_noex_ctx     libc_feholdsetround_noex_ppc_ctx
     190  #define libc_feholdsetround_noexf_ctx    libc_feholdsetround_noex_ppc_ctx
     191  #define libc_feholdsetround_noexl_ctx    libc_feholdsetround_noex_ppc_ctx
     192  #define libc_feresetround_ctx            libc_feresetround_ppc_ctx
     193  #define libc_feresetroundf_ctx           libc_feresetround_ppc_ctx
     194  #define libc_feresetroundl_ctx           libc_feresetround_ppc_ctx
     195  #define libc_feupdateenv_ctx             libc_feupdateenv_ppc_ctx
     196  #define libc_feupdateenvf_ctx            libc_feupdateenv_ppc_ctx
     197  #define libc_feupdateenvl_ctx            libc_feupdateenv_ppc_ctx
     198  
     199  #include_next <fenv_private.h>
     200  
     201  #endif