|
|
1.1 root 1: /* $Id: float.c,v 1.2 2005/05/14 22:08:07 fredette Exp $ */
2:
3: /* generic/float.c - generic native floating-point support: */
4:
5: /*
6: * Copyright (c) 2004 Matt Fredette
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Matt Fredette.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33: * POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: #include <tme/common.h>
37: _TME_RCSID("$Id: float.c,v 1.2 2005/05/14 22:08:07 fredette Exp $");
38:
39: /* includes: */
40: #include <tme/generic/float.h>
41: #include <signal.h>
42:
43: /* the mutex protecting the native floating point: */
44: static tme_mutex_t _tme_float_mutex;
45:
46: /* this is nonzero if the SIGFPE handler has been installed: */
47: /* XXX FIXME this assumes that a handler installed once in one thread
48: will catch signals for all threads. obviously, whether or not this
49: is true depends on how the threads package deals with signals: */
50: static int _tme_float_sigfpe_handler_installed;
51:
52: /* the current exceptions: */
53: static int _tme_float_exceptions;
54:
55: /* the user's exception handler: */
56: static void (*_tme_float_exception_handler) _TME_P((int, void *));
57: static void *_tme_float_exception_handler_private;
58:
59: /* update the current exceptions: */
60: static void
61: _tme_float_exceptions_update(int at_least_one)
62: {
63: int exceptions_new;
64: #ifdef HAVE_FPGETSTICKY
65: int sticky;
66: #endif /* HAVE_FPGETSTICKY */
67:
68: /* start with no new exceptions: */
69: exceptions_new = 0;
70:
71: /* get the exception status: */
72: #ifdef HAVE_FPGETSTICKY
73: sticky = fpgetsticky();
74: #define TME_FP_X_MAP(fp_x, float_x) if (sticky & (fp_x)) exceptions_new |= (float_x)
75: #ifdef FP_X_INV
76: TME_FP_X_MAP(FP_X_INV, TME_FLOAT_EXCEPTION_INVALID);
77: #endif
78: #ifdef FP_X_DNML
79: TME_FP_X_MAP(FP_X_DNML, TME_FLOAT_EXCEPTION_DENORMAL);
80: #endif
81: #ifdef FP_X_DZ
82: TME_FP_X_MAP(FP_X_DZ, TME_FLOAT_EXCEPTION_DIVBYZERO);
83: #endif
84: #ifdef FP_X_OFL
85: TME_FP_X_MAP(FP_X_OFL, TME_FLOAT_EXCEPTION_OVERFLOW);
86: #endif
87: #ifdef FP_X_UFL
88: TME_FP_X_MAP(FP_X_UFL, TME_FLOAT_EXCEPTION_UNDERFLOW);
89: #endif
90: #ifdef FP_X_IMP
91: TME_FP_X_MAP(FP_X_IMP, TME_FLOAT_EXCEPTION_INEXACT);
92: #endif
93: #ifdef FP_X_IOV
94: TME_FP_X_MAP(FP_X_IOV, TME_FLOAT_EXCEPTION_OVERFLOW_INT);
95: #endif
96: #undef TME_FP_X_MAP
97: #endif /* HAVE_FPGETSTICKY */
98:
99: /* if we have no new exceptions, but we should have at least one,
100: add in the generic exception: */
101: if (exceptions_new == 0
102: && at_least_one) {
103: exceptions_new |= TME_FLOAT_EXCEPTION_GENERIC;
104: }
105:
106: /* accumulate the new exceptions into the current exceptions: */
107: _tme_float_exceptions |= exceptions_new;
108:
109: /* clear the exception status: */
110: #ifdef HAVE_FPSETSTICKY
111: fpsetsticky(0);
112: #endif /* HAVE_FPSETSTICKY */
113: }
114:
115: /* our SIGFPE handler: */
116: static RETSIGTYPE
117: _tme_float_sigfpe_handler(int unused)
118: {
119:
120: /* update the current exceptions: */
121: _tme_float_exceptions_update(TRUE);
122:
123: /* call any user exception handler with the new exceptions: */
124: if (_tme_float_exception_handler != NULL) {
125: (*_tme_float_exception_handler)(_tme_float_exceptions, _tme_float_exception_handler_private);
126: }
127: }
128:
129: /* this enters native floating-point operation: */
130: void
131: tme_float_enter(int rounding_mode, void (*exception_handler)(int, void *), void *exception_handler_private)
132: {
133:
134: /* lock the native floating-point mutex: */
135: tme_mutex_lock(&_tme_float_mutex);
136:
137: /* set any user exception handler: */
138: _tme_float_exception_handler = exception_handler;
139: _tme_float_exception_handler_private = exception_handler_private;
140:
141: /* establish a signal handler: */
142: /* XXX FIXME this assumes that a handler installed once in one thread
143: will catch signals for all threads. obviously, whether or not this
144: is true depends on how the threads package deals with signals: */
145: if (!_tme_float_sigfpe_handler_installed) {
146: signal(SIGFPE, _tme_float_sigfpe_handler);
147: _tme_float_sigfpe_handler_installed = TRUE;
148: }
149:
150: /* set the rounding mode: */
151: #ifdef HAVE_FPSETROUND
152: fpsetround(rounding_mode);
153: #endif /* HAVE_FPSETROUND */
154:
155: /* clear the exception status: */
156: _tme_float_exceptions = 0;
157: #ifdef HAVE_FPSETSTICKY
158: fpsetsticky(0);
159: #endif /* HAVE_FPSETSTICKY */
160:
161: /* unmask all exceptions: */
162: #ifdef HAVE_FPSETMASK
163: fpsetmask(0
164: #ifdef FP_X_INV
165: | FP_X_INV
166: #endif
167: #ifdef FP_X_DNML
168: | FP_X_DNML
169: #endif
170: #ifdef FP_X_DZ
171: | FP_X_DZ
172: #endif
173: #ifdef FP_X_OFL
174: | FP_X_OFL
175: #endif
176: #ifdef FP_X_UFL
177: | FP_X_UFL
178: #endif
179: #ifdef FP_X_IMP
180: | FP_X_IMP
181: #endif
182: #ifdef FP_X_IOV
183: | FP_X_IOV
184: #endif
185: );
186: #endif /* HAVE_FPSETMASK */
187: }
188:
189: /* this returns the current native floating-point exceptions: */
190: int
191: tme_float_exceptions(void)
192: {
193: /* update and return the current exceptions: */
194: _tme_float_exceptions_update(FALSE);
195: return (_tme_float_exceptions);
196: }
197:
198: /* this leaves native floating-point operation: */
199: int
200: tme_float_leave(void)
201: {
202: int exceptions;
203:
204: /* get the final set of exceptions: */
205: exceptions = tme_float_exceptions();
206:
207: /* clear any user exception handler: */
208: _tme_float_exception_handler = NULL;
209:
210: /* unlock the native floating-point mutex: */
211: tme_mutex_unlock(&_tme_float_mutex);
212:
213: /* return the final set of exceptions: */
214: return (exceptions);
215: }
216:
217: /* missing standard functions: */
218: #ifndef HAVE_ISINFF
219: int
220: isinff(float x)
221: {
222: return (x > FLOAT_MAX_FLOAT
223: || x < (-FLOAT_MAX_FLOAT));
224: }
225: #endif /* !HAVE_ISINFF */
226:
227: /* include the automatically-generated code: */
228: #include "float-auto.c"
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.