(root)/
glibc-2.38/
sysdeps/
x86_64/
fpu/
fraiseexcpt.c
       1  /* Raise given exceptions.
       2     Copyright (C) 2001-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        float f = 0.0;
      35  
      36        __asm__ __volatile__ ("divss %0, %0 " : "+x" (f));
      37        (void) &f;
      38      }
      39  
      40    /* Next: division by zero.  */
      41    if ((FE_DIVBYZERO & excepts) != 0)
      42      {
      43        float f = 1.0;
      44        float g = 0.0;
      45  
      46        __asm__ __volatile__ ("divss %1, %0" : "+x" (f) : "x" (g));
      47        (void) &f;
      48      }
      49  
      50    /* Next: overflow.  */
      51    if ((FE_OVERFLOW & excepts) != 0)
      52      {
      53        /* XXX: Is it ok to only set the x87 FPU?  */
      54        /* There is no way to raise only the overflow flag.  Do it the
      55  	 hard way.  */
      56        fenv_t temp;
      57  
      58        /* Bah, we have to clear selected exceptions.  Since there is no
      59  	 `fldsw' instruction we have to do it the hard way.  */
      60        __asm__ __volatile__ ("fnstenv %0" : "=m" (*&temp));
      61  
      62        /* Set the relevant bits.  */
      63        temp.__status_word |= FE_OVERFLOW;
      64  
      65        /* Put the new data in effect.  */
      66        __asm__ __volatile__ ("fldenv %0" : : "m" (*&temp));
      67  
      68        /* And raise the exception.  */
      69        __asm__ __volatile__ ("fwait");
      70      }
      71  
      72    /* Next: underflow.  */
      73    if ((FE_UNDERFLOW & excepts) != 0)
      74      {
      75        /* XXX: Is it ok to only set the x87 FPU?  */
      76        /* There is no way to raise only the underflow flag.  Do it the
      77  	 hard way.  */
      78        fenv_t temp;
      79  
      80        /* Bah, we have to clear selected exceptions.  Since there is no
      81  	 `fldsw' instruction we have to do it the hard way.  */
      82        __asm__ __volatile__ ("fnstenv %0" : "=m" (*&temp));
      83  
      84        /* Set the relevant bits.  */
      85        temp.__status_word |= FE_UNDERFLOW;
      86  
      87        /* Put the new data in effect.  */
      88        __asm__ __volatile__ ("fldenv %0" : : "m" (*&temp));
      89  
      90        /* And raise the exception.  */
      91        __asm__ __volatile__ ("fwait");
      92      }
      93  
      94    /* Last: inexact.  */
      95    if ((FE_INEXACT & excepts) != 0)
      96      {
      97        /* XXX: Is it ok to only set the x87 FPU?  */
      98        /* There is no way to raise only the inexact flag.  Do it the
      99  	 hard way.  */
     100        fenv_t temp;
     101  
     102        /* Bah, we have to clear selected exceptions.  Since there is no
     103  	 `fldsw' instruction we have to do it the hard way.  */
     104        __asm__ __volatile__ ("fnstenv %0" : "=m" (*&temp));
     105  
     106        /* Set the relevant bits.  */
     107        temp.__status_word |= FE_INEXACT;
     108  
     109        /* Put the new data in effect.  */
     110        __asm__ __volatile__ ("fldenv %0" : : "m" (*&temp));
     111  
     112        /* And raise the exception.  */
     113        __asm__ __volatile__ ("fwait");
     114      }
     115  
     116    /* Success.  */
     117    return 0;
     118  }
     119  libm_hidden_def (__feraiseexcept)
     120  weak_alias (__feraiseexcept, feraiseexcept)
     121  libm_hidden_weak (feraiseexcept)