mirror of
https://github.com/phabrics/Run-Sun3-SunOS-4.1.1.git
synced 2026-04-29 11:02:59 -04:00
229 lines
6.6 KiB
C
229 lines
6.6 KiB
C
/* $Id: float.c,v 1.2 2005/05/14 22:08:07 fredette Exp $ */
|
|
|
|
/* generic/float.c - generic native floating-point support: */
|
|
|
|
/*
|
|
* Copyright (c) 2004 Matt Fredette
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Matt Fredette.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <tme/common.h>
|
|
_TME_RCSID("$Id: float.c,v 1.2 2005/05/14 22:08:07 fredette Exp $");
|
|
|
|
/* includes: */
|
|
#include <tme/generic/float.h>
|
|
#include <signal.h>
|
|
|
|
/* the mutex protecting the native floating point: */
|
|
static tme_mutex_t _tme_float_mutex;
|
|
|
|
/* this is nonzero if the SIGFPE handler has been installed: */
|
|
/* XXX FIXME this assumes that a handler installed once in one thread
|
|
will catch signals for all threads. obviously, whether or not this
|
|
is true depends on how the threads package deals with signals: */
|
|
static int _tme_float_sigfpe_handler_installed;
|
|
|
|
/* the current exceptions: */
|
|
static int _tme_float_exceptions;
|
|
|
|
/* the user's exception handler: */
|
|
static void (*_tme_float_exception_handler) _TME_P((int, void *));
|
|
static void *_tme_float_exception_handler_private;
|
|
|
|
/* update the current exceptions: */
|
|
static void
|
|
_tme_float_exceptions_update(int at_least_one)
|
|
{
|
|
int exceptions_new;
|
|
#ifdef HAVE_FPGETSTICKY
|
|
int sticky;
|
|
#endif /* HAVE_FPGETSTICKY */
|
|
|
|
/* start with no new exceptions: */
|
|
exceptions_new = 0;
|
|
|
|
/* get the exception status: */
|
|
#ifdef HAVE_FPGETSTICKY
|
|
sticky = fpgetsticky();
|
|
#define TME_FP_X_MAP(fp_x, float_x) if (sticky & (fp_x)) exceptions_new |= (float_x)
|
|
#ifdef FP_X_INV
|
|
TME_FP_X_MAP(FP_X_INV, TME_FLOAT_EXCEPTION_INVALID);
|
|
#endif
|
|
#ifdef FP_X_DNML
|
|
TME_FP_X_MAP(FP_X_DNML, TME_FLOAT_EXCEPTION_DENORMAL);
|
|
#endif
|
|
#ifdef FP_X_DZ
|
|
TME_FP_X_MAP(FP_X_DZ, TME_FLOAT_EXCEPTION_DIVBYZERO);
|
|
#endif
|
|
#ifdef FP_X_OFL
|
|
TME_FP_X_MAP(FP_X_OFL, TME_FLOAT_EXCEPTION_OVERFLOW);
|
|
#endif
|
|
#ifdef FP_X_UFL
|
|
TME_FP_X_MAP(FP_X_UFL, TME_FLOAT_EXCEPTION_UNDERFLOW);
|
|
#endif
|
|
#ifdef FP_X_IMP
|
|
TME_FP_X_MAP(FP_X_IMP, TME_FLOAT_EXCEPTION_INEXACT);
|
|
#endif
|
|
#ifdef FP_X_IOV
|
|
TME_FP_X_MAP(FP_X_IOV, TME_FLOAT_EXCEPTION_OVERFLOW_INT);
|
|
#endif
|
|
#undef TME_FP_X_MAP
|
|
#endif /* HAVE_FPGETSTICKY */
|
|
|
|
/* if we have no new exceptions, but we should have at least one,
|
|
add in the generic exception: */
|
|
if (exceptions_new == 0
|
|
&& at_least_one) {
|
|
exceptions_new |= TME_FLOAT_EXCEPTION_GENERIC;
|
|
}
|
|
|
|
/* accumulate the new exceptions into the current exceptions: */
|
|
_tme_float_exceptions |= exceptions_new;
|
|
|
|
/* clear the exception status: */
|
|
#ifdef HAVE_FPSETSTICKY
|
|
fpsetsticky(0);
|
|
#endif /* HAVE_FPSETSTICKY */
|
|
}
|
|
|
|
/* our SIGFPE handler: */
|
|
static RETSIGTYPE
|
|
_tme_float_sigfpe_handler(int unused)
|
|
{
|
|
|
|
/* update the current exceptions: */
|
|
_tme_float_exceptions_update(TRUE);
|
|
|
|
/* call any user exception handler with the new exceptions: */
|
|
if (_tme_float_exception_handler != NULL) {
|
|
(*_tme_float_exception_handler)(_tme_float_exceptions, _tme_float_exception_handler_private);
|
|
}
|
|
}
|
|
|
|
/* this enters native floating-point operation: */
|
|
void
|
|
tme_float_enter(int rounding_mode, void (*exception_handler)(int, void *), void *exception_handler_private)
|
|
{
|
|
|
|
/* lock the native floating-point mutex: */
|
|
tme_mutex_lock(&_tme_float_mutex);
|
|
|
|
/* set any user exception handler: */
|
|
_tme_float_exception_handler = exception_handler;
|
|
_tme_float_exception_handler_private = exception_handler_private;
|
|
|
|
/* establish a signal handler: */
|
|
/* XXX FIXME this assumes that a handler installed once in one thread
|
|
will catch signals for all threads. obviously, whether or not this
|
|
is true depends on how the threads package deals with signals: */
|
|
if (!_tme_float_sigfpe_handler_installed) {
|
|
signal(SIGFPE, _tme_float_sigfpe_handler);
|
|
_tme_float_sigfpe_handler_installed = TRUE;
|
|
}
|
|
|
|
/* set the rounding mode: */
|
|
#ifdef HAVE_FPSETROUND
|
|
fpsetround(rounding_mode);
|
|
#endif /* HAVE_FPSETROUND */
|
|
|
|
/* clear the exception status: */
|
|
_tme_float_exceptions = 0;
|
|
#ifdef HAVE_FPSETSTICKY
|
|
fpsetsticky(0);
|
|
#endif /* HAVE_FPSETSTICKY */
|
|
|
|
/* unmask all exceptions: */
|
|
#ifdef HAVE_FPSETMASK
|
|
fpsetmask(0
|
|
#ifdef FP_X_INV
|
|
| FP_X_INV
|
|
#endif
|
|
#ifdef FP_X_DNML
|
|
| FP_X_DNML
|
|
#endif
|
|
#ifdef FP_X_DZ
|
|
| FP_X_DZ
|
|
#endif
|
|
#ifdef FP_X_OFL
|
|
| FP_X_OFL
|
|
#endif
|
|
#ifdef FP_X_UFL
|
|
| FP_X_UFL
|
|
#endif
|
|
#ifdef FP_X_IMP
|
|
| FP_X_IMP
|
|
#endif
|
|
#ifdef FP_X_IOV
|
|
| FP_X_IOV
|
|
#endif
|
|
);
|
|
#endif /* HAVE_FPSETMASK */
|
|
}
|
|
|
|
/* this returns the current native floating-point exceptions: */
|
|
int
|
|
tme_float_exceptions(void)
|
|
{
|
|
/* update and return the current exceptions: */
|
|
_tme_float_exceptions_update(FALSE);
|
|
return (_tme_float_exceptions);
|
|
}
|
|
|
|
/* this leaves native floating-point operation: */
|
|
int
|
|
tme_float_leave(void)
|
|
{
|
|
int exceptions;
|
|
|
|
/* get the final set of exceptions: */
|
|
exceptions = tme_float_exceptions();
|
|
|
|
/* clear any user exception handler: */
|
|
_tme_float_exception_handler = NULL;
|
|
|
|
/* unlock the native floating-point mutex: */
|
|
tme_mutex_unlock(&_tme_float_mutex);
|
|
|
|
/* return the final set of exceptions: */
|
|
return (exceptions);
|
|
}
|
|
|
|
/* missing standard functions: */
|
|
#ifndef HAVE_ISINFF
|
|
int
|
|
isinff(float x)
|
|
{
|
|
return (x > FLOAT_MAX_FLOAT
|
|
|| x < (-FLOAT_MAX_FLOAT));
|
|
}
|
|
#endif /* !HAVE_ISINFF */
|
|
|
|
/* include the automatically-generated code: */
|
|
#include "float-auto.c"
|