root/lib/libm/src/math_private.h
/*      $OpenBSD: math_private.h,v 1.18 2016/09/12 19:47:02 guenther Exp $      */
/*
 * ====================================================
 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
 *
 * Developed at SunPro, a Sun Microsystems, Inc. business.
 * Permission to use, copy, modify, and distribute this
 * software is freely granted, provided that this notice 
 * is preserved.
 * ====================================================
 */

/*
 * from: @(#)fdlibm.h 5.1 93/09/24
 */

#ifndef _MATH_PRIVATE_H_
#define _MATH_PRIVATE_H_

#include <sys/types.h>

/* The original fdlibm code used statements like:
        n0 = ((*(int*)&one)>>29)^1;             * index of high word *
        ix0 = *(n0+(int*)&x);                   * high word of x *
        ix1 = *((1-n0)+(int*)&x);               * low word of x *
   to dig two 32 bit words out of the 64 bit IEEE floating point
   value.  That is non-ANSI, and, moreover, the gcc instruction
   scheduler gets it wrong.  We instead use the following macros.
   Unlike the original code, we determine the endianness at compile
   time, not at run time; I don't see much benefit to selecting
   endianness at run time.  */

/* A union which permits us to convert between a long double and
   four 32 bit ints.  */

#if BYTE_ORDER == BIG_ENDIAN

typedef union
{
  long double value;
  struct {
    u_int32_t mswhi;
    u_int32_t mswlo;
    u_int32_t lswhi;
    u_int32_t lswlo;
  } parts32;
  struct {
    u_int64_t msw;
    u_int64_t lsw;
  } parts64;
} ieee_quad_shape_type;

#endif

#if BYTE_ORDER == LITTLE_ENDIAN

typedef union
{
  long double value;
  struct {
    u_int32_t lswlo;
    u_int32_t lswhi;
    u_int32_t mswlo;
    u_int32_t mswhi;
  } parts32;
  struct {
    u_int64_t lsw;
    u_int64_t msw;
  } parts64;
} ieee_quad_shape_type;

#endif

/* Get two 64 bit ints from a long double.  */

#define GET_LDOUBLE_WORDS64(ix0,ix1,d)                          \
do {                                                            \
  ieee_quad_shape_type qw_u;                                    \
  qw_u.value = (d);                                             \
  (ix0) = qw_u.parts64.msw;                                     \
  (ix1) = qw_u.parts64.lsw;                                     \
} while (0)

/* Set a long double from two 64 bit ints.  */

#define SET_LDOUBLE_WORDS64(d,ix0,ix1)                          \
do {                                                            \
  ieee_quad_shape_type qw_u;                                    \
  qw_u.parts64.msw = (ix0);                                     \
  qw_u.parts64.lsw = (ix1);                                     \
  (d) = qw_u.value;                                             \
} while (0)

/* Get the more significant 64 bits of a long double mantissa.  */

#define GET_LDOUBLE_MSW64(v,d)                                  \
do {                                                            \
  ieee_quad_shape_type sh_u;                                    \
  sh_u.value = (d);                                             \
  (v) = sh_u.parts64.msw;                                       \
} while (0)

/* Set the more significant 64 bits of a long double mantissa from an int.  */

#define SET_LDOUBLE_MSW64(d,v)                                  \
do {                                                            \
  ieee_quad_shape_type sh_u;                                    \
  sh_u.value = (d);                                             \
  sh_u.parts64.msw = (v);                                       \
  (d) = sh_u.value;                                             \
} while (0)

/* Get the least significant 64 bits of a long double mantissa.  */

#define GET_LDOUBLE_LSW64(v,d)                                  \
do {                                                            \
  ieee_quad_shape_type sh_u;                                    \
  sh_u.value = (d);                                             \
  (v) = sh_u.parts64.lsw;                                       \
} while (0)

/* A union which permits us to convert between a long double and
   three 32 bit ints.  */

#if BYTE_ORDER == BIG_ENDIAN

typedef union
{
  long double value;
  struct {
#ifdef __LP64__
    int padh:32;
#endif
    int exp:16;
    int padl:16;
    u_int32_t msw;
    u_int32_t lsw;
  } parts;
} ieee_extended_shape_type;

#endif

#if BYTE_ORDER == LITTLE_ENDIAN

typedef union
{
  long double value;
  struct {
    u_int32_t lsw;
    u_int32_t msw;
    int exp:16;
    int padl:16;
#ifdef __LP64__
    int padh:32;
#endif
  } parts;
} ieee_extended_shape_type;

#endif

/* Get three 32 bit ints from a double.  */

#define GET_LDOUBLE_WORDS(se,ix0,ix1,d)                         \
do {                                                            \
  ieee_extended_shape_type ew_u;                                \
  ew_u.value = (d);                                             \
  (se) = ew_u.parts.exp;                                        \
  (ix0) = ew_u.parts.msw;                                       \
  (ix1) = ew_u.parts.lsw;                                       \
} while (0)

/* Set a double from two 32 bit ints.  */

#define SET_LDOUBLE_WORDS(d,se,ix0,ix1)                         \
do {                                                            \
  ieee_extended_shape_type iw_u;                                \
  iw_u.parts.exp = (se);                                        \
  iw_u.parts.msw = (ix0);                                       \
  iw_u.parts.lsw = (ix1);                                       \
  (d) = iw_u.value;                                             \
} while (0)

/* Get the more significant 32 bits of a long double mantissa.  */

#define GET_LDOUBLE_MSW(v,d)                                    \
do {                                                            \
  ieee_extended_shape_type sh_u;                                \
  sh_u.value = (d);                                             \
  (v) = sh_u.parts.msw;                                         \
} while (0)

/* Set the more significant 32 bits of a long double mantissa from an int.  */

#define SET_LDOUBLE_MSW(d,v)                                    \
do {                                                            \
  ieee_extended_shape_type sh_u;                                \
  sh_u.value = (d);                                             \
  sh_u.parts.msw = (v);                                         \
  (d) = sh_u.value;                                             \
} while (0)

/* Get int from the exponent of a long double.  */

#define GET_LDOUBLE_EXP(se,d)                                   \
do {                                                            \
  ieee_extended_shape_type ge_u;                                \
  ge_u.value = (d);                                             \
  (se) = ge_u.parts.exp;                                        \
} while (0)

/* Set exponent of a long double from an int.  */

#define SET_LDOUBLE_EXP(d,se)                                   \
do {                                                            \
  ieee_extended_shape_type se_u;                                \
  se_u.value = (d);                                             \
  se_u.parts.exp = (se);                                        \
  (d) = se_u.value;                                             \
} while (0)

/* A union which permits us to convert between a double and two 32 bit
   ints.  */

/*
 * The arm port is little endian except for the FP word order which is
 * big endian.
 */

#if (BYTE_ORDER == BIG_ENDIAN) || (defined(__arm__) && !defined(__VFP_FP__))

typedef union
{
  double value;
  struct
  {
    u_int32_t msw;
    u_int32_t lsw;
  } parts;
} ieee_double_shape_type;

#endif

#if (BYTE_ORDER == LITTLE_ENDIAN) && !(defined(__arm__) && !defined(__VFP_FP__))

typedef union
{
  double value;
  struct
  {
    u_int32_t lsw;
    u_int32_t msw;
  } parts;
} ieee_double_shape_type;

#endif

/* Get two 32 bit ints from a double.  */

#define EXTRACT_WORDS(ix0,ix1,d)                                \
do {                                                            \
  ieee_double_shape_type ew_u;                                  \
  ew_u.value = (d);                                             \
  (ix0) = ew_u.parts.msw;                                       \
  (ix1) = ew_u.parts.lsw;                                       \
} while (0)

/* Get the more significant 32 bit int from a double.  */

#define GET_HIGH_WORD(i,d)                                      \
do {                                                            \
  ieee_double_shape_type gh_u;                                  \
  gh_u.value = (d);                                             \
  (i) = gh_u.parts.msw;                                         \
} while (0)

/* Get the less significant 32 bit int from a double.  */

#define GET_LOW_WORD(i,d)                                       \
do {                                                            \
  ieee_double_shape_type gl_u;                                  \
  gl_u.value = (d);                                             \
  (i) = gl_u.parts.lsw;                                         \
} while (0)

/* Set a double from two 32 bit ints.  */

#define INSERT_WORDS(d,ix0,ix1)                                 \
do {                                                            \
  ieee_double_shape_type iw_u;                                  \
  iw_u.parts.msw = (ix0);                                       \
  iw_u.parts.lsw = (ix1);                                       \
  (d) = iw_u.value;                                             \
} while (0)

/* Set the more significant 32 bits of a double from an int.  */

#define SET_HIGH_WORD(d,v)                                      \
do {                                                            \
  ieee_double_shape_type sh_u;                                  \
  sh_u.value = (d);                                             \
  sh_u.parts.msw = (v);                                         \
  (d) = sh_u.value;                                             \
} while (0)

/* Set the less significant 32 bits of a double from an int.  */

#define SET_LOW_WORD(d,v)                                       \
do {                                                            \
  ieee_double_shape_type sl_u;                                  \
  sl_u.value = (d);                                             \
  sl_u.parts.lsw = (v);                                         \
  (d) = sl_u.value;                                             \
} while (0)

/* A union which permits us to convert between a float and a 32 bit
   int.  */

typedef union
{
  float value;
  u_int32_t word;
} ieee_float_shape_type;

/* Get a 32 bit int from a float.  */

#define GET_FLOAT_WORD(i,d)                                     \
do {                                                            \
  ieee_float_shape_type gf_u;                                   \
  gf_u.value = (d);                                             \
  (i) = gf_u.word;                                              \
} while (0)

/* Set a float from a 32 bit int.  */

#define SET_FLOAT_WORD(d,i)                                     \
do {                                                            \
  ieee_float_shape_type sf_u;                                   \
  sf_u.word = (i);                                              \
  (d) = sf_u.value;                                             \
} while (0)

#ifdef FLT_EVAL_METHOD
/*
 * Attempt to get strict C99 semantics for assignment with non-C99 compilers.
 */
#if FLT_EVAL_METHOD == 0 || __GNUC__ == 0
#define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval))
#else /* FLT_EVAL_METHOD == 0 || __GNUC__ == 0 */
#define STRICT_ASSIGN(type, lval, rval) do {    \
        volatile type __lval;                   \
                                                \
        if (sizeof(type) >= sizeof(long double))        \
                (lval) = (rval);                \
        else {                                  \
                __lval = (rval);                \
                (lval) = __lval;                \
        }                                       \
} while (0)
#endif /* FLT_EVAL_METHOD == 0 || __GNUC__ == 0 */
#endif /* FLT_EVAL_METHOD */

__BEGIN_HIDDEN_DECLS
/* fdlibm kernel function */
extern int    __ieee754_rem_pio2(double,double*);
extern double __kernel_sin(double,double,int);
extern double __kernel_cos(double,double);
extern double __kernel_tan(double,double,int);
extern int    __kernel_rem_pio2(double*,double*,int,int,int);

/* float versions of fdlibm kernel functions */
extern int   __ieee754_rem_pio2f(float,float*);
extern float __kernel_sinf(float,float,int);
extern float __kernel_cosf(float,float);
extern float __kernel_tanf(float,float,int);
extern int   __kernel_rem_pio2f(float*,float*,int,int,int,const int*);

/* long double precision kernel functions */
long double __kernel_sinl(long double, long double, int);
long double __kernel_cosl(long double, long double);
long double __kernel_tanl(long double, long double, int);

/*
 * Common routine to process the arguments to nan(), nanf(), and nanl().
 */
void _scan_nan(uint32_t *__words, int __num_words, const char *__s);
__END_HIDDEN_DECLS

/*
 * TRUNC() is a macro that sets the trailing 27 bits in the mantissa
 * of an IEEE double variable to zero.  It must be expression-like
 * for syntactic reasons, and we implement this expression using
 * an inline function instead of a pure macro to avoid depending
 * on the gcc feature of statement-expressions.
 */
#define TRUNC(d)        (_b_trunc(&(d)))

static __inline void
_b_trunc(volatile double *_dp)
{
        uint32_t _lw;

        GET_LOW_WORD(_lw, *_dp);
        SET_LOW_WORD(*_dp, _lw & 0xf8000000);
}

struct Double {
        double  a;
        double  b;
};

/*
 * Functions internal to the math package, yet not static.
 */
__BEGIN_HIDDEN_DECLS
double __exp__D(double, double);
struct Double __log__D(double);
long double __p1evll(long double, void *, int);
long double __polevll(long double, void *, int);
__END_HIDDEN_DECLS

#endif /* _MATH_PRIVATE_H_ */