162306a36Sopenharmony_ci/* Software floating-point emulation. Common operations. 262306a36Sopenharmony_ci Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. 362306a36Sopenharmony_ci This file is part of the GNU C Library. 462306a36Sopenharmony_ci Contributed by Richard Henderson (rth@cygnus.com), 562306a36Sopenharmony_ci Jakub Jelinek (jj@ultra.linux.cz), 662306a36Sopenharmony_ci David S. Miller (davem@redhat.com) and 762306a36Sopenharmony_ci Peter Maydell (pmaydell@chiark.greenend.org.uk). 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci The GNU C Library is free software; you can redistribute it and/or 1062306a36Sopenharmony_ci modify it under the terms of the GNU Library General Public License as 1162306a36Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 1262306a36Sopenharmony_ci License, or (at your option) any later version. 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci The GNU C Library is distributed in the hope that it will be useful, 1562306a36Sopenharmony_ci but WITHOUT ANY WARRANTY; without even the implied warranty of 1662306a36Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1762306a36Sopenharmony_ci Library General Public License for more details. 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci You should have received a copy of the GNU Library General Public 2062306a36Sopenharmony_ci License along with the GNU C Library; see the file COPYING.LIB. If 2162306a36Sopenharmony_ci not, write to the Free Software Foundation, Inc., 2262306a36Sopenharmony_ci 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#ifndef __MATH_EMU_OP_COMMON_H__ 2562306a36Sopenharmony_ci#define __MATH_EMU_OP_COMMON_H__ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define _FP_DECL(wc, X) \ 2862306a36Sopenharmony_ci _FP_I_TYPE X##_c=0, X##_s=0, X##_e=0; \ 2962306a36Sopenharmony_ci _FP_FRAC_DECL_##wc(X) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci * Finish truly unpacking a native fp value by classifying the kind 3362306a36Sopenharmony_ci * of fp value and normalizing both the exponent and the fraction. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define _FP_UNPACK_CANONICAL(fs, wc, X) \ 3762306a36Sopenharmony_cido { \ 3862306a36Sopenharmony_ci switch (X##_e) \ 3962306a36Sopenharmony_ci { \ 4062306a36Sopenharmony_ci default: \ 4162306a36Sopenharmony_ci _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_IMPLBIT_##fs; \ 4262306a36Sopenharmony_ci _FP_FRAC_SLL_##wc(X, _FP_WORKBITS); \ 4362306a36Sopenharmony_ci X##_e -= _FP_EXPBIAS_##fs; \ 4462306a36Sopenharmony_ci X##_c = FP_CLS_NORMAL; \ 4562306a36Sopenharmony_ci break; \ 4662306a36Sopenharmony_ci \ 4762306a36Sopenharmony_ci case 0: \ 4862306a36Sopenharmony_ci if (_FP_FRAC_ZEROP_##wc(X)) \ 4962306a36Sopenharmony_ci X##_c = FP_CLS_ZERO; \ 5062306a36Sopenharmony_ci else \ 5162306a36Sopenharmony_ci { \ 5262306a36Sopenharmony_ci /* a denormalized number */ \ 5362306a36Sopenharmony_ci _FP_I_TYPE _shift; \ 5462306a36Sopenharmony_ci _FP_FRAC_CLZ_##wc(_shift, X); \ 5562306a36Sopenharmony_ci _shift -= _FP_FRACXBITS_##fs; \ 5662306a36Sopenharmony_ci _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS)); \ 5762306a36Sopenharmony_ci X##_e -= _FP_EXPBIAS_##fs - 1 + _shift; \ 5862306a36Sopenharmony_ci X##_c = FP_CLS_NORMAL; \ 5962306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_DENORM); \ 6062306a36Sopenharmony_ci if (FP_DENORM_ZERO) \ 6162306a36Sopenharmony_ci { \ 6262306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INEXACT); \ 6362306a36Sopenharmony_ci X##_c = FP_CLS_ZERO; \ 6462306a36Sopenharmony_ci } \ 6562306a36Sopenharmony_ci } \ 6662306a36Sopenharmony_ci break; \ 6762306a36Sopenharmony_ci \ 6862306a36Sopenharmony_ci case _FP_EXPMAX_##fs: \ 6962306a36Sopenharmony_ci if (_FP_FRAC_ZEROP_##wc(X)) \ 7062306a36Sopenharmony_ci X##_c = FP_CLS_INF; \ 7162306a36Sopenharmony_ci else \ 7262306a36Sopenharmony_ci { \ 7362306a36Sopenharmony_ci X##_c = FP_CLS_NAN; \ 7462306a36Sopenharmony_ci /* Check for signaling NaN */ \ 7562306a36Sopenharmony_ci if (!(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \ 7662306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_SNAN); \ 7762306a36Sopenharmony_ci } \ 7862306a36Sopenharmony_ci break; \ 7962306a36Sopenharmony_ci } \ 8062306a36Sopenharmony_ci} while (0) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* 8362306a36Sopenharmony_ci * Before packing the bits back into the native fp result, take care 8462306a36Sopenharmony_ci * of such mundane things as rounding and overflow. Also, for some 8562306a36Sopenharmony_ci * kinds of fp values, the original parts may not have been fully 8662306a36Sopenharmony_ci * extracted -- but that is ok, we can regenerate them now. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#define _FP_PACK_CANONICAL(fs, wc, X) \ 9062306a36Sopenharmony_cido { \ 9162306a36Sopenharmony_ci switch (X##_c) \ 9262306a36Sopenharmony_ci { \ 9362306a36Sopenharmony_ci case FP_CLS_NORMAL: \ 9462306a36Sopenharmony_ci X##_e += _FP_EXPBIAS_##fs; \ 9562306a36Sopenharmony_ci if (X##_e > 0) \ 9662306a36Sopenharmony_ci { \ 9762306a36Sopenharmony_ci _FP_ROUND(wc, X); \ 9862306a36Sopenharmony_ci if (_FP_FRAC_OVERP_##wc(fs, X)) \ 9962306a36Sopenharmony_ci { \ 10062306a36Sopenharmony_ci _FP_FRAC_CLEAR_OVERP_##wc(fs, X); \ 10162306a36Sopenharmony_ci X##_e++; \ 10262306a36Sopenharmony_ci } \ 10362306a36Sopenharmony_ci _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ 10462306a36Sopenharmony_ci if (X##_e >= _FP_EXPMAX_##fs) \ 10562306a36Sopenharmony_ci { \ 10662306a36Sopenharmony_ci /* overflow */ \ 10762306a36Sopenharmony_ci switch (FP_ROUNDMODE) \ 10862306a36Sopenharmony_ci { \ 10962306a36Sopenharmony_ci case FP_RND_NEAREST: \ 11062306a36Sopenharmony_ci X##_c = FP_CLS_INF; \ 11162306a36Sopenharmony_ci break; \ 11262306a36Sopenharmony_ci case FP_RND_PINF: \ 11362306a36Sopenharmony_ci if (!X##_s) X##_c = FP_CLS_INF; \ 11462306a36Sopenharmony_ci break; \ 11562306a36Sopenharmony_ci case FP_RND_MINF: \ 11662306a36Sopenharmony_ci if (X##_s) X##_c = FP_CLS_INF; \ 11762306a36Sopenharmony_ci break; \ 11862306a36Sopenharmony_ci } \ 11962306a36Sopenharmony_ci if (X##_c == FP_CLS_INF) \ 12062306a36Sopenharmony_ci { \ 12162306a36Sopenharmony_ci /* Overflow to infinity */ \ 12262306a36Sopenharmony_ci X##_e = _FP_EXPMAX_##fs; \ 12362306a36Sopenharmony_ci _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ 12462306a36Sopenharmony_ci } \ 12562306a36Sopenharmony_ci else \ 12662306a36Sopenharmony_ci { \ 12762306a36Sopenharmony_ci /* Overflow to maximum normal */ \ 12862306a36Sopenharmony_ci X##_e = _FP_EXPMAX_##fs - 1; \ 12962306a36Sopenharmony_ci _FP_FRAC_SET_##wc(X, _FP_MAXFRAC_##wc); \ 13062306a36Sopenharmony_ci } \ 13162306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_OVERFLOW); \ 13262306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INEXACT); \ 13362306a36Sopenharmony_ci } \ 13462306a36Sopenharmony_ci } \ 13562306a36Sopenharmony_ci else \ 13662306a36Sopenharmony_ci { \ 13762306a36Sopenharmony_ci /* we've got a denormalized number */ \ 13862306a36Sopenharmony_ci X##_e = -X##_e + 1; \ 13962306a36Sopenharmony_ci if (X##_e <= _FP_WFRACBITS_##fs) \ 14062306a36Sopenharmony_ci { \ 14162306a36Sopenharmony_ci _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \ 14262306a36Sopenharmony_ci if (_FP_FRAC_HIGH_##fs(X) \ 14362306a36Sopenharmony_ci & (_FP_OVERFLOW_##fs >> 1)) \ 14462306a36Sopenharmony_ci { \ 14562306a36Sopenharmony_ci X##_e = 1; \ 14662306a36Sopenharmony_ci _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ 14762306a36Sopenharmony_ci } \ 14862306a36Sopenharmony_ci else \ 14962306a36Sopenharmony_ci { \ 15062306a36Sopenharmony_ci _FP_ROUND(wc, X); \ 15162306a36Sopenharmony_ci if (_FP_FRAC_HIGH_##fs(X) \ 15262306a36Sopenharmony_ci & (_FP_OVERFLOW_##fs >> 1)) \ 15362306a36Sopenharmony_ci { \ 15462306a36Sopenharmony_ci X##_e = 1; \ 15562306a36Sopenharmony_ci _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ 15662306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INEXACT); \ 15762306a36Sopenharmony_ci } \ 15862306a36Sopenharmony_ci else \ 15962306a36Sopenharmony_ci { \ 16062306a36Sopenharmony_ci X##_e = 0; \ 16162306a36Sopenharmony_ci _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ 16262306a36Sopenharmony_ci } \ 16362306a36Sopenharmony_ci } \ 16462306a36Sopenharmony_ci if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT) || \ 16562306a36Sopenharmony_ci (FP_TRAPPING_EXCEPTIONS & FP_EX_UNDERFLOW)) \ 16662306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_UNDERFLOW); \ 16762306a36Sopenharmony_ci } \ 16862306a36Sopenharmony_ci else \ 16962306a36Sopenharmony_ci { \ 17062306a36Sopenharmony_ci /* underflow to zero */ \ 17162306a36Sopenharmony_ci X##_e = 0; \ 17262306a36Sopenharmony_ci if (!_FP_FRAC_ZEROP_##wc(X)) \ 17362306a36Sopenharmony_ci { \ 17462306a36Sopenharmony_ci _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \ 17562306a36Sopenharmony_ci _FP_ROUND(wc, X); \ 17662306a36Sopenharmony_ci _FP_FRAC_LOW_##wc(X) >>= (_FP_WORKBITS); \ 17762306a36Sopenharmony_ci } \ 17862306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_UNDERFLOW); \ 17962306a36Sopenharmony_ci } \ 18062306a36Sopenharmony_ci } \ 18162306a36Sopenharmony_ci break; \ 18262306a36Sopenharmony_ci \ 18362306a36Sopenharmony_ci case FP_CLS_ZERO: \ 18462306a36Sopenharmony_ci X##_e = 0; \ 18562306a36Sopenharmony_ci _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ 18662306a36Sopenharmony_ci break; \ 18762306a36Sopenharmony_ci \ 18862306a36Sopenharmony_ci case FP_CLS_INF: \ 18962306a36Sopenharmony_ci X##_e = _FP_EXPMAX_##fs; \ 19062306a36Sopenharmony_ci _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ 19162306a36Sopenharmony_ci break; \ 19262306a36Sopenharmony_ci \ 19362306a36Sopenharmony_ci case FP_CLS_NAN: \ 19462306a36Sopenharmony_ci X##_e = _FP_EXPMAX_##fs; \ 19562306a36Sopenharmony_ci if (!_FP_KEEPNANFRACP) \ 19662306a36Sopenharmony_ci { \ 19762306a36Sopenharmony_ci _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs); \ 19862306a36Sopenharmony_ci X##_s = _FP_NANSIGN_##fs; \ 19962306a36Sopenharmony_ci } \ 20062306a36Sopenharmony_ci else \ 20162306a36Sopenharmony_ci _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs; \ 20262306a36Sopenharmony_ci break; \ 20362306a36Sopenharmony_ci } \ 20462306a36Sopenharmony_ci} while (0) 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* This one accepts raw argument and not cooked, returns 20762306a36Sopenharmony_ci * 1 if X is a signaling NaN. 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_ci#define _FP_ISSIGNAN(fs, wc, X) \ 21062306a36Sopenharmony_ci({ \ 21162306a36Sopenharmony_ci int __ret = 0; \ 21262306a36Sopenharmony_ci if (X##_e == _FP_EXPMAX_##fs) \ 21362306a36Sopenharmony_ci { \ 21462306a36Sopenharmony_ci if (!_FP_FRAC_ZEROP_##wc(X) \ 21562306a36Sopenharmony_ci && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \ 21662306a36Sopenharmony_ci __ret = 1; \ 21762306a36Sopenharmony_ci } \ 21862306a36Sopenharmony_ci __ret; \ 21962306a36Sopenharmony_ci}) 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/* 22662306a36Sopenharmony_ci * Main addition routine. The input values should be cooked. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci#define _FP_ADD_INTERNAL(fs, wc, R, X, Y, OP) \ 23062306a36Sopenharmony_cido { \ 23162306a36Sopenharmony_ci switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ 23262306a36Sopenharmony_ci { \ 23362306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ 23462306a36Sopenharmony_ci { \ 23562306a36Sopenharmony_ci /* shift the smaller number so that its exponent matches the larger */ \ 23662306a36Sopenharmony_ci _FP_I_TYPE diff = X##_e - Y##_e; \ 23762306a36Sopenharmony_ci \ 23862306a36Sopenharmony_ci if (diff < 0) \ 23962306a36Sopenharmony_ci { \ 24062306a36Sopenharmony_ci diff = -diff; \ 24162306a36Sopenharmony_ci if (diff <= _FP_WFRACBITS_##fs) \ 24262306a36Sopenharmony_ci _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs); \ 24362306a36Sopenharmony_ci else if (!_FP_FRAC_ZEROP_##wc(X)) \ 24462306a36Sopenharmony_ci _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \ 24562306a36Sopenharmony_ci R##_e = Y##_e; \ 24662306a36Sopenharmony_ci } \ 24762306a36Sopenharmony_ci else \ 24862306a36Sopenharmony_ci { \ 24962306a36Sopenharmony_ci if (diff > 0) \ 25062306a36Sopenharmony_ci { \ 25162306a36Sopenharmony_ci if (diff <= _FP_WFRACBITS_##fs) \ 25262306a36Sopenharmony_ci _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs); \ 25362306a36Sopenharmony_ci else if (!_FP_FRAC_ZEROP_##wc(Y)) \ 25462306a36Sopenharmony_ci _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc); \ 25562306a36Sopenharmony_ci } \ 25662306a36Sopenharmony_ci R##_e = X##_e; \ 25762306a36Sopenharmony_ci } \ 25862306a36Sopenharmony_ci \ 25962306a36Sopenharmony_ci R##_c = FP_CLS_NORMAL; \ 26062306a36Sopenharmony_ci \ 26162306a36Sopenharmony_ci if (X##_s == Y##_s) \ 26262306a36Sopenharmony_ci { \ 26362306a36Sopenharmony_ci R##_s = X##_s; \ 26462306a36Sopenharmony_ci _FP_FRAC_ADD_##wc(R, X, Y); \ 26562306a36Sopenharmony_ci if (_FP_FRAC_OVERP_##wc(fs, R)) \ 26662306a36Sopenharmony_ci { \ 26762306a36Sopenharmony_ci _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \ 26862306a36Sopenharmony_ci R##_e++; \ 26962306a36Sopenharmony_ci } \ 27062306a36Sopenharmony_ci } \ 27162306a36Sopenharmony_ci else \ 27262306a36Sopenharmony_ci { \ 27362306a36Sopenharmony_ci R##_s = X##_s; \ 27462306a36Sopenharmony_ci _FP_FRAC_SUB_##wc(R, X, Y); \ 27562306a36Sopenharmony_ci if (_FP_FRAC_ZEROP_##wc(R)) \ 27662306a36Sopenharmony_ci { \ 27762306a36Sopenharmony_ci /* return an exact zero */ \ 27862306a36Sopenharmony_ci if (FP_ROUNDMODE == FP_RND_MINF) \ 27962306a36Sopenharmony_ci R##_s |= Y##_s; \ 28062306a36Sopenharmony_ci else \ 28162306a36Sopenharmony_ci R##_s &= Y##_s; \ 28262306a36Sopenharmony_ci R##_c = FP_CLS_ZERO; \ 28362306a36Sopenharmony_ci } \ 28462306a36Sopenharmony_ci else \ 28562306a36Sopenharmony_ci { \ 28662306a36Sopenharmony_ci if (_FP_FRAC_NEGP_##wc(R)) \ 28762306a36Sopenharmony_ci { \ 28862306a36Sopenharmony_ci _FP_FRAC_SUB_##wc(R, Y, X); \ 28962306a36Sopenharmony_ci R##_s = Y##_s; \ 29062306a36Sopenharmony_ci } \ 29162306a36Sopenharmony_ci \ 29262306a36Sopenharmony_ci /* renormalize after subtraction */ \ 29362306a36Sopenharmony_ci _FP_FRAC_CLZ_##wc(diff, R); \ 29462306a36Sopenharmony_ci diff -= _FP_WFRACXBITS_##fs; \ 29562306a36Sopenharmony_ci if (diff) \ 29662306a36Sopenharmony_ci { \ 29762306a36Sopenharmony_ci R##_e -= diff; \ 29862306a36Sopenharmony_ci _FP_FRAC_SLL_##wc(R, diff); \ 29962306a36Sopenharmony_ci } \ 30062306a36Sopenharmony_ci } \ 30162306a36Sopenharmony_ci } \ 30262306a36Sopenharmony_ci break; \ 30362306a36Sopenharmony_ci } \ 30462306a36Sopenharmony_ci \ 30562306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ 30662306a36Sopenharmony_ci _FP_CHOOSENAN(fs, wc, R, X, Y, OP); \ 30762306a36Sopenharmony_ci break; \ 30862306a36Sopenharmony_ci \ 30962306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ 31062306a36Sopenharmony_ci R##_e = X##_e; \ 31162306a36Sopenharmony_ci fallthrough; \ 31262306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ 31362306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ 31462306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ 31562306a36Sopenharmony_ci _FP_FRAC_COPY_##wc(R, X); \ 31662306a36Sopenharmony_ci R##_s = X##_s; \ 31762306a36Sopenharmony_ci R##_c = X##_c; \ 31862306a36Sopenharmony_ci break; \ 31962306a36Sopenharmony_ci \ 32062306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ 32162306a36Sopenharmony_ci R##_e = Y##_e; \ 32262306a36Sopenharmony_ci fallthrough; \ 32362306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ 32462306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ 32562306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ 32662306a36Sopenharmony_ci _FP_FRAC_COPY_##wc(R, Y); \ 32762306a36Sopenharmony_ci R##_s = Y##_s; \ 32862306a36Sopenharmony_ci R##_c = Y##_c; \ 32962306a36Sopenharmony_ci break; \ 33062306a36Sopenharmony_ci \ 33162306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ 33262306a36Sopenharmony_ci if (X##_s != Y##_s) \ 33362306a36Sopenharmony_ci { \ 33462306a36Sopenharmony_ci /* +INF + -INF => NAN */ \ 33562306a36Sopenharmony_ci _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ 33662306a36Sopenharmony_ci R##_s = _FP_NANSIGN_##fs; \ 33762306a36Sopenharmony_ci R##_c = FP_CLS_NAN; \ 33862306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_ISI); \ 33962306a36Sopenharmony_ci break; \ 34062306a36Sopenharmony_ci } \ 34162306a36Sopenharmony_ci fallthrough; \ 34262306a36Sopenharmony_ci \ 34362306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ 34462306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ 34562306a36Sopenharmony_ci R##_s = X##_s; \ 34662306a36Sopenharmony_ci R##_c = FP_CLS_INF; \ 34762306a36Sopenharmony_ci break; \ 34862306a36Sopenharmony_ci \ 34962306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ 35062306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ 35162306a36Sopenharmony_ci R##_s = Y##_s; \ 35262306a36Sopenharmony_ci R##_c = FP_CLS_INF; \ 35362306a36Sopenharmony_ci break; \ 35462306a36Sopenharmony_ci \ 35562306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ 35662306a36Sopenharmony_ci /* make sure the sign is correct */ \ 35762306a36Sopenharmony_ci if (FP_ROUNDMODE == FP_RND_MINF) \ 35862306a36Sopenharmony_ci R##_s = X##_s | Y##_s; \ 35962306a36Sopenharmony_ci else \ 36062306a36Sopenharmony_ci R##_s = X##_s & Y##_s; \ 36162306a36Sopenharmony_ci R##_c = FP_CLS_ZERO; \ 36262306a36Sopenharmony_ci break; \ 36362306a36Sopenharmony_ci \ 36462306a36Sopenharmony_ci default: \ 36562306a36Sopenharmony_ci abort(); \ 36662306a36Sopenharmony_ci } \ 36762306a36Sopenharmony_ci} while (0) 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci#define _FP_ADD(fs, wc, R, X, Y) _FP_ADD_INTERNAL(fs, wc, R, X, Y, '+') 37062306a36Sopenharmony_ci#define _FP_SUB(fs, wc, R, X, Y) \ 37162306a36Sopenharmony_ci do { \ 37262306a36Sopenharmony_ci if (Y##_c != FP_CLS_NAN) Y##_s ^= 1; \ 37362306a36Sopenharmony_ci _FP_ADD_INTERNAL(fs, wc, R, X, Y, '-'); \ 37462306a36Sopenharmony_ci } while (0) 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci/* 37862306a36Sopenharmony_ci * Main negation routine. FIXME -- when we care about setting exception 37962306a36Sopenharmony_ci * bits reliably, this will not do. We should examine all of the fp classes. 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci#define _FP_NEG(fs, wc, R, X) \ 38362306a36Sopenharmony_ci do { \ 38462306a36Sopenharmony_ci _FP_FRAC_COPY_##wc(R, X); \ 38562306a36Sopenharmony_ci R##_c = X##_c; \ 38662306a36Sopenharmony_ci R##_e = X##_e; \ 38762306a36Sopenharmony_ci R##_s = 1 ^ X##_s; \ 38862306a36Sopenharmony_ci } while (0) 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci/* 39262306a36Sopenharmony_ci * Main multiplication routine. The input values should be cooked. 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci#define _FP_MUL(fs, wc, R, X, Y) \ 39662306a36Sopenharmony_cido { \ 39762306a36Sopenharmony_ci R##_s = X##_s ^ Y##_s; \ 39862306a36Sopenharmony_ci switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ 39962306a36Sopenharmony_ci { \ 40062306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ 40162306a36Sopenharmony_ci R##_c = FP_CLS_NORMAL; \ 40262306a36Sopenharmony_ci R##_e = X##_e + Y##_e + 1; \ 40362306a36Sopenharmony_ci \ 40462306a36Sopenharmony_ci _FP_MUL_MEAT_##fs(R,X,Y); \ 40562306a36Sopenharmony_ci \ 40662306a36Sopenharmony_ci if (_FP_FRAC_OVERP_##wc(fs, R)) \ 40762306a36Sopenharmony_ci _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \ 40862306a36Sopenharmony_ci else \ 40962306a36Sopenharmony_ci R##_e--; \ 41062306a36Sopenharmony_ci break; \ 41162306a36Sopenharmony_ci \ 41262306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ 41362306a36Sopenharmony_ci _FP_CHOOSENAN(fs, wc, R, X, Y, '*'); \ 41462306a36Sopenharmony_ci break; \ 41562306a36Sopenharmony_ci \ 41662306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ 41762306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ 41862306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ 41962306a36Sopenharmony_ci R##_s = X##_s; \ 42062306a36Sopenharmony_ci fallthrough; \ 42162306a36Sopenharmony_ci \ 42262306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ 42362306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ 42462306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ 42562306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ 42662306a36Sopenharmony_ci _FP_FRAC_COPY_##wc(R, X); \ 42762306a36Sopenharmony_ci R##_c = X##_c; \ 42862306a36Sopenharmony_ci break; \ 42962306a36Sopenharmony_ci \ 43062306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ 43162306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ 43262306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ 43362306a36Sopenharmony_ci R##_s = Y##_s; \ 43462306a36Sopenharmony_ci fallthrough; \ 43562306a36Sopenharmony_ci \ 43662306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ 43762306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ 43862306a36Sopenharmony_ci _FP_FRAC_COPY_##wc(R, Y); \ 43962306a36Sopenharmony_ci R##_c = Y##_c; \ 44062306a36Sopenharmony_ci break; \ 44162306a36Sopenharmony_ci \ 44262306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ 44362306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ 44462306a36Sopenharmony_ci R##_s = _FP_NANSIGN_##fs; \ 44562306a36Sopenharmony_ci R##_c = FP_CLS_NAN; \ 44662306a36Sopenharmony_ci _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ 44762306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_IMZ);\ 44862306a36Sopenharmony_ci break; \ 44962306a36Sopenharmony_ci \ 45062306a36Sopenharmony_ci default: \ 45162306a36Sopenharmony_ci abort(); \ 45262306a36Sopenharmony_ci } \ 45362306a36Sopenharmony_ci} while (0) 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci/* 45762306a36Sopenharmony_ci * Main division routine. The input values should be cooked. 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci#define _FP_DIV(fs, wc, R, X, Y) \ 46162306a36Sopenharmony_cido { \ 46262306a36Sopenharmony_ci R##_s = X##_s ^ Y##_s; \ 46362306a36Sopenharmony_ci switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ 46462306a36Sopenharmony_ci { \ 46562306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ 46662306a36Sopenharmony_ci R##_c = FP_CLS_NORMAL; \ 46762306a36Sopenharmony_ci R##_e = X##_e - Y##_e; \ 46862306a36Sopenharmony_ci \ 46962306a36Sopenharmony_ci _FP_DIV_MEAT_##fs(R,X,Y); \ 47062306a36Sopenharmony_ci break; \ 47162306a36Sopenharmony_ci \ 47262306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ 47362306a36Sopenharmony_ci _FP_CHOOSENAN(fs, wc, R, X, Y, '/'); \ 47462306a36Sopenharmony_ci break; \ 47562306a36Sopenharmony_ci \ 47662306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ 47762306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ 47862306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ 47962306a36Sopenharmony_ci R##_s = X##_s; \ 48062306a36Sopenharmony_ci _FP_FRAC_COPY_##wc(R, X); \ 48162306a36Sopenharmony_ci R##_c = X##_c; \ 48262306a36Sopenharmony_ci break; \ 48362306a36Sopenharmony_ci \ 48462306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ 48562306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ 48662306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ 48762306a36Sopenharmony_ci R##_s = Y##_s; \ 48862306a36Sopenharmony_ci _FP_FRAC_COPY_##wc(R, Y); \ 48962306a36Sopenharmony_ci R##_c = Y##_c; \ 49062306a36Sopenharmony_ci break; \ 49162306a36Sopenharmony_ci \ 49262306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ 49362306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ 49462306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ 49562306a36Sopenharmony_ci R##_c = FP_CLS_ZERO; \ 49662306a36Sopenharmony_ci break; \ 49762306a36Sopenharmony_ci \ 49862306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ 49962306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_DIVZERO); \ 50062306a36Sopenharmony_ci fallthrough; \ 50162306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ 50262306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ 50362306a36Sopenharmony_ci R##_c = FP_CLS_INF; \ 50462306a36Sopenharmony_ci break; \ 50562306a36Sopenharmony_ci \ 50662306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ 50762306a36Sopenharmony_ci R##_s = _FP_NANSIGN_##fs; \ 50862306a36Sopenharmony_ci R##_c = FP_CLS_NAN; \ 50962306a36Sopenharmony_ci _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ 51062306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_IDI);\ 51162306a36Sopenharmony_ci break; \ 51262306a36Sopenharmony_ci \ 51362306a36Sopenharmony_ci case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ 51462306a36Sopenharmony_ci R##_s = _FP_NANSIGN_##fs; \ 51562306a36Sopenharmony_ci R##_c = FP_CLS_NAN; \ 51662306a36Sopenharmony_ci _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ 51762306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_ZDZ);\ 51862306a36Sopenharmony_ci break; \ 51962306a36Sopenharmony_ci \ 52062306a36Sopenharmony_ci default: \ 52162306a36Sopenharmony_ci abort(); \ 52262306a36Sopenharmony_ci } \ 52362306a36Sopenharmony_ci} while (0) 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci/* 52762306a36Sopenharmony_ci * Main differential comparison routine. The inputs should be raw not 52862306a36Sopenharmony_ci * cooked. The return is -1,0,1 for normal values, 2 otherwise. 52962306a36Sopenharmony_ci */ 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci#define _FP_CMP(fs, wc, ret, X, Y, un) \ 53262306a36Sopenharmony_ci do { \ 53362306a36Sopenharmony_ci /* NANs are unordered */ \ 53462306a36Sopenharmony_ci if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \ 53562306a36Sopenharmony_ci || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \ 53662306a36Sopenharmony_ci { \ 53762306a36Sopenharmony_ci ret = un; \ 53862306a36Sopenharmony_ci } \ 53962306a36Sopenharmony_ci else \ 54062306a36Sopenharmony_ci { \ 54162306a36Sopenharmony_ci int __is_zero_x; \ 54262306a36Sopenharmony_ci int __is_zero_y; \ 54362306a36Sopenharmony_ci \ 54462306a36Sopenharmony_ci __is_zero_x = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0; \ 54562306a36Sopenharmony_ci __is_zero_y = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0; \ 54662306a36Sopenharmony_ci \ 54762306a36Sopenharmony_ci if (__is_zero_x && __is_zero_y) \ 54862306a36Sopenharmony_ci ret = 0; \ 54962306a36Sopenharmony_ci else if (__is_zero_x) \ 55062306a36Sopenharmony_ci ret = Y##_s ? 1 : -1; \ 55162306a36Sopenharmony_ci else if (__is_zero_y) \ 55262306a36Sopenharmony_ci ret = X##_s ? -1 : 1; \ 55362306a36Sopenharmony_ci else if (X##_s != Y##_s) \ 55462306a36Sopenharmony_ci ret = X##_s ? -1 : 1; \ 55562306a36Sopenharmony_ci else if (X##_e > Y##_e) \ 55662306a36Sopenharmony_ci ret = X##_s ? -1 : 1; \ 55762306a36Sopenharmony_ci else if (X##_e < Y##_e) \ 55862306a36Sopenharmony_ci ret = X##_s ? 1 : -1; \ 55962306a36Sopenharmony_ci else if (_FP_FRAC_GT_##wc(X, Y)) \ 56062306a36Sopenharmony_ci ret = X##_s ? -1 : 1; \ 56162306a36Sopenharmony_ci else if (_FP_FRAC_GT_##wc(Y, X)) \ 56262306a36Sopenharmony_ci ret = X##_s ? 1 : -1; \ 56362306a36Sopenharmony_ci else \ 56462306a36Sopenharmony_ci ret = 0; \ 56562306a36Sopenharmony_ci } \ 56662306a36Sopenharmony_ci } while (0) 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci/* Simplification for strict equality. */ 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci#define _FP_CMP_EQ(fs, wc, ret, X, Y) \ 57262306a36Sopenharmony_ci do { \ 57362306a36Sopenharmony_ci /* NANs are unordered */ \ 57462306a36Sopenharmony_ci if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \ 57562306a36Sopenharmony_ci || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \ 57662306a36Sopenharmony_ci { \ 57762306a36Sopenharmony_ci ret = 1; \ 57862306a36Sopenharmony_ci } \ 57962306a36Sopenharmony_ci else \ 58062306a36Sopenharmony_ci { \ 58162306a36Sopenharmony_ci ret = !(X##_e == Y##_e \ 58262306a36Sopenharmony_ci && _FP_FRAC_EQ_##wc(X, Y) \ 58362306a36Sopenharmony_ci && (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \ 58462306a36Sopenharmony_ci } \ 58562306a36Sopenharmony_ci } while (0) 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci/* 58862306a36Sopenharmony_ci * Main square root routine. The input value should be cooked. 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci#define _FP_SQRT(fs, wc, R, X) \ 59262306a36Sopenharmony_cido { \ 59362306a36Sopenharmony_ci _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S); \ 59462306a36Sopenharmony_ci _FP_W_TYPE q; \ 59562306a36Sopenharmony_ci switch (X##_c) \ 59662306a36Sopenharmony_ci { \ 59762306a36Sopenharmony_ci case FP_CLS_NAN: \ 59862306a36Sopenharmony_ci _FP_FRAC_COPY_##wc(R, X); \ 59962306a36Sopenharmony_ci R##_s = X##_s; \ 60062306a36Sopenharmony_ci R##_c = FP_CLS_NAN; \ 60162306a36Sopenharmony_ci break; \ 60262306a36Sopenharmony_ci case FP_CLS_INF: \ 60362306a36Sopenharmony_ci if (X##_s) \ 60462306a36Sopenharmony_ci { \ 60562306a36Sopenharmony_ci R##_s = _FP_NANSIGN_##fs; \ 60662306a36Sopenharmony_ci R##_c = FP_CLS_NAN; /* NAN */ \ 60762306a36Sopenharmony_ci _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ 60862306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); \ 60962306a36Sopenharmony_ci } \ 61062306a36Sopenharmony_ci else \ 61162306a36Sopenharmony_ci { \ 61262306a36Sopenharmony_ci R##_s = 0; \ 61362306a36Sopenharmony_ci R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */ \ 61462306a36Sopenharmony_ci } \ 61562306a36Sopenharmony_ci break; \ 61662306a36Sopenharmony_ci case FP_CLS_ZERO: \ 61762306a36Sopenharmony_ci R##_s = X##_s; \ 61862306a36Sopenharmony_ci R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */ \ 61962306a36Sopenharmony_ci break; \ 62062306a36Sopenharmony_ci case FP_CLS_NORMAL: \ 62162306a36Sopenharmony_ci R##_s = 0; \ 62262306a36Sopenharmony_ci if (X##_s) \ 62362306a36Sopenharmony_ci { \ 62462306a36Sopenharmony_ci R##_c = FP_CLS_NAN; /* sNAN */ \ 62562306a36Sopenharmony_ci R##_s = _FP_NANSIGN_##fs; \ 62662306a36Sopenharmony_ci _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ 62762306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); \ 62862306a36Sopenharmony_ci break; \ 62962306a36Sopenharmony_ci } \ 63062306a36Sopenharmony_ci R##_c = FP_CLS_NORMAL; \ 63162306a36Sopenharmony_ci if (X##_e & 1) \ 63262306a36Sopenharmony_ci _FP_FRAC_SLL_##wc(X, 1); \ 63362306a36Sopenharmony_ci R##_e = X##_e >> 1; \ 63462306a36Sopenharmony_ci _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc); \ 63562306a36Sopenharmony_ci _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc); \ 63662306a36Sopenharmony_ci q = _FP_OVERFLOW_##fs >> 1; \ 63762306a36Sopenharmony_ci _FP_SQRT_MEAT_##wc(R, S, T, X, q); \ 63862306a36Sopenharmony_ci } \ 63962306a36Sopenharmony_ci } while (0) 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci/* 64262306a36Sopenharmony_ci * Convert from FP to integer 64362306a36Sopenharmony_ci */ 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci/* RSIGNED can have following values: 64662306a36Sopenharmony_ci * 0: the number is required to be 0..(2^rsize)-1, if not, NV is set plus 64762306a36Sopenharmony_ci * the result is either 0 or (2^rsize)-1 depending on the sign in such case. 64862306a36Sopenharmony_ci * 1: the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is 64962306a36Sopenharmony_ci * set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending 65062306a36Sopenharmony_ci * on the sign in such case. 65162306a36Sopenharmony_ci * 2: the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is 65262306a36Sopenharmony_ci * set plus the result is truncated to fit into destination. 65362306a36Sopenharmony_ci * -1: the number is required to be -(2^(rsize-1))..(2^rsize)-1, if not, NV is 65462306a36Sopenharmony_ci * set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending 65562306a36Sopenharmony_ci * on the sign in such case. 65662306a36Sopenharmony_ci */ 65762306a36Sopenharmony_ci#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned) \ 65862306a36Sopenharmony_ci do { \ 65962306a36Sopenharmony_ci switch (X##_c) \ 66062306a36Sopenharmony_ci { \ 66162306a36Sopenharmony_ci case FP_CLS_NORMAL: \ 66262306a36Sopenharmony_ci if (X##_e < 0) \ 66362306a36Sopenharmony_ci { \ 66462306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INEXACT); \ 66562306a36Sopenharmony_ci fallthrough; \ 66662306a36Sopenharmony_ci case FP_CLS_ZERO: \ 66762306a36Sopenharmony_ci r = 0; \ 66862306a36Sopenharmony_ci } \ 66962306a36Sopenharmony_ci else if (X##_e >= rsize - (rsigned > 0 || X##_s) \ 67062306a36Sopenharmony_ci || (!rsigned && X##_s)) \ 67162306a36Sopenharmony_ci { /* overflow */ \ 67262306a36Sopenharmony_ci fallthrough; \ 67362306a36Sopenharmony_ci case FP_CLS_NAN: \ 67462306a36Sopenharmony_ci case FP_CLS_INF: \ 67562306a36Sopenharmony_ci if (rsigned == 2) \ 67662306a36Sopenharmony_ci { \ 67762306a36Sopenharmony_ci if (X##_c != FP_CLS_NORMAL \ 67862306a36Sopenharmony_ci || X##_e >= rsize - 1 + _FP_WFRACBITS_##fs) \ 67962306a36Sopenharmony_ci r = 0; \ 68062306a36Sopenharmony_ci else \ 68162306a36Sopenharmony_ci { \ 68262306a36Sopenharmony_ci _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1)); \ 68362306a36Sopenharmony_ci _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ 68462306a36Sopenharmony_ci } \ 68562306a36Sopenharmony_ci } \ 68662306a36Sopenharmony_ci else if (rsigned) \ 68762306a36Sopenharmony_ci { \ 68862306a36Sopenharmony_ci r = 1; \ 68962306a36Sopenharmony_ci r <<= rsize - 1; \ 69062306a36Sopenharmony_ci r -= 1 - X##_s; \ 69162306a36Sopenharmony_ci } \ 69262306a36Sopenharmony_ci else \ 69362306a36Sopenharmony_ci { \ 69462306a36Sopenharmony_ci r = 0; \ 69562306a36Sopenharmony_ci if (!X##_s) \ 69662306a36Sopenharmony_ci r = ~r; \ 69762306a36Sopenharmony_ci } \ 69862306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); \ 69962306a36Sopenharmony_ci } \ 70062306a36Sopenharmony_ci else \ 70162306a36Sopenharmony_ci { \ 70262306a36Sopenharmony_ci if (_FP_W_TYPE_SIZE*wc < rsize) \ 70362306a36Sopenharmony_ci { \ 70462306a36Sopenharmony_ci _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ 70562306a36Sopenharmony_ci r <<= X##_e - _FP_WFRACBITS_##fs; \ 70662306a36Sopenharmony_ci } \ 70762306a36Sopenharmony_ci else \ 70862306a36Sopenharmony_ci { \ 70962306a36Sopenharmony_ci if (X##_e >= _FP_WFRACBITS_##fs) \ 71062306a36Sopenharmony_ci _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1)); \ 71162306a36Sopenharmony_ci else if (X##_e < _FP_WFRACBITS_##fs - 1) \ 71262306a36Sopenharmony_ci { \ 71362306a36Sopenharmony_ci _FP_FRAC_SRS_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 2), \ 71462306a36Sopenharmony_ci _FP_WFRACBITS_##fs); \ 71562306a36Sopenharmony_ci if (_FP_FRAC_LOW_##wc(X) & 1) \ 71662306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INEXACT); \ 71762306a36Sopenharmony_ci _FP_FRAC_SRL_##wc(X, 1); \ 71862306a36Sopenharmony_ci } \ 71962306a36Sopenharmony_ci _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ 72062306a36Sopenharmony_ci } \ 72162306a36Sopenharmony_ci if (rsigned && X##_s) \ 72262306a36Sopenharmony_ci r = -r; \ 72362306a36Sopenharmony_ci } \ 72462306a36Sopenharmony_ci break; \ 72562306a36Sopenharmony_ci } \ 72662306a36Sopenharmony_ci } while (0) 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci#define _FP_TO_INT_ROUND(fs, wc, r, X, rsize, rsigned) \ 72962306a36Sopenharmony_ci do { \ 73062306a36Sopenharmony_ci r = 0; \ 73162306a36Sopenharmony_ci switch (X##_c) \ 73262306a36Sopenharmony_ci { \ 73362306a36Sopenharmony_ci case FP_CLS_NORMAL: \ 73462306a36Sopenharmony_ci if (X##_e >= _FP_FRACBITS_##fs - 1) \ 73562306a36Sopenharmony_ci { \ 73662306a36Sopenharmony_ci if (X##_e < rsize - 1 + _FP_WFRACBITS_##fs) \ 73762306a36Sopenharmony_ci { \ 73862306a36Sopenharmony_ci if (X##_e >= _FP_WFRACBITS_##fs - 1) \ 73962306a36Sopenharmony_ci { \ 74062306a36Sopenharmony_ci _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ 74162306a36Sopenharmony_ci r <<= X##_e - _FP_WFRACBITS_##fs + 1; \ 74262306a36Sopenharmony_ci } \ 74362306a36Sopenharmony_ci else \ 74462306a36Sopenharmony_ci { \ 74562306a36Sopenharmony_ci _FP_FRAC_SRL_##wc(X, _FP_WORKBITS - X##_e \ 74662306a36Sopenharmony_ci + _FP_FRACBITS_##fs - 1); \ 74762306a36Sopenharmony_ci _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ 74862306a36Sopenharmony_ci } \ 74962306a36Sopenharmony_ci } \ 75062306a36Sopenharmony_ci } \ 75162306a36Sopenharmony_ci else \ 75262306a36Sopenharmony_ci { \ 75362306a36Sopenharmony_ci int _lz0, _lz1; \ 75462306a36Sopenharmony_ci if (X##_e <= -_FP_WORKBITS - 1) \ 75562306a36Sopenharmony_ci _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \ 75662306a36Sopenharmony_ci else \ 75762306a36Sopenharmony_ci _FP_FRAC_SRS_##wc(X, _FP_FRACBITS_##fs - 1 - X##_e, \ 75862306a36Sopenharmony_ci _FP_WFRACBITS_##fs); \ 75962306a36Sopenharmony_ci _FP_FRAC_CLZ_##wc(_lz0, X); \ 76062306a36Sopenharmony_ci _FP_ROUND(wc, X); \ 76162306a36Sopenharmony_ci _FP_FRAC_CLZ_##wc(_lz1, X); \ 76262306a36Sopenharmony_ci if (_lz1 < _lz0) \ 76362306a36Sopenharmony_ci X##_e++; /* For overflow detection. */ \ 76462306a36Sopenharmony_ci _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ 76562306a36Sopenharmony_ci _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ 76662306a36Sopenharmony_ci } \ 76762306a36Sopenharmony_ci if (rsigned && X##_s) \ 76862306a36Sopenharmony_ci r = -r; \ 76962306a36Sopenharmony_ci if (X##_e >= rsize - (rsigned > 0 || X##_s) \ 77062306a36Sopenharmony_ci || (!rsigned && X##_s)) \ 77162306a36Sopenharmony_ci { /* overflow */ \ 77262306a36Sopenharmony_ci fallthrough; \ 77362306a36Sopenharmony_ci case FP_CLS_NAN: \ 77462306a36Sopenharmony_ci case FP_CLS_INF: \ 77562306a36Sopenharmony_ci if (!rsigned) \ 77662306a36Sopenharmony_ci { \ 77762306a36Sopenharmony_ci r = 0; \ 77862306a36Sopenharmony_ci if (!X##_s) \ 77962306a36Sopenharmony_ci r = ~r; \ 78062306a36Sopenharmony_ci } \ 78162306a36Sopenharmony_ci else if (rsigned != 2) \ 78262306a36Sopenharmony_ci { \ 78362306a36Sopenharmony_ci r = 1; \ 78462306a36Sopenharmony_ci r <<= rsize - 1; \ 78562306a36Sopenharmony_ci r -= 1 - X##_s; \ 78662306a36Sopenharmony_ci } \ 78762306a36Sopenharmony_ci FP_SET_EXCEPTION(FP_EX_INVALID); \ 78862306a36Sopenharmony_ci } \ 78962306a36Sopenharmony_ci break; \ 79062306a36Sopenharmony_ci case FP_CLS_ZERO: \ 79162306a36Sopenharmony_ci break; \ 79262306a36Sopenharmony_ci } \ 79362306a36Sopenharmony_ci } while (0) 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci#define _FP_FROM_INT(fs, wc, X, r, rsize, rtype) \ 79662306a36Sopenharmony_ci do { \ 79762306a36Sopenharmony_ci if (r) \ 79862306a36Sopenharmony_ci { \ 79962306a36Sopenharmony_ci unsigned rtype ur_; \ 80062306a36Sopenharmony_ci X##_c = FP_CLS_NORMAL; \ 80162306a36Sopenharmony_ci \ 80262306a36Sopenharmony_ci if ((X##_s = (r < 0))) \ 80362306a36Sopenharmony_ci ur_ = (unsigned rtype) -r; \ 80462306a36Sopenharmony_ci else \ 80562306a36Sopenharmony_ci ur_ = (unsigned rtype) r; \ 80662306a36Sopenharmony_ci (void) (((rsize) <= _FP_W_TYPE_SIZE) \ 80762306a36Sopenharmony_ci ? ({ __FP_CLZ(X##_e, ur_); }) \ 80862306a36Sopenharmony_ci : ({ \ 80962306a36Sopenharmony_ci __FP_CLZ_2(X##_e, (_FP_W_TYPE)(ur_ >> _FP_W_TYPE_SIZE), \ 81062306a36Sopenharmony_ci (_FP_W_TYPE)ur_); \ 81162306a36Sopenharmony_ci })); \ 81262306a36Sopenharmony_ci if (rsize < _FP_W_TYPE_SIZE) \ 81362306a36Sopenharmony_ci X##_e -= (_FP_W_TYPE_SIZE - rsize); \ 81462306a36Sopenharmony_ci X##_e = rsize - X##_e - 1; \ 81562306a36Sopenharmony_ci \ 81662306a36Sopenharmony_ci if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs <= X##_e) \ 81762306a36Sopenharmony_ci __FP_FRAC_SRS_1(ur_, (X##_e - _FP_WFRACBITS_##fs + 1), rsize);\ 81862306a36Sopenharmony_ci _FP_FRAC_DISASSEMBLE_##wc(X, ur_, rsize); \ 81962306a36Sopenharmony_ci if ((_FP_WFRACBITS_##fs - X##_e - 1) > 0) \ 82062306a36Sopenharmony_ci _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \ 82162306a36Sopenharmony_ci } \ 82262306a36Sopenharmony_ci else \ 82362306a36Sopenharmony_ci { \ 82462306a36Sopenharmony_ci X##_c = FP_CLS_ZERO, X##_s = 0; \ 82562306a36Sopenharmony_ci } \ 82662306a36Sopenharmony_ci } while (0) 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci#define FP_CONV(dfs,sfs,dwc,swc,D,S) \ 83062306a36Sopenharmony_ci do { \ 83162306a36Sopenharmony_ci _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S); \ 83262306a36Sopenharmony_ci D##_e = S##_e; \ 83362306a36Sopenharmony_ci D##_c = S##_c; \ 83462306a36Sopenharmony_ci D##_s = S##_s; \ 83562306a36Sopenharmony_ci } while (0) 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci/* 83862306a36Sopenharmony_ci * Helper primitives. 83962306a36Sopenharmony_ci */ 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci/* Count leading zeros in a word. */ 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci#ifndef __FP_CLZ 84462306a36Sopenharmony_ci#if _FP_W_TYPE_SIZE < 64 84562306a36Sopenharmony_ci/* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */ 84662306a36Sopenharmony_ci#define __FP_CLZ(r, x) \ 84762306a36Sopenharmony_ci do { \ 84862306a36Sopenharmony_ci _FP_W_TYPE _t = (x); \ 84962306a36Sopenharmony_ci r = _FP_W_TYPE_SIZE - 1; \ 85062306a36Sopenharmony_ci if (_t > 0xffff) r -= 16; \ 85162306a36Sopenharmony_ci if (_t > 0xffff) _t >>= 16; \ 85262306a36Sopenharmony_ci if (_t > 0xff) r -= 8; \ 85362306a36Sopenharmony_ci if (_t > 0xff) _t >>= 8; \ 85462306a36Sopenharmony_ci if (_t & 0xf0) r -= 4; \ 85562306a36Sopenharmony_ci if (_t & 0xf0) _t >>= 4; \ 85662306a36Sopenharmony_ci if (_t & 0xc) r -= 2; \ 85762306a36Sopenharmony_ci if (_t & 0xc) _t >>= 2; \ 85862306a36Sopenharmony_ci if (_t & 0x2) r -= 1; \ 85962306a36Sopenharmony_ci } while (0) 86062306a36Sopenharmony_ci#else /* not _FP_W_TYPE_SIZE < 64 */ 86162306a36Sopenharmony_ci#define __FP_CLZ(r, x) \ 86262306a36Sopenharmony_ci do { \ 86362306a36Sopenharmony_ci _FP_W_TYPE _t = (x); \ 86462306a36Sopenharmony_ci r = _FP_W_TYPE_SIZE - 1; \ 86562306a36Sopenharmony_ci if (_t > 0xffffffff) r -= 32; \ 86662306a36Sopenharmony_ci if (_t > 0xffffffff) _t >>= 32; \ 86762306a36Sopenharmony_ci if (_t > 0xffff) r -= 16; \ 86862306a36Sopenharmony_ci if (_t > 0xffff) _t >>= 16; \ 86962306a36Sopenharmony_ci if (_t > 0xff) r -= 8; \ 87062306a36Sopenharmony_ci if (_t > 0xff) _t >>= 8; \ 87162306a36Sopenharmony_ci if (_t & 0xf0) r -= 4; \ 87262306a36Sopenharmony_ci if (_t & 0xf0) _t >>= 4; \ 87362306a36Sopenharmony_ci if (_t & 0xc) r -= 2; \ 87462306a36Sopenharmony_ci if (_t & 0xc) _t >>= 2; \ 87562306a36Sopenharmony_ci if (_t & 0x2) r -= 1; \ 87662306a36Sopenharmony_ci } while (0) 87762306a36Sopenharmony_ci#endif /* not _FP_W_TYPE_SIZE < 64 */ 87862306a36Sopenharmony_ci#endif /* ndef __FP_CLZ */ 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci#define _FP_DIV_HELP_imm(q, r, n, d) \ 88162306a36Sopenharmony_ci do { \ 88262306a36Sopenharmony_ci q = n / d, r = n % d; \ 88362306a36Sopenharmony_ci } while (0) 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci#endif /* __MATH_EMU_OP_COMMON_H__ */ 886