1 /* Raise given exceptions.
2 Copyright (C) 1997,99,2000,01,02 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
19
20 #include <fenv.h>
21 #include <math.h>
22
libm_hidden_proto(feraiseexcept)23 libm_hidden_proto(feraiseexcept)
24
25 int
26 feraiseexcept (int excepts)
27 {
28 /* Raise exceptions represented by EXPECTS. But we must raise only
29 one signal at a time. It is important that if the overflow/underflow
30 exception and the inexact exception are given at the same time,
31 the overflow/underflow exception follows the inexact exception. */
32
33 /* First: invalid exception. */
34 if ((FE_INVALID & excepts) != 0)
35 {
36 /* One example of a invalid operation is 0.0 / 0.0. */
37 double d;
38 __asm__ __volatile__ ("fldz; fdiv %%st, %%st(0); fwait" : "=t" (d));
39 (void) &d;
40 }
41
42 /* Next: division by zero. */
43 if ((FE_DIVBYZERO & excepts) != 0)
44 {
45 double d;
46 __asm__ __volatile__ ("fldz; fld1; fdivp %%st, %%st(1); fwait"
47 : "=t" (d));
48 (void) &d;
49 }
50
51 /* Next: overflow. */
52 if ((FE_OVERFLOW & excepts) != 0)
53 {
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 /* 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 /* There is no way to raise only the inexact flag. Do it the
97 hard way. */
98 fenv_t temp;
99
100 /* Bah, we have to clear selected exceptions. Since there is no
101 `fldsw' instruction we have to do it the hard way. */
102 __asm__ __volatile__ ("fnstenv %0" : "=m" (*&temp));
103
104 /* Set the relevant bits. */
105 temp.__status_word |= FE_INEXACT;
106
107 /* Put the new data in effect. */
108 __asm__ __volatile__ ("fldenv %0" : : "m" (*&temp));
109
110 /* And raise the exception. */
111 __asm__ __volatile__ ("fwait");
112 }
113
114 /* Success. */
115 return 0;
116 }
117 libm_hidden_def(feraiseexcept)
118