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