1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  24  *
  25  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  26  * Use is subject to license terms.
  27  */
  28 
  29 /*      Copyright (c) 1988 AT&T */
  30 /*        All Rights Reserved */
  31 
  32 
  33 #ifndef _IEEEFP_H
  34 #define _IEEEFP_H
  35 
  36 #ifdef  __cplusplus
  37 extern "C" {
  38 #endif
  39 
  40 /*
  41  * Floating point enviornment for machines that support
  42  * the IEEE 754 floating-point standard.  This file currently
  43  * supports the 80*87, and SPARC families.
  44  *
  45  * This header defines the following interfaces:
  46  *      1) Classes of floating point numbers
  47  *      2) Rounding Control
  48  *      3) Exception Control
  49  *      4) Exception Handling
  50  *      5) Utility Macros
  51  *      6) Full Exception Environment Control
  52  */
  53 
  54 /*
  55  * CLASSES of floating point numbers *************************
  56  * IEEE floating point values fall into 1 of the following 10
  57  * classes
  58  */
  59 typedef enum    fpclass_t {
  60         FP_SNAN = 0,    /* signaling NaN */
  61         FP_QNAN = 1,    /* quiet NaN */
  62         FP_NINF = 2,    /* negative infinity */
  63         FP_PINF = 3,    /* positive infinity */
  64         FP_NDENORM = 4, /* negative denormalized non-zero */
  65         FP_PDENORM = 5, /* positive denormalized non-zero */
  66         FP_NZERO = 6,   /* -0.0 */
  67         FP_PZERO = 7,   /* +0.0 */
  68         FP_NNORM = 8,   /* negative normalized non-zero */
  69         FP_PNORM = 9    /* positive normalized non-zero */
  70 } fpclass_t;
  71 
  72 extern fpclass_t fpclass(double);       /* get class of double value */
  73 extern int      finite(double);
  74 extern int      unordered(double, double);
  75 
  76 /*
  77  * ROUNDING CONTROL ******************************************
  78  *
  79  * At all times, floating-point math is done using one of four
  80  * mutually-exclusive rounding modes.
  81  */
  82 
  83 #if defined(__i386) || defined(__amd64)
  84 
  85 /*
  86  * NOTE: the values given are chosen to match those used by the
  87  * 80*87 rounding mode field in the control word.
  88  */
  89 typedef enum    fp_rnd {
  90         FP_RN = 0,      /* round to nearest representable number, tie -> even */
  91         FP_RM = 1,      /* round toward minus infinity */
  92         FP_RP = 2,      /* round toward plus infinity */
  93         FP_RZ = 3       /* round toward zero (truncate) */
  94 } fp_rnd;
  95 
  96 #endif
  97 
  98 #if defined(__sparc)
  99 
 100 /*
 101  * NOTE: the values given are chosen to match those used by the
 102  * RD (Round Direction) field of the FSR (Floating Point State Register).
 103  */
 104 typedef enum    fp_rnd {
 105         FP_RN = 0,      /* round to nearest representable number, tie -> even */
 106         FP_RZ = 1,      /* round toward zero (truncate) */
 107         FP_RP = 2,      /* round toward plus infinity */
 108         FP_RM = 3       /* round toward minus infinity */
 109 } fp_rnd;
 110 
 111 #endif
 112 
 113 extern fp_rnd   fpsetround(fp_rnd);     /* set rounding mode, return previous */
 114 extern fp_rnd   fpgetround(void);       /* return current rounding mode */
 115 
 116 /*
 117  * EXCEPTION CONTROL *****************************************
 118  *
 119  */
 120 
 121 #define fp_except       int
 122 
 123 #define FP_DISABLE      0       /* exception will be ignored */
 124 #define FP_ENABLE       1       /* exception will cause SIGFPE */
 125 #define FP_CLEAR        0       /* exception has not occurred */
 126 #define FP_SET          1       /* exception has occurred */
 127 
 128 #if defined(__i386) || defined(__amd64)
 129 
 130 /*
 131  * There are six floating point exceptions, which can be individually
 132  * ENABLED (== 1) or DISABLED (== 0).  When an exception occurs
 133  * (ENABLED or not), the fact is noted by changing an associated
 134  * "sticky bit" from CLEAR (==0) to SET (==1).
 135  *
 136  * NOTE: the bit positions in fp_except are chosen to match those of
 137  * the 80*87 control word mask bits.  Although the 87 chips actually
 138  * ENABLE exceptions with a mask value of 0 (not 1, as on the 3b), it
 139  * is felt that switching these values may create more problems than
 140  * it solves.
 141  */
 142 
 143 /* an fp_except can have the following (not exclusive) values: */
 144 #define FP_X_INV        0x01    /* invalid operation exception */
 145 #define FP_X_DNML       0x02    /* denormalization exception */
 146 #define FP_X_DZ         0x04    /* divide-by-zero exception */
 147 #define FP_X_OFL        0x08    /* overflow exception */
 148 #define FP_X_UFL        0x10    /* underflow exception */
 149 #define FP_X_IMP        0x20    /* imprecise (loss of precision) */
 150 
 151 #endif
 152 
 153 #if defined(__sparc)
 154 
 155 /*
 156  * There are five floating-point exceptions, which can be individually
 157  * ENABLED (== 1) or DISABLED (== 0).  When an exception occurs
 158  * (ENABLED or not), the fact is noted by changing an associated
 159  * "sticky bit" from CLEAR (==0) to SET (==1).
 160  *
 161  * NOTE: the bit positions in an fp_except are chosen to match that in
 162  * the Trap Enable Mask of the FSR (Floating Point State Register).
 163  */
 164 
 165 /* an fp_except can have the following (not exclusive) values: */
 166 #define FP_X_INV        0x10    /* invalid operation exception */
 167 #define FP_X_OFL        0x08    /* overflow exception */
 168 #define FP_X_UFL        0x04    /* underflow exception */
 169 #define FP_X_DZ         0x02    /* divide-by-zero exception */
 170 #define FP_X_IMP        0x01    /* imprecise (loss of precision) */
 171 
 172 #endif
 173 
 174 extern fp_except fpgetmask(void);               /* current exception mask */
 175 extern fp_except fpsetmask(fp_except);          /* set mask, return previous */
 176 extern fp_except fpgetsticky(void);             /* return logged exceptions */
 177 extern fp_except fpsetsticky(fp_except);        /* change logged exceptions */
 178 
 179 /*
 180  * UTILITY MACROS ********************************************
 181  */
 182 
 183 extern int isnanf(float);
 184 extern int isnand(double);
 185 
 186 #if defined(__i386) || defined(__amd64)
 187 
 188 /*
 189  * EXCEPTION HANDLING ****************************************
 190  *
 191  * When a signal handler catches an FPE, it will have a freshly initialized
 192  * coprocessor.  This allows signal handling routines to make use of
 193  * floating point arithmetic, if need be.  The previous state of the 87
 194  * chip is available, however.  There are two ways to get at this information,
 195  * depending on how the signal handler was set up.
 196  *
 197  * If the handler was set via signal() or sigset(), the old, SVR3, method
 198  * should be used: the signal handler assumes that it has a single parameter,
 199  * which is of type struct _fpstackframe, defined below.  By investigating
 200  * this parameter, the cause of the FPE may be determined.  By modifying it,
 201  * the state of the coprocessor can be changed upon return to the main task.
 202  * THIS METHOD IS OBSOLETE, AND MAY NOT BE SUPPORTED IN FUTURE RELEASES.
 203  *
 204  * If the handler was set via sigaction(), the new, SVR4, method should be
 205  * used: the third argument to the handler will be a pointer to a ucontext
 206  * structure (see sys/ucontext.h).  The uc_mcontext.fpregs member of the
 207  * ucontext structure holds the saved floating-point registers.  This can be
 208  * examined and/or modified.  By modifying it, the state of the coprocessor
 209  * can be changed upon return to the main task.
 210  */
 211 
 212 struct _fpreg { /* structure of a temp real fp register */
 213         unsigned short significand[4];  /* 64 bit mantissa value */
 214         unsigned short exponent;        /* 15 bit exponent and sign bit */
 215 };
 216 
 217 #if defined(__i386)
 218 
 219 /*
 220  * AMD64 users should use sigaction() as described above.
 221  */
 222 
 223 struct _fpstackframe {          /* signal handler's argument */
 224         long signo;             /* signal number arg */
 225         long regs[19];          /* all registers */
 226         struct _fpstate *fpsp;  /* address of saved 387 state */
 227         char *wsp;              /* address of saved Weitek state */
 228 };
 229 
 230 #endif
 231 
 232 #if defined(__i386) || defined(__amd64)
 233 
 234 #if defined(__amd64)
 235 #define _fpstate _fpstate32
 236 #endif
 237 
 238 struct _fpstate {               /* saved state info from an exception */
 239         unsigned int    cw,     /* control word */
 240                         sw,     /* status word after fnclex-not useful */
 241                         tag,    /* tag word */
 242                         ipoff,  /* %eip register */
 243                         cssel,  /* code segment selector */
 244                         dataoff, /* data operand address */
 245                         datasel; /* data operand selector */
 246         struct _fpreg _st[8];   /* saved register stack */
 247         unsigned int status;    /* status word saved at exception */
 248         unsigned int mxcsr;
 249         unsigned int xstatus;   /* status word saved at exception */
 250         unsigned int __pad[2];
 251         unsigned int xmm[8][4];
 252 };
 253 
 254 #if defined(__amd64)
 255 #undef  _fpstate
 256 #endif
 257 
 258 #endif  /* __i386 || __amd64 */
 259 
 260 /*
 261  * The structure of the 80*87 status and control words, and the mxcsr
 262  * register are given by the following structures.
 263  */
 264 struct _cw87 {
 265         unsigned
 266                 mask:   6,      /* exception masks */
 267                 res1:   2,      /* not used */
 268                 prec:   2,      /* precision control field */
 269                 rnd:    2,      /* rounding control field */
 270                 inf:    1,      /* infinity control (not on 387) */
 271                 res2:   3;      /* not used */
 272 };
 273 
 274 struct _sw87 {
 275         unsigned
 276                 excp:   6,      /* exception sticky bits */
 277                 res1:   1,      /* not used */
 278                 errs:   1,      /* error summary-set if unmasked excp */
 279                 c012:   3,      /* condition code bits 0..2 */
 280                 stkt:   3,      /* stack top pointer */
 281                 c3:     1,      /* condition code bit 3 */
 282                 busy:   1;      /* coprocessor busy */
 283 };
 284 
 285 struct _mxcsr {
 286         unsigned
 287                 excp:   6,      /* exception sticky bits */
 288                 daz:    1,      /* denormals are zeroes */
 289                 mask:   6,      /* exception masks */
 290                 rnd:    2,      /* rounding control */
 291                 fzero:  1;      /* flush to zero */
 292 };
 293 
 294 #endif
 295 
 296 #ifdef  __cplusplus
 297 }
 298 #endif
 299 
 300 #endif  /* _IEEEFP_H */