1 /* Raise given exceptions.
2 Copyright (C) 1997-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 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);
124