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