linux/include/math-emu/op-common.h
<<
>>
Prefs
   1/* Software floating-point emulation. Common operations.
   2   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
   3   This file is part of the GNU C Library.
   4   Contributed by Richard Henderson (rth@cygnus.com),
   5                  Jakub Jelinek (jj@ultra.linux.cz),
   6                  David S. Miller (davem@redhat.com) and
   7                  Peter Maydell (pmaydell@chiark.greenend.org.uk).
   8
   9   The GNU C Library is free software; you can redistribute it and/or
  10   modify it under the terms of the GNU Library General Public License as
  11   published by the Free Software Foundation; either version 2 of the
  12   License, or (at your option) any later version.
  13
  14   The GNU C Library is distributed in the hope that it will be useful,
  15   but WITHOUT ANY WARRANTY; without even the implied warranty of
  16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17   Library General Public License for more details.
  18
  19   You should have received a copy of the GNU Library General Public
  20   License along with the GNU C Library; see the file COPYING.LIB.  If
  21   not, write to the Free Software Foundation, Inc.,
  22   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  23
  24#ifndef __MATH_EMU_OP_COMMON_H__
  25#define __MATH_EMU_OP_COMMON_H__
  26
  27#define _FP_DECL(wc, X)                 \
  28  _FP_I_TYPE X##_c=0, X##_s=0, X##_e=0; \
  29  _FP_FRAC_DECL_##wc(X)
  30
  31/*
  32 * Finish truly unpacking a native fp value by classifying the kind
  33 * of fp value and normalizing both the exponent and the fraction.
  34 */
  35
  36#define _FP_UNPACK_CANONICAL(fs, wc, X)                                 \
  37do {                                                                    \
  38  switch (X##_e)                                                        \
  39  {                                                                     \
  40  default:                                                              \
  41    _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_IMPLBIT_##fs;                      \
  42    _FP_FRAC_SLL_##wc(X, _FP_WORKBITS);                                 \
  43    X##_e -= _FP_EXPBIAS_##fs;                                          \
  44    X##_c = FP_CLS_NORMAL;                                              \
  45    break;                                                              \
  46                                                                        \
  47  case 0:                                                               \
  48    if (_FP_FRAC_ZEROP_##wc(X))                                         \
  49      X##_c = FP_CLS_ZERO;                                              \
  50    else                                                                \
  51      {                                                                 \
  52        /* a denormalized number */                                     \
  53        _FP_I_TYPE _shift;                                              \
  54        _FP_FRAC_CLZ_##wc(_shift, X);                                   \
  55        _shift -= _FP_FRACXBITS_##fs;                                   \
  56        _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS));                    \
  57        X##_e -= _FP_EXPBIAS_##fs - 1 + _shift;                         \
  58        X##_c = FP_CLS_NORMAL;                                          \
  59        FP_SET_EXCEPTION(FP_EX_DENORM);                                 \
  60        if (FP_DENORM_ZERO)                                             \
  61          {                                                             \
  62            FP_SET_EXCEPTION(FP_EX_INEXACT);                            \
  63            X##_c = FP_CLS_ZERO;                                        \
  64          }                                                             \
  65      }                                                                 \
  66    break;                                                              \
  67                                                                        \
  68  case _FP_EXPMAX_##fs:                                                 \
  69    if (_FP_FRAC_ZEROP_##wc(X))                                         \
  70      X##_c = FP_CLS_INF;                                               \
  71    else                                                                \
  72      {                                                                 \
  73        X##_c = FP_CLS_NAN;                                             \
  74        /* Check for signaling NaN */                                   \
  75        if (!(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))            \
  76          FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_SNAN);         \
  77      }                                                                 \
  78    break;                                                              \
  79  }                                                                     \
  80} while (0)
  81
  82/*
  83 * Before packing the bits back into the native fp result, take care
  84 * of such mundane things as rounding and overflow.  Also, for some
  85 * kinds of fp values, the original parts may not have been fully
  86 * extracted -- but that is ok, we can regenerate them now.
  87 */
  88
  89#define _FP_PACK_CANONICAL(fs, wc, X)                           \
  90do {                                                            \
  91  switch (X##_c)                                                \
  92  {                                                             \
  93  case FP_CLS_NORMAL:                                           \
  94    X##_e += _FP_EXPBIAS_##fs;                                  \
  95    if (X##_e > 0)                                              \
  96      {                                                         \
  97        _FP_ROUND(wc, X);                                       \
  98        if (_FP_FRAC_OVERP_##wc(fs, X))                         \
  99          {                                                     \
 100            _FP_FRAC_CLEAR_OVERP_##wc(fs, X);                   \
 101            X##_e++;                                            \
 102          }                                                     \
 103        _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);                     \
 104        if (X##_e >= _FP_EXPMAX_##fs)                           \
 105          {                                                     \
 106            /* overflow */                                      \
 107            switch (FP_ROUNDMODE)                               \
 108              {                                                 \
 109              case FP_RND_NEAREST:                              \
 110                X##_c = FP_CLS_INF;                             \
 111                break;                                          \
 112              case FP_RND_PINF:                                 \
 113                if (!X##_s) X##_c = FP_CLS_INF;                 \
 114                break;                                          \
 115              case FP_RND_MINF:                                 \
 116                if (X##_s) X##_c = FP_CLS_INF;                  \
 117                break;                                          \
 118              }                                                 \
 119            if (X##_c == FP_CLS_INF)                            \
 120              {                                                 \
 121                /* Overflow to infinity */                      \
 122                X##_e = _FP_EXPMAX_##fs;                        \
 123                _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);        \
 124              }                                                 \
 125            else                                                \
 126              {                                                 \
 127                /* Overflow to maximum normal */                \
 128                X##_e = _FP_EXPMAX_##fs - 1;                    \
 129                _FP_FRAC_SET_##wc(X, _FP_MAXFRAC_##wc);         \
 130              }                                                 \
 131            FP_SET_EXCEPTION(FP_EX_OVERFLOW);                   \
 132            FP_SET_EXCEPTION(FP_EX_INEXACT);                    \
 133          }                                                     \
 134      }                                                         \
 135    else                                                        \
 136      {                                                         \
 137        /* we've got a denormalized number */                   \
 138        X##_e = -X##_e + 1;                                     \
 139        if (X##_e <= _FP_WFRACBITS_##fs)                        \
 140          {                                                     \
 141            _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs);    \
 142            if (_FP_FRAC_HIGH_##fs(X)                           \
 143                & (_FP_OVERFLOW_##fs >> 1))                     \
 144              {                                                 \
 145                X##_e = 1;                                      \
 146                _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);        \
 147              }                                                 \
 148            else                                                \
 149              {                                                 \
 150                _FP_ROUND(wc, X);                               \
 151                if (_FP_FRAC_HIGH_##fs(X)                       \
 152                   & (_FP_OVERFLOW_##fs >> 1))                  \
 153                  {                                             \
 154                    X##_e = 1;                                  \
 155                    _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);    \
 156                    FP_SET_EXCEPTION(FP_EX_INEXACT);            \
 157                  }                                             \
 158                else                                            \
 159                  {                                             \
 160                    X##_e = 0;                                  \
 161                    _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);         \
 162                  }                                             \
 163              }                                                 \
 164            if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) ||          \
 165                (FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW))     \
 166                FP_SET_EXCEPTION(FP_EX_UNDERFLOW);              \
 167          }                                                     \
 168        else                                                    \
 169          {                                                     \
 170            /* underflow to zero */                             \
 171            X##_e = 0;                                          \
 172            if (!_FP_FRAC_ZEROP_##wc(X))                        \
 173              {                                                 \
 174                _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);         \
 175                _FP_ROUND(wc, X);                               \
 176                _FP_FRAC_LOW_##wc(X) >>= (_FP_WORKBITS);        \
 177              }                                                 \
 178            FP_SET_EXCEPTION(FP_EX_UNDERFLOW);                  \
 179          }                                                     \
 180      }                                                         \
 181    break;                                                      \
 182                                                                \
 183  case FP_CLS_ZERO:                                             \
 184    X##_e = 0;                                                  \
 185    _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                    \
 186    break;                                                      \
 187                                                                \
 188  case FP_CLS_INF:                                              \
 189    X##_e = _FP_EXPMAX_##fs;                                    \
 190    _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                    \
 191    break;                                                      \
 192                                                                \
 193  case FP_CLS_NAN:                                              \
 194    X##_e = _FP_EXPMAX_##fs;                                    \
 195    if (!_FP_KEEPNANFRACP)                                      \
 196      {                                                         \
 197        _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs);                 \
 198        X##_s = _FP_NANSIGN_##fs;                               \
 199      }                                                         \
 200    else                                                        \
 201      _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs;            \
 202    break;                                                      \
 203  }                                                             \
 204} while (0)
 205
 206/* This one accepts raw argument and not cooked,  returns
 207 * 1 if X is a signaling NaN.
 208 */
 209#define _FP_ISSIGNAN(fs, wc, X)                                 \
 210({                                                              \
 211  int __ret = 0;                                                \
 212  if (X##_e == _FP_EXPMAX_##fs)                                 \
 213    {                                                           \
 214      if (!_FP_FRAC_ZEROP_##wc(X)                               \
 215          && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))   \
 216        __ret = 1;                                              \
 217    }                                                           \
 218  __ret;                                                        \
 219})
 220
 221
 222
 223
 224
 225/*
 226 * Main addition routine.  The input values should be cooked.
 227 */
 228
 229#define _FP_ADD_INTERNAL(fs, wc, R, X, Y, OP)                                \
 230do {                                                                         \
 231  switch (_FP_CLS_COMBINE(X##_c, Y##_c))                                     \
 232  {                                                                          \
 233  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):                         \
 234    {                                                                        \
 235      /* shift the smaller number so that its exponent matches the larger */ \
 236      _FP_I_TYPE diff = X##_e - Y##_e;                                       \
 237                                                                             \
 238      if (diff < 0)                                                          \
 239        {                                                                    \
 240          diff = -diff;                                                      \
 241          if (diff <= _FP_WFRACBITS_##fs)                                    \
 242            _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs);                  \
 243          else if (!_FP_FRAC_ZEROP_##wc(X))                                  \
 244            _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);                          \
 245          R##_e = Y##_e;                                                     \
 246        }                                                                    \
 247      else                                                                   \
 248        {                                                                    \
 249          if (diff > 0)                                                      \
 250            {                                                                \
 251              if (diff <= _FP_WFRACBITS_##fs)                                \
 252                _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs);              \
 253              else if (!_FP_FRAC_ZEROP_##wc(Y))                              \
 254                _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc);                      \
 255            }                                                                \
 256          R##_e = X##_e;                                                     \
 257        }                                                                    \
 258                                                                             \
 259      R##_c = FP_CLS_NORMAL;                                                 \
 260                                                                             \
 261      if (X##_s == Y##_s)                                                    \
 262        {                                                                    \
 263          R##_s = X##_s;                                                     \
 264          _FP_FRAC_ADD_##wc(R, X, Y);                                        \
 265          if (_FP_FRAC_OVERP_##wc(fs, R))                                    \
 266            {                                                                \
 267              _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);                   \
 268              R##_e++;                                                       \
 269            }                                                                \
 270        }                                                                    \
 271      else                                                                   \
 272        {                                                                    \
 273          R##_s = X##_s;                                                     \
 274          _FP_FRAC_SUB_##wc(R, X, Y);                                        \
 275          if (_FP_FRAC_ZEROP_##wc(R))                                        \
 276            {                                                                \
 277              /* return an exact zero */                                     \
 278              if (FP_ROUNDMODE == FP_RND_MINF)                               \
 279                R##_s |= Y##_s;                                              \
 280              else                                                           \
 281                R##_s &= Y##_s;                                              \
 282              R##_c = FP_CLS_ZERO;                                           \
 283            }                                                                \
 284          else                                                               \
 285            {                                                                \
 286              if (_FP_FRAC_NEGP_##wc(R))                                     \
 287                {                                                            \
 288                  _FP_FRAC_SUB_##wc(R, Y, X);                                \
 289                  R##_s = Y##_s;                                             \
 290                }                                                            \
 291                                                                             \
 292              /* renormalize after subtraction */                            \
 293              _FP_FRAC_CLZ_##wc(diff, R);                                    \
 294              diff -= _FP_WFRACXBITS_##fs;                                   \
 295              if (diff)                                                      \
 296                {                                                            \
 297                  R##_e -= diff;                                             \
 298                  _FP_FRAC_SLL_##wc(R, diff);                                \
 299                }                                                            \
 300            }                                                                \
 301        }                                                                    \
 302      break;                                                                 \
 303    }                                                                        \
 304                                                                             \
 305  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):                               \
 306    _FP_CHOOSENAN(fs, wc, R, X, Y, OP);                                      \
 307    break;                                                                   \
 308                                                                             \
 309  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):                           \
 310    R##_e = X##_e;                                                           \
 311          /* Fall through */                                                 \
 312  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):                            \
 313  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):                               \
 314  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):                              \
 315    _FP_FRAC_COPY_##wc(R, X);                                                \
 316    R##_s = X##_s;                                                           \
 317    R##_c = X##_c;                                                           \
 318    break;                                                                   \
 319                                                                             \
 320  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):                           \
 321    R##_e = Y##_e;                                                           \
 322          /* Fall through */                                                 \
 323  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):                            \
 324  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):                               \
 325  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):                              \
 326    _FP_FRAC_COPY_##wc(R, Y);                                                \
 327    R##_s = Y##_s;                                                           \
 328    R##_c = Y##_c;                                                           \
 329    break;                                                                   \
 330                                                                             \
 331  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):                               \
 332    if (X##_s != Y##_s)                                                      \
 333      {                                                                      \
 334        /* +INF + -INF => NAN */                                             \
 335        _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                              \
 336        R##_s = _FP_NANSIGN_##fs;                                            \
 337        R##_c = FP_CLS_NAN;                                                  \
 338        FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_ISI);                 \
 339        break;                                                               \
 340      }                                                                      \
 341    /* FALLTHRU */                                                           \
 342                                                                             \
 343  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):                            \
 344  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):                              \
 345    R##_s = X##_s;                                                           \
 346    R##_c = FP_CLS_INF;                                                      \
 347    break;                                                                   \
 348                                                                             \
 349  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):                            \
 350  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):                              \
 351    R##_s = Y##_s;                                                           \
 352    R##_c = FP_CLS_INF;                                                      \
 353    break;                                                                   \
 354                                                                             \
 355  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):                             \
 356    /* make sure the sign is correct */                                      \
 357    if (FP_ROUNDMODE == FP_RND_MINF)                                         \
 358      R##_s = X##_s | Y##_s;                                                 \
 359    else                                                                     \
 360      R##_s = X##_s & Y##_s;                                                 \
 361    R##_c = FP_CLS_ZERO;                                                     \
 362    break;                                                                   \
 363                                                                             \
 364  default:                                                                   \
 365    abort();                                                                 \
 366  }                                                                          \
 367} while (0)
 368
 369#define _FP_ADD(fs, wc, R, X, Y) _FP_ADD_INTERNAL(fs, wc, R, X, Y, '+')
 370#define _FP_SUB(fs, wc, R, X, Y)                                             \
 371  do {                                                                       \
 372    if (Y##_c != FP_CLS_NAN) Y##_s ^= 1;                                     \
 373    _FP_ADD_INTERNAL(fs, wc, R, X, Y, '-');                                  \
 374  } while (0)
 375
 376
 377/*
 378 * Main negation routine.  FIXME -- when we care about setting exception
 379 * bits reliably, this will not do.  We should examine all of the fp classes.
 380 */
 381
 382#define _FP_NEG(fs, wc, R, X)           \
 383  do {                                  \
 384    _FP_FRAC_COPY_##wc(R, X);           \
 385    R##_c = X##_c;                      \
 386    R##_e = X##_e;                      \
 387    R##_s = 1 ^ X##_s;                  \
 388  } while (0)
 389
 390
 391/*
 392 * Main multiplication routine.  The input values should be cooked.
 393 */
 394
 395#define _FP_MUL(fs, wc, R, X, Y)                        \
 396do {                                                    \
 397  R##_s = X##_s ^ Y##_s;                                \
 398  switch (_FP_CLS_COMBINE(X##_c, Y##_c))                \
 399  {                                                     \
 400  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):    \
 401    R##_c = FP_CLS_NORMAL;                              \
 402    R##_e = X##_e + Y##_e + 1;                          \
 403                                                        \
 404    _FP_MUL_MEAT_##fs(R,X,Y);                           \
 405                                                        \
 406    if (_FP_FRAC_OVERP_##wc(fs, R))                     \
 407      _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);      \
 408    else                                                \
 409      R##_e--;                                          \
 410    break;                                              \
 411                                                        \
 412  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):          \
 413    _FP_CHOOSENAN(fs, wc, R, X, Y, '*');                \
 414    break;                                              \
 415                                                        \
 416  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):       \
 417  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):          \
 418  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):         \
 419    R##_s = X##_s;                                      \
 420        /* Fall through */                              \
 421                                                        \
 422  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):          \
 423  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):       \
 424  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):      \
 425  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):        \
 426    _FP_FRAC_COPY_##wc(R, X);                           \
 427    R##_c = X##_c;                                      \
 428    break;                                              \
 429                                                        \
 430  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):       \
 431  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):          \
 432  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):         \
 433    R##_s = Y##_s;                                      \
 434        /* Fall through */                              \
 435                                                        \
 436  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):       \
 437  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):      \
 438    _FP_FRAC_COPY_##wc(R, Y);                           \
 439    R##_c = Y##_c;                                      \
 440    break;                                              \
 441                                                        \
 442  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):         \
 443  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):         \
 444    R##_s = _FP_NANSIGN_##fs;                           \
 445    R##_c = FP_CLS_NAN;                                 \
 446    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);             \
 447    FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_IMZ);\
 448    break;                                              \
 449                                                        \
 450  default:                                              \
 451    abort();                                            \
 452  }                                                     \
 453} while (0)
 454
 455
 456/*
 457 * Main division routine.  The input values should be cooked.
 458 */
 459
 460#define _FP_DIV(fs, wc, R, X, Y)                        \
 461do {                                                    \
 462  R##_s = X##_s ^ Y##_s;                                \
 463  switch (_FP_CLS_COMBINE(X##_c, Y##_c))                \
 464  {                                                     \
 465  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):    \
 466    R##_c = FP_CLS_NORMAL;                              \
 467    R##_e = X##_e - Y##_e;                              \
 468                                                        \
 469    _FP_DIV_MEAT_##fs(R,X,Y);                           \
 470    break;                                              \
 471                                                        \
 472  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):          \
 473    _FP_CHOOSENAN(fs, wc, R, X, Y, '/');                \
 474    break;                                              \
 475                                                        \
 476  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):       \
 477  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):          \
 478  case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):         \
 479    R##_s = X##_s;                                      \
 480    _FP_FRAC_COPY_##wc(R, X);                           \
 481    R##_c = X##_c;                                      \
 482    break;                                              \
 483                                                        \
 484  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):       \
 485  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):          \
 486  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):         \
 487    R##_s = Y##_s;                                      \
 488    _FP_FRAC_COPY_##wc(R, Y);                           \
 489    R##_c = Y##_c;                                      \
 490    break;                                              \
 491                                                        \
 492  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):       \
 493  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):         \
 494  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):      \
 495    R##_c = FP_CLS_ZERO;                                \
 496    break;                                              \
 497                                                        \
 498  case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):      \
 499    FP_SET_EXCEPTION(FP_EX_DIVZERO);                    \
 500          /* Fall through */                            \
 501  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):         \
 502  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):       \
 503    R##_c = FP_CLS_INF;                                 \
 504    break;                                              \
 505                                                        \
 506  case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):          \
 507    R##_s = _FP_NANSIGN_##fs;                           \
 508    R##_c = FP_CLS_NAN;                                 \
 509    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);             \
 510    FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_IDI);\
 511    break;                                              \
 512                                                        \
 513  case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):        \
 514    R##_s = _FP_NANSIGN_##fs;                           \
 515    R##_c = FP_CLS_NAN;                                 \
 516    _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);             \
 517    FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_ZDZ);\
 518    break;                                              \
 519                                                        \
 520  default:                                              \
 521    abort();                                            \
 522  }                                                     \
 523} while (0)
 524
 525
 526/*
 527 * Main differential comparison routine.  The inputs should be raw not
 528 * cooked.  The return is -1,0,1 for normal values, 2 otherwise.
 529 */
 530
 531#define _FP_CMP(fs, wc, ret, X, Y, un)                                  \
 532  do {                                                                  \
 533    /* NANs are unordered */                                            \
 534    if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))           \
 535        || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))       \
 536      {                                                                 \
 537        ret = un;                                                       \
 538      }                                                                 \
 539    else                                                                \
 540      {                                                                 \
 541        int __is_zero_x;                                                \
 542        int __is_zero_y;                                                \
 543                                                                        \
 544        __is_zero_x = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0;       \
 545        __is_zero_y = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0;       \
 546                                                                        \
 547        if (__is_zero_x && __is_zero_y)                                 \
 548                ret = 0;                                                \
 549        else if (__is_zero_x)                                           \
 550                ret = Y##_s ? 1 : -1;                                   \
 551        else if (__is_zero_y)                                           \
 552                ret = X##_s ? -1 : 1;                                   \
 553        else if (X##_s != Y##_s)                                        \
 554          ret = X##_s ? -1 : 1;                                         \
 555        else if (X##_e > Y##_e)                                         \
 556          ret = X##_s ? -1 : 1;                                         \
 557        else if (X##_e < Y##_e)                                         \
 558          ret = X##_s ? 1 : -1;                                         \
 559        else if (_FP_FRAC_GT_##wc(X, Y))                                \
 560          ret = X##_s ? -1 : 1;                                         \
 561        else if (_FP_FRAC_GT_##wc(Y, X))                                \
 562          ret = X##_s ? 1 : -1;                                         \
 563        else                                                            \
 564          ret = 0;                                                      \
 565      }                                                                 \
 566  } while (0)
 567
 568
 569/* Simplification for strict equality.  */
 570
 571#define _FP_CMP_EQ(fs, wc, ret, X, Y)                                     \
 572  do {                                                                    \
 573    /* NANs are unordered */                                              \
 574    if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))             \
 575        || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))         \
 576      {                                                                   \
 577        ret = 1;                                                          \
 578      }                                                                   \
 579    else                                                                  \
 580      {                                                                   \
 581        ret = !(X##_e == Y##_e                                            \
 582                && _FP_FRAC_EQ_##wc(X, Y)                                 \
 583                && (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \
 584      }                                                                   \
 585  } while (0)
 586
 587/*
 588 * Main square root routine.  The input value should be cooked.
 589 */
 590
 591#define _FP_SQRT(fs, wc, R, X)                                          \
 592do {                                                                    \
 593    _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S);                       \
 594    _FP_W_TYPE q;                                                       \
 595    switch (X##_c)                                                      \
 596    {                                                                   \
 597    case FP_CLS_NAN:                                                    \
 598        _FP_FRAC_COPY_##wc(R, X);                                       \
 599        R##_s = X##_s;                                                  \
 600        R##_c = FP_CLS_NAN;                                             \
 601        break;                                                          \
 602    case FP_CLS_INF:                                                    \
 603        if (X##_s)                                                      \
 604          {                                                             \
 605            R##_s = _FP_NANSIGN_##fs;                                   \
 606            R##_c = FP_CLS_NAN; /* NAN */                               \
 607            _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                     \
 608            FP_SET_EXCEPTION(FP_EX_INVALID);                            \
 609          }                                                             \
 610        else                                                            \
 611          {                                                             \
 612            R##_s = 0;                                                  \
 613            R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */                 \
 614          }                                                             \
 615        break;                                                          \
 616    case FP_CLS_ZERO:                                                   \
 617        R##_s = X##_s;                                                  \
 618        R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */                      \
 619        break;                                                          \
 620    case FP_CLS_NORMAL:                                                 \
 621        R##_s = 0;                                                      \
 622        if (X##_s)                                                      \
 623          {                                                             \
 624            R##_c = FP_CLS_NAN; /* sNAN */                              \
 625            R##_s = _FP_NANSIGN_##fs;                                   \
 626            _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                     \
 627            FP_SET_EXCEPTION(FP_EX_INVALID);                            \
 628            break;                                                      \
 629          }                                                             \
 630        R##_c = FP_CLS_NORMAL;                                          \
 631        if (X##_e & 1)                                                  \
 632          _FP_FRAC_SLL_##wc(X, 1);                                      \
 633        R##_e = X##_e >> 1;                                             \
 634        _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc);                        \
 635        _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc);                        \
 636        q = _FP_OVERFLOW_##fs >> 1;                                     \
 637        _FP_SQRT_MEAT_##wc(R, S, T, X, q);                              \
 638    }                                                                   \
 639  } while (0)
 640
 641/*
 642 * Convert from FP to integer
 643 */
 644
 645/* RSIGNED can have following values:
 646 * 0:  the number is required to be 0..(2^rsize)-1, if not, NV is set plus
 647 *     the result is either 0 or (2^rsize)-1 depending on the sign in such case.
 648 * 1:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is
 649 *     set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
 650 *     on the sign in such case.
 651 * 2:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is
 652 *     set plus the result is truncated to fit into destination.
 653 * -1: the number is required to be -(2^(rsize-1))..(2^rsize)-1, if not, NV is
 654 *     set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
 655 *     on the sign in such case.
 656 */
 657#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned)                                \
 658  do {                                                                          \
 659    switch (X##_c)                                                              \
 660      {                                                                         \
 661      case FP_CLS_NORMAL:                                                       \
 662        if (X##_e < 0)                                                          \
 663          {                                                                     \
 664            FP_SET_EXCEPTION(FP_EX_INEXACT);                                    \
 665          case FP_CLS_ZERO:                                                     \
 666            r = 0;                                                              \
 667          }                                                                     \
 668        else if (X##_e >= rsize - (rsigned > 0 || X##_s)                        \
 669                 || (!rsigned && X##_s))                                        \
 670          {     /* overflow */                                                  \
 671          case FP_CLS_NAN:                                                      \
 672          case FP_CLS_INF:                                                      \
 673            if (rsigned == 2)                                                   \
 674              {                                                                 \
 675                if (X##_c != FP_CLS_NORMAL                                      \
 676                    || X##_e >= rsize - 1 + _FP_WFRACBITS_##fs)                 \
 677                  r = 0;                                                        \
 678                else                                                            \
 679                  {                                                             \
 680                    _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));     \
 681                    _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                        \
 682                  }                                                             \
 683              }                                                                 \
 684            else if (rsigned)                                                   \
 685              {                                                                 \
 686                r = 1;                                                          \
 687                r <<= rsize - 1;                                                \
 688                r -= 1 - X##_s;                                                 \
 689              }                                                                 \
 690            else                                                                \
 691              {                                                                 \
 692                r = 0;                                                          \
 693                if (!X##_s)                                                     \
 694                  r = ~r;                                                       \
 695              }                                                                 \
 696            FP_SET_EXCEPTION(FP_EX_INVALID);                                    \
 697          }                                                                     \
 698        else                                                                    \
 699          {                                                                     \
 700            if (_FP_W_TYPE_SIZE*wc < rsize)                                     \
 701              {                                                                 \
 702                _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                            \
 703                r <<= X##_e - _FP_WFRACBITS_##fs;                               \
 704              }                                                                 \
 705            else                                                                \
 706              {                                                                 \
 707                if (X##_e >= _FP_WFRACBITS_##fs)                                \
 708                  _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));       \
 709                else if (X##_e < _FP_WFRACBITS_##fs - 1)                        \
 710                  {                                                             \
 711                    _FP_FRAC_SRS_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 2),      \
 712                                      _FP_WFRACBITS_##fs);                      \
 713                    if (_FP_FRAC_LOW_##wc(X) & 1)                               \
 714                      FP_SET_EXCEPTION(FP_EX_INEXACT);                          \
 715                    _FP_FRAC_SRL_##wc(X, 1);                                    \
 716                  }                                                             \
 717                _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                            \
 718              }                                                                 \
 719            if (rsigned && X##_s)                                               \
 720              r = -r;                                                           \
 721          }                                                                     \
 722        break;                                                                  \
 723      }                                                                         \
 724  } while (0)
 725
 726#define _FP_TO_INT_ROUND(fs, wc, r, X, rsize, rsigned)                          \
 727  do {                                                                          \
 728    r = 0;                                                                      \
 729    switch (X##_c)                                                              \
 730      {                                                                         \
 731      case FP_CLS_NORMAL:                                                       \
 732        if (X##_e >= _FP_FRACBITS_##fs - 1)                                     \
 733          {                                                                     \
 734            if (X##_e < rsize - 1 + _FP_WFRACBITS_##fs)                         \
 735              {                                                                 \
 736                if (X##_e >= _FP_WFRACBITS_##fs - 1)                            \
 737                  {                                                             \
 738                    _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                        \
 739                    r <<= X##_e - _FP_WFRACBITS_##fs + 1;                       \
 740                  }                                                             \
 741                else                                                            \
 742                  {                                                             \
 743                    _FP_FRAC_SRL_##wc(X, _FP_WORKBITS - X##_e                   \
 744                                      + _FP_FRACBITS_##fs - 1);                 \
 745                    _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                        \
 746                  }                                                             \
 747              }                                                                 \
 748          }                                                                     \
 749        else                                                                    \
 750          {                                                                     \
 751            int _lz0, _lz1;                                                     \
 752            if (X##_e <= -_FP_WORKBITS - 1)                                     \
 753              _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);                           \
 754            else                                                                \
 755              _FP_FRAC_SRS_##wc(X, _FP_FRACBITS_##fs - 1 - X##_e,               \
 756                                _FP_WFRACBITS_##fs);                            \
 757            _FP_FRAC_CLZ_##wc(_lz0, X);                                         \
 758            _FP_ROUND(wc, X);                                                   \
 759            _FP_FRAC_CLZ_##wc(_lz1, X);                                         \
 760            if (_lz1 < _lz0)                                                    \
 761              X##_e++; /* For overflow detection.  */                           \
 762            _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);                                 \
 763            _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                                \
 764          }                                                                     \
 765        if (rsigned && X##_s)                                                   \
 766          r = -r;                                                               \
 767        if (X##_e >= rsize - (rsigned > 0 || X##_s)                             \
 768            || (!rsigned && X##_s))                                             \
 769          {     /* overflow */                                                  \
 770          case FP_CLS_NAN:                                                      \
 771          case FP_CLS_INF:                                                      \
 772            if (!rsigned)                                                       \
 773              {                                                                 \
 774                r = 0;                                                          \
 775                if (!X##_s)                                                     \
 776                  r = ~r;                                                       \
 777              }                                                                 \
 778            else if (rsigned != 2)                                              \
 779              {                                                                 \
 780                r = 1;                                                          \
 781                r <<= rsize - 1;                                                \
 782                r -= 1 - X##_s;                                                 \
 783              }                                                                 \
 784            FP_SET_EXCEPTION(FP_EX_INVALID);                                    \
 785          }                                                                     \
 786        break;                                                                  \
 787      case FP_CLS_ZERO:                                                         \
 788        break;                                                                  \
 789      }                                                                         \
 790  } while (0)
 791
 792#define _FP_FROM_INT(fs, wc, X, r, rsize, rtype)                        \
 793  do {                                                                  \
 794    if (r)                                                              \
 795      {                                                                 \
 796        unsigned rtype ur_;                                             \
 797        X##_c = FP_CLS_NORMAL;                                          \
 798                                                                        \
 799        if ((X##_s = (r < 0)))                                          \
 800          ur_ = (unsigned rtype) -r;                                    \
 801        else                                                            \
 802          ur_ = (unsigned rtype) r;                                     \
 803        (void) (((rsize) <= _FP_W_TYPE_SIZE)                            \
 804                ? ({ __FP_CLZ(X##_e, ur_); })                           \
 805                : ({                                                    \
 806                     __FP_CLZ_2(X##_e, (_FP_W_TYPE)(ur_ >> _FP_W_TYPE_SIZE),  \
 807                                                            (_FP_W_TYPE)ur_); \
 808                  }));                                                  \
 809        if (rsize < _FP_W_TYPE_SIZE)                                    \
 810                X##_e -= (_FP_W_TYPE_SIZE - rsize);                     \
 811        X##_e = rsize - X##_e - 1;                                      \
 812                                                                        \
 813        if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs <= X##_e)   \
 814          __FP_FRAC_SRS_1(ur_, (X##_e - _FP_WFRACBITS_##fs + 1), rsize);\
 815        _FP_FRAC_DISASSEMBLE_##wc(X, ur_, rsize);                       \
 816        if ((_FP_WFRACBITS_##fs - X##_e - 1) > 0)                       \
 817          _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));       \
 818      }                                                                 \
 819    else                                                                \
 820      {                                                                 \
 821        X##_c = FP_CLS_ZERO, X##_s = 0;                                 \
 822      }                                                                 \
 823  } while (0)
 824
 825
 826#define FP_CONV(dfs,sfs,dwc,swc,D,S)                    \
 827  do {                                                  \
 828    _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S);        \
 829    D##_e = S##_e;                                      \
 830    D##_c = S##_c;                                      \
 831    D##_s = S##_s;                                      \
 832  } while (0)
 833
 834/*
 835 * Helper primitives.
 836 */
 837
 838/* Count leading zeros in a word.  */
 839
 840#ifndef __FP_CLZ
 841#if _FP_W_TYPE_SIZE < 64
 842/* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */
 843#define __FP_CLZ(r, x)                          \
 844  do {                                          \
 845    _FP_W_TYPE _t = (x);                        \
 846    r = _FP_W_TYPE_SIZE - 1;                    \
 847    if (_t > 0xffff) r -= 16;                   \
 848    if (_t > 0xffff) _t >>= 16;                 \
 849    if (_t > 0xff) r -= 8;                      \
 850    if (_t > 0xff) _t >>= 8;                    \
 851    if (_t & 0xf0) r -= 4;                      \
 852    if (_t & 0xf0) _t >>= 4;                    \
 853    if (_t & 0xc) r -= 2;                       \
 854    if (_t & 0xc) _t >>= 2;                     \
 855    if (_t & 0x2) r -= 1;                       \
 856  } while (0)
 857#else /* not _FP_W_TYPE_SIZE < 64 */
 858#define __FP_CLZ(r, x)                          \
 859  do {                                          \
 860    _FP_W_TYPE _t = (x);                        \
 861    r = _FP_W_TYPE_SIZE - 1;                    \
 862    if (_t > 0xffffffff) r -= 32;               \
 863    if (_t > 0xffffffff) _t >>= 32;             \
 864    if (_t > 0xffff) r -= 16;                   \
 865    if (_t > 0xffff) _t >>= 16;                 \
 866    if (_t > 0xff) r -= 8;                      \
 867    if (_t > 0xff) _t >>= 8;                    \
 868    if (_t & 0xf0) r -= 4;                      \
 869    if (_t & 0xf0) _t >>= 4;                    \
 870    if (_t & 0xc) r -= 2;                       \
 871    if (_t & 0xc) _t >>= 2;                     \
 872    if (_t & 0x2) r -= 1;                       \
 873  } while (0)
 874#endif /* not _FP_W_TYPE_SIZE < 64 */
 875#endif /* ndef __FP_CLZ */
 876
 877#define _FP_DIV_HELP_imm(q, r, n, d)            \
 878  do {                                          \
 879    q = n / d, r = n % d;                       \
 880  } while (0)
 881
 882#endif /* __MATH_EMU_OP_COMMON_H__ */
 883