root/usr/src/head/ieeefp.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
 *
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*      Copyright (c) 1988 AT&T */
/*        All Rights Reserved */


#ifndef _IEEEFP_H
#define _IEEEFP_H

#ifdef  __cplusplus
extern "C" {
#endif

/*
 * Floating point enviornment for machines that support
 * the IEEE 754 floating-point standard.  This file currently
 * supports the 80*87, and SPARC families.
 *
 * This header defines the following interfaces:
 *      1) Classes of floating point numbers
 *      2) Rounding Control
 *      3) Exception Control
 *      4) Exception Handling
 *      5) Utility Macros
 *      6) Full Exception Environment Control
 */

/*
 * CLASSES of floating point numbers *************************
 * IEEE floating point values fall into 1 of the following 10
 * classes
 */
typedef enum    fpclass_t {
        FP_SNAN = 0,    /* signaling NaN */
        FP_QNAN = 1,    /* quiet NaN */
        FP_NINF = 2,    /* negative infinity */
        FP_PINF = 3,    /* positive infinity */
        FP_NDENORM = 4, /* negative denormalized non-zero */
        FP_PDENORM = 5, /* positive denormalized non-zero */
        FP_NZERO = 6,   /* -0.0 */
        FP_PZERO = 7,   /* +0.0 */
        FP_NNORM = 8,   /* negative normalized non-zero */
        FP_PNORM = 9    /* positive normalized non-zero */
} fpclass_t;

extern fpclass_t fpclass(double);       /* get class of double value */
extern int      finite(double);
extern int      unordered(double, double);

/*
 * ROUNDING CONTROL ******************************************
 *
 * At all times, floating-point math is done using one of four
 * mutually-exclusive rounding modes.
 */

#if defined(__i386) || defined(__amd64)

/*
 * NOTE: the values given are chosen to match those used by the
 * 80*87 rounding mode field in the control word.
 */
typedef enum    fp_rnd {
        FP_RN = 0,      /* round to nearest representable number, tie -> even */
        FP_RM = 1,      /* round toward minus infinity */
        FP_RP = 2,      /* round toward plus infinity */
        FP_RZ = 3       /* round toward zero (truncate) */
} fp_rnd;

#endif

#if defined(__sparc)

/*
 * NOTE: the values given are chosen to match those used by the
 * RD (Round Direction) field of the FSR (Floating Point State Register).
 */
typedef enum    fp_rnd {
        FP_RN = 0,      /* round to nearest representable number, tie -> even */
        FP_RZ = 1,      /* round toward zero (truncate) */
        FP_RP = 2,      /* round toward plus infinity */
        FP_RM = 3       /* round toward minus infinity */
} fp_rnd;

#endif

extern fp_rnd   fpsetround(fp_rnd);     /* set rounding mode, return previous */
extern fp_rnd   fpgetround(void);       /* return current rounding mode */

/*
 * EXCEPTION CONTROL *****************************************
 *
 */

#define fp_except       int

#define FP_DISABLE      0       /* exception will be ignored */
#define FP_ENABLE       1       /* exception will cause SIGFPE */
#define FP_CLEAR        0       /* exception has not occurred */
#define FP_SET          1       /* exception has occurred */

#if defined(__i386) || defined(__amd64)

/*
 * There are six floating point exceptions, which can be individually
 * ENABLED (== 1) or DISABLED (== 0).  When an exception occurs
 * (ENABLED or not), the fact is noted by changing an associated
 * "sticky bit" from CLEAR (==0) to SET (==1).
 *
 * NOTE: the bit positions in fp_except are chosen to match those of
 * the 80*87 control word mask bits.  Although the 87 chips actually
 * ENABLE exceptions with a mask value of 0 (not 1, as on the 3b), it
 * is felt that switching these values may create more problems than
 * it solves.
 */

/* an fp_except can have the following (not exclusive) values: */
#define FP_X_INV        0x01    /* invalid operation exception */
#define FP_X_DNML       0x02    /* denormalization exception */
#define FP_X_DZ         0x04    /* divide-by-zero exception */
#define FP_X_OFL        0x08    /* overflow exception */
#define FP_X_UFL        0x10    /* underflow exception */
#define FP_X_IMP        0x20    /* imprecise (loss of precision) */

#endif

#if defined(__sparc)

/*
 * There are five floating-point exceptions, which can be individually
 * ENABLED (== 1) or DISABLED (== 0).  When an exception occurs
 * (ENABLED or not), the fact is noted by changing an associated
 * "sticky bit" from CLEAR (==0) to SET (==1).
 *
 * NOTE: the bit positions in an fp_except are chosen to match that in
 * the Trap Enable Mask of the FSR (Floating Point State Register).
 */

/* an fp_except can have the following (not exclusive) values: */
#define FP_X_INV        0x10    /* invalid operation exception */
#define FP_X_OFL        0x08    /* overflow exception */
#define FP_X_UFL        0x04    /* underflow exception */
#define FP_X_DZ         0x02    /* divide-by-zero exception */
#define FP_X_IMP        0x01    /* imprecise (loss of precision) */

#endif

extern fp_except fpgetmask(void);               /* current exception mask */
extern fp_except fpsetmask(fp_except);          /* set mask, return previous */
extern fp_except fpgetsticky(void);             /* return logged exceptions */
extern fp_except fpsetsticky(fp_except);        /* change logged exceptions */

/*
 * UTILITY MACROS ********************************************
 */

extern int isnanf(float);
extern int isnand(double);

#if defined(__i386) || defined(__amd64)

/*
 * EXCEPTION HANDLING ****************************************
 *
 * When a signal handler catches an FPE, it will have a freshly initialized
 * coprocessor.  This allows signal handling routines to make use of
 * floating point arithmetic, if need be.  The previous state of the 87
 * chip is available, however.  There are two ways to get at this information,
 * depending on how the signal handler was set up.
 *
 * If the handler was set via signal() or sigset(), the old, SVR3, method
 * should be used: the signal handler assumes that it has a single parameter,
 * which is of type struct _fpstackframe, defined below.  By investigating
 * this parameter, the cause of the FPE may be determined.  By modifying it,
 * the state of the coprocessor can be changed upon return to the main task.
 * THIS METHOD IS OBSOLETE, AND MAY NOT BE SUPPORTED IN FUTURE RELEASES.
 *
 * If the handler was set via sigaction(), the new, SVR4, method should be
 * used: the third argument to the handler will be a pointer to a ucontext
 * structure (see sys/ucontext.h).  The uc_mcontext.fpregs member of the
 * ucontext structure holds the saved floating-point registers.  This can be
 * examined and/or modified.  By modifying it, the state of the coprocessor
 * can be changed upon return to the main task.
 */

struct _fpreg { /* structure of a temp real fp register */
        unsigned short significand[4];  /* 64 bit mantissa value */
        unsigned short exponent;        /* 15 bit exponent and sign bit */
};

#if defined(__i386)

/*
 * AMD64 users should use sigaction() as described above.
 */

struct _fpstackframe {          /* signal handler's argument */
        long signo;             /* signal number arg */
        long regs[19];          /* all registers */
        struct _fpstate *fpsp;  /* address of saved 387 state */
        char *wsp;              /* address of saved Weitek state */
};

#endif

#if defined(__i386) || defined(__amd64)

#if defined(__amd64)
#define _fpstate _fpstate32
#endif

struct _fpstate {               /* saved state info from an exception */
        unsigned int    cw,     /* control word */
                        sw,     /* status word after fnclex-not useful */
                        tag,    /* tag word */
                        ipoff,  /* %eip register */
                        cssel,  /* code segment selector */
                        dataoff, /* data operand address */
                        datasel; /* data operand selector */
        struct _fpreg _st[8];   /* saved register stack */
        unsigned int status;    /* status word saved at exception */
        unsigned int mxcsr;
        unsigned int xstatus;   /* status word saved at exception */
        unsigned int __pad[2];
        unsigned int xmm[8][4];
};

#if defined(__amd64)
#undef  _fpstate
#endif

#endif  /* __i386 || __amd64 */

/*
 * The structure of the 80*87 status and control words, and the mxcsr
 * register are given by the following structures.
 */
struct _cw87 {
        unsigned
                mask:   6,      /* exception masks */
                res1:   2,      /* not used */
                prec:   2,      /* precision control field */
                rnd:    2,      /* rounding control field */
                inf:    1,      /* infinity control (not on 387) */
                res2:   3;      /* not used */
};

struct _sw87 {
        unsigned
                excp:   6,      /* exception sticky bits */
                res1:   1,      /* not used */
                errs:   1,      /* error summary-set if unmasked excp */
                c012:   3,      /* condition code bits 0..2 */
                stkt:   3,      /* stack top pointer */
                c3:     1,      /* condition code bit 3 */
                busy:   1;      /* coprocessor busy */
};

struct _mxcsr {
        unsigned
                excp:   6,      /* exception sticky bits */
                daz:    1,      /* denormals are zeroes */
                mask:   6,      /* exception masks */
                rnd:    2,      /* rounding control */
                fzero:  1;      /* flush to zero */
};

#endif

#ifdef  __cplusplus
}
#endif

#endif  /* _IEEEFP_H */