1 /* Raise given exceptions.
2    Copyright (C) 2001-2017 Free Software Foundation, Inc.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <http://www.gnu.org/licenses/>.  */
17 
18 #include <fenv.h>
19 #include <math.h>
20 
21 int
feraiseexcept(int excepts)22 feraiseexcept (int excepts)
23 {
24   /* Raise exceptions represented by EXPECTS.  But we must raise only
25      one signal at a time.  It is important that if the overflow/underflow
26      exception and the inexact exception are given at the same time,
27      the overflow/underflow exception follows the inexact exception.  */
28 
29   /* First: invalid exception.  */
30   if ((FE_INVALID & excepts) != 0)
31     {
32       /* One example of an invalid operation is 0.0 / 0.0.  */
33       float f = 0.0;
34 
35       __asm__ __volatile__ ("divss %0, %0 " : : "x" (f));
36       (void) &f;
37     }
38 
39   /* Next: division by zero.  */
40   if ((FE_DIVBYZERO & excepts) != 0)
41     {
42       float f = 1.0;
43       float g = 0.0;
44 
45       __asm__ __volatile__ ("divss %1, %0" : : "x" (f), "x" (g));
46       (void) &f;
47     }
48 
49   /* Next: overflow.  */
50   if ((FE_OVERFLOW & excepts) != 0)
51     {
52       /* XXX: Is it ok to only set the x87 FPU?  */
53       /* There is no way to raise only the overflow flag.  Do it the
54 	 hard way.  */
55       fenv_t temp;
56 
57       /* Bah, we have to clear selected exceptions.  Since there is no
58 	 `fldsw' instruction we have to do it the hard way.  */
59       __asm__ __volatile__ ("fnstenv %0" : "=m" (*&temp));
60 
61       /* Set the relevant bits.  */
62       temp.__status_word |= FE_OVERFLOW;
63 
64       /* Put the new data in effect.  */
65       __asm__ __volatile__ ("fldenv %0" : : "m" (*&temp));
66 
67       /* And raise the exception.  */
68       __asm__ __volatile__ ("fwait");
69     }
70 
71   /* Next: underflow.  */
72   if ((FE_UNDERFLOW & excepts) != 0)
73     {
74       /* XXX: Is it ok to only set the x87 FPU?  */
75       /* There is no way to raise only the underflow flag.  Do it the
76 	 hard way.  */
77       fenv_t temp;
78 
79       /* Bah, we have to clear selected exceptions.  Since there is no
80 	 `fldsw' instruction we have to do it the hard way.  */
81       __asm__ __volatile__ ("fnstenv %0" : "=m" (*&temp));
82 
83       /* Set the relevant bits.  */
84       temp.__status_word |= FE_UNDERFLOW;
85 
86       /* Put the new data in effect.  */
87       __asm__ __volatile__ ("fldenv %0" : : "m" (*&temp));
88 
89       /* And raise the exception.  */
90       __asm__ __volatile__ ("fwait");
91     }
92 
93   /* Last: inexact.  */
94   if ((FE_INEXACT & excepts) != 0)
95     {
96       /* XXX: Is it ok to only set the x87 FPU?  */
97       /* There is no way to raise only the inexact flag.  Do it the
98 	 hard way.  */
99       fenv_t temp;
100 
101       /* Bah, we have to clear selected exceptions.  Since there is no
102 	 `fldsw' instruction we have to do it the hard way.  */
103       __asm__ __volatile__ ("fnstenv %0" : "=m" (*&temp));
104 
105       /* Set the relevant bits.  */
106       temp.__status_word |= FE_INEXACT;
107 
108       /* Put the new data in effect.  */
109       __asm__ __volatile__ ("fldenv %0" : : "m" (*&temp));
110 
111       /* And raise the exception.  */
112       __asm__ __volatile__ ("fwait");
113     }
114 
115   /* Success.  */
116   return 0;
117 }
118