(root)/
glibc-2.38/
sysdeps/
i386/
fpu/
fraiseexcpt.c
       1  /* Raise given exceptions.
       2     Copyright (C) 1997-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  #include <fenv.h>
      20  #include <math.h>
      21  
      22  int
      23  __feraiseexcept (int excepts)
      24  {
      25    /* Raise exceptions represented by EXPECTS.  But we must raise only
      26       one signal at a time.  It is important that if the overflow/underflow
      27       exception and the inexact exception are given at the same time,
      28       the overflow/underflow exception follows the inexact exception.  */
      29  
      30    /* First: invalid exception.  */
      31    if ((FE_INVALID & excepts) != 0)
      32      {
      33        /* One example of an invalid operation is 0.0 / 0.0.  */
      34        double d;
      35        __asm__ __volatile__ ("fldz; fdiv %%st, %%st(0); fwait" : "=t" (d));
      36        (void) &d;
      37      }
      38  
      39    /* Next: division by zero.  */
      40    if ((FE_DIVBYZERO & excepts) != 0)
      41      {
      42        double d;
      43        __asm__ __volatile__ ("fldz; fld1; fdivp %%st, %%st(1); fwait"
      44  			    : "=t" (d));
      45        (void) &d;
      46      }
      47  
      48    /* Next: overflow.  */
      49    if ((FE_OVERFLOW & excepts) != 0)
      50      {
      51        /* There is no way to raise only the overflow flag.  Do it the
      52  	 hard way.  */
      53        fenv_t temp;
      54  
      55        /* Bah, we have to clear selected exceptions.  Since there is no
      56  	 `fldsw' instruction we have to do it the hard way.  */
      57        __asm__ __volatile__ ("fnstenv %0" : "=m" (*&temp));
      58  
      59        /* Set the relevant bits.  */
      60        temp.__status_word |= FE_OVERFLOW;
      61  
      62        /* Put the new data in effect.  */
      63        __asm__ __volatile__ ("fldenv %0" : : "m" (*&temp));
      64  
      65        /* And raise the exception.  */
      66        __asm__ __volatile__ ("fwait");
      67      }
      68  
      69    /* Next: underflow.  */
      70    if ((FE_UNDERFLOW & excepts) != 0)
      71      {
      72        /* There is no way to raise only the underflow flag.  Do it the
      73  	 hard way.  */
      74        fenv_t temp;
      75  
      76        /* Bah, we have to clear selected exceptions.  Since there is no
      77  	 `fldsw' instruction we have to do it the hard way.  */
      78        __asm__ __volatile__ ("fnstenv %0" : "=m" (*&temp));
      79  
      80        /* Set the relevant bits.  */
      81        temp.__status_word |= FE_UNDERFLOW;
      82  
      83        /* Put the new data in effect.  */
      84        __asm__ __volatile__ ("fldenv %0" : : "m" (*&temp));
      85  
      86        /* And raise the exception.  */
      87        __asm__ __volatile__ ("fwait");
      88      }
      89  
      90    /* Last: inexact.  */
      91    if ((FE_INEXACT & excepts) != 0)
      92      {
      93        /* There is no way to raise only the inexact flag.  Do it the
      94  	 hard way.  */
      95        fenv_t temp;
      96  
      97        /* Bah, we have to clear selected exceptions.  Since there is no
      98  	 `fldsw' instruction we have to do it the hard way.  */
      99        __asm__ __volatile__ ("fnstenv %0" : "=m" (*&temp));
     100  
     101        /* Set the relevant bits.  */
     102        temp.__status_word |= FE_INEXACT;
     103  
     104        /* Put the new data in effect.  */
     105        __asm__ __volatile__ ("fldenv %0" : : "m" (*&temp));
     106  
     107        /* And raise the exception.  */
     108        __asm__ __volatile__ ("fwait");
     109      }
     110  
     111    /* Success.  */
     112    return 0;
     113  }
     114  
     115  #include <shlib-compat.h>
     116  #if SHLIB_COMPAT (libm, GLIBC_2_1, GLIBC_2_2)
     117  strong_alias (__feraiseexcept, __old_feraiseexcept)
     118  compat_symbol (libm, __old_feraiseexcept, feraiseexcept, GLIBC_2_1);
     119  #endif
     120  
     121  libm_hidden_def (__feraiseexcept)
     122  libm_hidden_ver (__feraiseexcept, feraiseexcept)
     123  versioned_symbol (libm, __feraiseexcept, feraiseexcept, GLIBC_2_2);