1 /* Raise given exceptions.
2    Copyright (C) 2001-2022 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
__feraiseexcept(int excepts)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)
122