162306a36Sopenharmony_ci/* Software floating-point emulation.
262306a36Sopenharmony_ci   Basic four-word fraction declaration and manipulation.
362306a36Sopenharmony_ci   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
462306a36Sopenharmony_ci   This file is part of the GNU C Library.
562306a36Sopenharmony_ci   Contributed by Richard Henderson (rth@cygnus.com),
662306a36Sopenharmony_ci		  Jakub Jelinek (jj@ultra.linux.cz),
762306a36Sopenharmony_ci		  David S. Miller (davem@redhat.com) and
862306a36Sopenharmony_ci		  Peter Maydell (pmaydell@chiark.greenend.org.uk).
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci   The GNU C Library is free software; you can redistribute it and/or
1162306a36Sopenharmony_ci   modify it under the terms of the GNU Library General Public License as
1262306a36Sopenharmony_ci   published by the Free Software Foundation; either version 2 of the
1362306a36Sopenharmony_ci   License, or (at your option) any later version.
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci   The GNU C Library is distributed in the hope that it will be useful,
1662306a36Sopenharmony_ci   but WITHOUT ANY WARRANTY; without even the implied warranty of
1762306a36Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1862306a36Sopenharmony_ci   Library General Public License for more details.
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci   You should have received a copy of the GNU Library General Public
2162306a36Sopenharmony_ci   License along with the GNU C Library; see the file COPYING.LIB.  If
2262306a36Sopenharmony_ci   not, write to the Free Software Foundation, Inc.,
2362306a36Sopenharmony_ci   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#ifndef __MATH_EMU_OP_4_H__
2662306a36Sopenharmony_ci#define __MATH_EMU_OP_4_H__
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define _FP_FRAC_DECL_4(X)	_FP_W_TYPE X##_f[4]
2962306a36Sopenharmony_ci#define _FP_FRAC_COPY_4(D,S)			\
3062306a36Sopenharmony_ci  (D##_f[0] = S##_f[0], D##_f[1] = S##_f[1],	\
3162306a36Sopenharmony_ci   D##_f[2] = S##_f[2], D##_f[3] = S##_f[3])
3262306a36Sopenharmony_ci#define _FP_FRAC_SET_4(X,I)	__FP_FRAC_SET_4(X, I)
3362306a36Sopenharmony_ci#define _FP_FRAC_HIGH_4(X)	(X##_f[3])
3462306a36Sopenharmony_ci#define _FP_FRAC_LOW_4(X)	(X##_f[0])
3562306a36Sopenharmony_ci#define _FP_FRAC_WORD_4(X,w)	(X##_f[w])
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define _FP_FRAC_SLL_4(X,N)						\
3862306a36Sopenharmony_ci  do {									\
3962306a36Sopenharmony_ci    _FP_I_TYPE _up, _down, _skip, _i;					\
4062306a36Sopenharmony_ci    _skip = (N) / _FP_W_TYPE_SIZE;					\
4162306a36Sopenharmony_ci    _up = (N) % _FP_W_TYPE_SIZE;					\
4262306a36Sopenharmony_ci    _down = _FP_W_TYPE_SIZE - _up;					\
4362306a36Sopenharmony_ci    if (!_up)								\
4462306a36Sopenharmony_ci      for (_i = 3; _i >= _skip; --_i)					\
4562306a36Sopenharmony_ci	X##_f[_i] = X##_f[_i-_skip];					\
4662306a36Sopenharmony_ci    else								\
4762306a36Sopenharmony_ci      {									\
4862306a36Sopenharmony_ci	for (_i = 3; _i > _skip; --_i)					\
4962306a36Sopenharmony_ci	  X##_f[_i] = X##_f[_i-_skip] << _up				\
5062306a36Sopenharmony_ci		      | X##_f[_i-_skip-1] >> _down;			\
5162306a36Sopenharmony_ci	X##_f[_i--] = X##_f[0] << _up; 					\
5262306a36Sopenharmony_ci      }									\
5362306a36Sopenharmony_ci    for (; _i >= 0; --_i)						\
5462306a36Sopenharmony_ci      X##_f[_i] = 0;							\
5562306a36Sopenharmony_ci  } while (0)
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* This one was broken too */
5862306a36Sopenharmony_ci#define _FP_FRAC_SRL_4(X,N)						\
5962306a36Sopenharmony_ci  do {									\
6062306a36Sopenharmony_ci    _FP_I_TYPE _up, _down, _skip, _i;					\
6162306a36Sopenharmony_ci    _skip = (N) / _FP_W_TYPE_SIZE;					\
6262306a36Sopenharmony_ci    _down = (N) % _FP_W_TYPE_SIZE;					\
6362306a36Sopenharmony_ci    _up = _FP_W_TYPE_SIZE - _down;					\
6462306a36Sopenharmony_ci    if (!_down)								\
6562306a36Sopenharmony_ci      for (_i = 0; _i <= 3-_skip; ++_i)					\
6662306a36Sopenharmony_ci	X##_f[_i] = X##_f[_i+_skip];					\
6762306a36Sopenharmony_ci    else								\
6862306a36Sopenharmony_ci      {									\
6962306a36Sopenharmony_ci	for (_i = 0; _i < 3-_skip; ++_i)				\
7062306a36Sopenharmony_ci	  X##_f[_i] = X##_f[_i+_skip] >> _down				\
7162306a36Sopenharmony_ci		      | X##_f[_i+_skip+1] << _up;			\
7262306a36Sopenharmony_ci	X##_f[_i++] = X##_f[3] >> _down;				\
7362306a36Sopenharmony_ci      }									\
7462306a36Sopenharmony_ci    for (; _i < 4; ++_i)						\
7562306a36Sopenharmony_ci      X##_f[_i] = 0;							\
7662306a36Sopenharmony_ci  } while (0)
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* Right shift with sticky-lsb.
8062306a36Sopenharmony_ci * What this actually means is that we do a standard right-shift,
8162306a36Sopenharmony_ci * but that if any of the bits that fall off the right hand side
8262306a36Sopenharmony_ci * were one then we always set the LSbit.
8362306a36Sopenharmony_ci */
8462306a36Sopenharmony_ci#define _FP_FRAC_SRS_4(X,N,size)					\
8562306a36Sopenharmony_ci  do {									\
8662306a36Sopenharmony_ci    _FP_I_TYPE _up, _down, _skip, _i;					\
8762306a36Sopenharmony_ci    _FP_W_TYPE _s;							\
8862306a36Sopenharmony_ci    _skip = (N) / _FP_W_TYPE_SIZE;					\
8962306a36Sopenharmony_ci    _down = (N) % _FP_W_TYPE_SIZE;					\
9062306a36Sopenharmony_ci    _up = _FP_W_TYPE_SIZE - _down;					\
9162306a36Sopenharmony_ci    for (_s = _i = 0; _i < _skip; ++_i)					\
9262306a36Sopenharmony_ci      _s |= X##_f[_i];							\
9362306a36Sopenharmony_ci    _s |= X##_f[_i] << _up;						\
9462306a36Sopenharmony_ci/* s is now != 0 if we want to set the LSbit */				\
9562306a36Sopenharmony_ci    if (!_down)								\
9662306a36Sopenharmony_ci      for (_i = 0; _i <= 3-_skip; ++_i)					\
9762306a36Sopenharmony_ci	X##_f[_i] = X##_f[_i+_skip];					\
9862306a36Sopenharmony_ci    else								\
9962306a36Sopenharmony_ci      {									\
10062306a36Sopenharmony_ci	for (_i = 0; _i < 3-_skip; ++_i)				\
10162306a36Sopenharmony_ci	  X##_f[_i] = X##_f[_i+_skip] >> _down				\
10262306a36Sopenharmony_ci		      | X##_f[_i+_skip+1] << _up;			\
10362306a36Sopenharmony_ci	X##_f[_i++] = X##_f[3] >> _down;				\
10462306a36Sopenharmony_ci      }									\
10562306a36Sopenharmony_ci    for (; _i < 4; ++_i)						\
10662306a36Sopenharmony_ci      X##_f[_i] = 0;							\
10762306a36Sopenharmony_ci    /* don't fix the LSB until the very end when we're sure f[0] is stable */	\
10862306a36Sopenharmony_ci    X##_f[0] |= (_s != 0);						\
10962306a36Sopenharmony_ci  } while (0)
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define _FP_FRAC_ADD_4(R,X,Y)						\
11262306a36Sopenharmony_ci  __FP_FRAC_ADD_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0],		\
11362306a36Sopenharmony_ci		  X##_f[3], X##_f[2], X##_f[1], X##_f[0],		\
11462306a36Sopenharmony_ci		  Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci#define _FP_FRAC_SUB_4(R,X,Y)						\
11762306a36Sopenharmony_ci  __FP_FRAC_SUB_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0],		\
11862306a36Sopenharmony_ci		  X##_f[3], X##_f[2], X##_f[1], X##_f[0],		\
11962306a36Sopenharmony_ci		  Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#define _FP_FRAC_DEC_4(X,Y)						\
12262306a36Sopenharmony_ci  __FP_FRAC_DEC_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0],		\
12362306a36Sopenharmony_ci		  Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci#define _FP_FRAC_ADDI_4(X,I)						\
12662306a36Sopenharmony_ci  __FP_FRAC_ADDI_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], I)
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define _FP_ZEROFRAC_4  0,0,0,0
12962306a36Sopenharmony_ci#define _FP_MINFRAC_4   0,0,0,1
13062306a36Sopenharmony_ci#define _FP_MAXFRAC_4	(~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0)
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci#define _FP_FRAC_ZEROP_4(X)     ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0)
13362306a36Sopenharmony_ci#define _FP_FRAC_NEGP_4(X)      ((_FP_WS_TYPE)X##_f[3] < 0)
13462306a36Sopenharmony_ci#define _FP_FRAC_OVERP_4(fs,X)  (_FP_FRAC_HIGH_##fs(X) & _FP_OVERFLOW_##fs)
13562306a36Sopenharmony_ci#define _FP_FRAC_CLEAR_OVERP_4(fs,X)  (_FP_FRAC_HIGH_##fs(X) &= ~_FP_OVERFLOW_##fs)
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci#define _FP_FRAC_EQ_4(X,Y)				\
13862306a36Sopenharmony_ci (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1]		\
13962306a36Sopenharmony_ci  && X##_f[2] == Y##_f[2] && X##_f[3] == Y##_f[3])
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci#define _FP_FRAC_GT_4(X,Y)				\
14262306a36Sopenharmony_ci (X##_f[3] > Y##_f[3] ||				\
14362306a36Sopenharmony_ci  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||	\
14462306a36Sopenharmony_ci   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||	\
14562306a36Sopenharmony_ci    (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0])	\
14662306a36Sopenharmony_ci   ))							\
14762306a36Sopenharmony_ci  ))							\
14862306a36Sopenharmony_ci )
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci#define _FP_FRAC_GE_4(X,Y)				\
15162306a36Sopenharmony_ci (X##_f[3] > Y##_f[3] ||				\
15262306a36Sopenharmony_ci  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||	\
15362306a36Sopenharmony_ci   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||	\
15462306a36Sopenharmony_ci    (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0])	\
15562306a36Sopenharmony_ci   ))							\
15662306a36Sopenharmony_ci  ))							\
15762306a36Sopenharmony_ci )
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci#define _FP_FRAC_CLZ_4(R,X)		\
16162306a36Sopenharmony_ci  do {					\
16262306a36Sopenharmony_ci    if (X##_f[3])			\
16362306a36Sopenharmony_ci    {					\
16462306a36Sopenharmony_ci	__FP_CLZ(R,X##_f[3]);		\
16562306a36Sopenharmony_ci    }					\
16662306a36Sopenharmony_ci    else if (X##_f[2])			\
16762306a36Sopenharmony_ci    {					\
16862306a36Sopenharmony_ci	__FP_CLZ(R,X##_f[2]);		\
16962306a36Sopenharmony_ci	R += _FP_W_TYPE_SIZE;		\
17062306a36Sopenharmony_ci    }					\
17162306a36Sopenharmony_ci    else if (X##_f[1])			\
17262306a36Sopenharmony_ci    {					\
17362306a36Sopenharmony_ci	__FP_CLZ(R,X##_f[2]);		\
17462306a36Sopenharmony_ci	R += _FP_W_TYPE_SIZE*2;		\
17562306a36Sopenharmony_ci    }					\
17662306a36Sopenharmony_ci    else				\
17762306a36Sopenharmony_ci    {					\
17862306a36Sopenharmony_ci	__FP_CLZ(R,X##_f[0]);		\
17962306a36Sopenharmony_ci	R += _FP_W_TYPE_SIZE*3;		\
18062306a36Sopenharmony_ci    }					\
18162306a36Sopenharmony_ci  } while(0)
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci#define _FP_UNPACK_RAW_4(fs, X, val)				\
18562306a36Sopenharmony_ci  do {								\
18662306a36Sopenharmony_ci    union _FP_UNION_##fs _flo; _flo.flt = (val);		\
18762306a36Sopenharmony_ci    X##_f[0] = _flo.bits.frac0;					\
18862306a36Sopenharmony_ci    X##_f[1] = _flo.bits.frac1;					\
18962306a36Sopenharmony_ci    X##_f[2] = _flo.bits.frac2;					\
19062306a36Sopenharmony_ci    X##_f[3] = _flo.bits.frac3;					\
19162306a36Sopenharmony_ci    X##_e  = _flo.bits.exp;					\
19262306a36Sopenharmony_ci    X##_s  = _flo.bits.sign;					\
19362306a36Sopenharmony_ci  } while (0)
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci#define _FP_UNPACK_RAW_4_P(fs, X, val)				\
19662306a36Sopenharmony_ci  do {								\
19762306a36Sopenharmony_ci    union _FP_UNION_##fs *_flo =				\
19862306a36Sopenharmony_ci      (union _FP_UNION_##fs *)(val);				\
19962306a36Sopenharmony_ci								\
20062306a36Sopenharmony_ci    X##_f[0] = _flo->bits.frac0;				\
20162306a36Sopenharmony_ci    X##_f[1] = _flo->bits.frac1;				\
20262306a36Sopenharmony_ci    X##_f[2] = _flo->bits.frac2;				\
20362306a36Sopenharmony_ci    X##_f[3] = _flo->bits.frac3;				\
20462306a36Sopenharmony_ci    X##_e  = _flo->bits.exp;					\
20562306a36Sopenharmony_ci    X##_s  = _flo->bits.sign;					\
20662306a36Sopenharmony_ci  } while (0)
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci#define _FP_PACK_RAW_4(fs, val, X)				\
20962306a36Sopenharmony_ci  do {								\
21062306a36Sopenharmony_ci    union _FP_UNION_##fs _flo;					\
21162306a36Sopenharmony_ci    _flo.bits.frac0 = X##_f[0];					\
21262306a36Sopenharmony_ci    _flo.bits.frac1 = X##_f[1];					\
21362306a36Sopenharmony_ci    _flo.bits.frac2 = X##_f[2];					\
21462306a36Sopenharmony_ci    _flo.bits.frac3 = X##_f[3];					\
21562306a36Sopenharmony_ci    _flo.bits.exp   = X##_e;					\
21662306a36Sopenharmony_ci    _flo.bits.sign  = X##_s;					\
21762306a36Sopenharmony_ci    (val) = _flo.flt;				   		\
21862306a36Sopenharmony_ci  } while (0)
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci#define _FP_PACK_RAW_4_P(fs, val, X)				\
22162306a36Sopenharmony_ci  do {								\
22262306a36Sopenharmony_ci    union _FP_UNION_##fs *_flo =				\
22362306a36Sopenharmony_ci      (union _FP_UNION_##fs *)(val);				\
22462306a36Sopenharmony_ci								\
22562306a36Sopenharmony_ci    _flo->bits.frac0 = X##_f[0];				\
22662306a36Sopenharmony_ci    _flo->bits.frac1 = X##_f[1];				\
22762306a36Sopenharmony_ci    _flo->bits.frac2 = X##_f[2];				\
22862306a36Sopenharmony_ci    _flo->bits.frac3 = X##_f[3];				\
22962306a36Sopenharmony_ci    _flo->bits.exp   = X##_e;					\
23062306a36Sopenharmony_ci    _flo->bits.sign  = X##_s;					\
23162306a36Sopenharmony_ci  } while (0)
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci/*
23462306a36Sopenharmony_ci * Multiplication algorithms:
23562306a36Sopenharmony_ci */
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci/* Given a 1W * 1W => 2W primitive, do the extended multiplication.  */
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci#define _FP_MUL_MEAT_4_wide(wfracbits, R, X, Y, doit)			    \
24062306a36Sopenharmony_ci  do {									    \
24162306a36Sopenharmony_ci    _FP_FRAC_DECL_8(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c);	    \
24262306a36Sopenharmony_ci    _FP_FRAC_DECL_2(_d); _FP_FRAC_DECL_2(_e); _FP_FRAC_DECL_2(_f);	    \
24362306a36Sopenharmony_ci									    \
24462306a36Sopenharmony_ci    doit(_FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0), X##_f[0], Y##_f[0]); \
24562306a36Sopenharmony_ci    doit(_b_f1, _b_f0, X##_f[0], Y##_f[1]);				    \
24662306a36Sopenharmony_ci    doit(_c_f1, _c_f0, X##_f[1], Y##_f[0]);				    \
24762306a36Sopenharmony_ci    doit(_d_f1, _d_f0, X##_f[1], Y##_f[1]);				    \
24862306a36Sopenharmony_ci    doit(_e_f1, _e_f0, X##_f[0], Y##_f[2]);				    \
24962306a36Sopenharmony_ci    doit(_f_f1, _f_f0, X##_f[2], Y##_f[0]);				    \
25062306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2),	    \
25162306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,1), 0,_b_f1,_b_f0,		    \
25262306a36Sopenharmony_ci		    0,0,_FP_FRAC_WORD_8(_z,1));				    \
25362306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2),	    \
25462306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,1), 0,_c_f1,_c_f0,		    \
25562306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2),	    \
25662306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,1));				    \
25762306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),	    \
25862306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,2), 0,_d_f1,_d_f0,		    \
25962306a36Sopenharmony_ci		    0,_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2));	    \
26062306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),	    \
26162306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,2), 0,_e_f1,_e_f0,		    \
26262306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),	    \
26362306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,2));				    \
26462306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),	    \
26562306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,2), 0,_f_f1,_f_f0,		    \
26662306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),	    \
26762306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,2));				    \
26862306a36Sopenharmony_ci    doit(_b_f1, _b_f0, X##_f[0], Y##_f[3]);				    \
26962306a36Sopenharmony_ci    doit(_c_f1, _c_f0, X##_f[3], Y##_f[0]);				    \
27062306a36Sopenharmony_ci    doit(_d_f1, _d_f0, X##_f[1], Y##_f[2]);				    \
27162306a36Sopenharmony_ci    doit(_e_f1, _e_f0, X##_f[2], Y##_f[1]);				    \
27262306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
27362306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,3), 0,_b_f1,_b_f0,		    \
27462306a36Sopenharmony_ci		    0,_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3));	    \
27562306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
27662306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,3), 0,_c_f1,_c_f0,		    \
27762306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
27862306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,3));				    \
27962306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
28062306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,3), 0,_d_f1,_d_f0,		    \
28162306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
28262306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,3));				    \
28362306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
28462306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,3), 0,_e_f1,_e_f0,		    \
28562306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),	    \
28662306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,3));				    \
28762306a36Sopenharmony_ci    doit(_b_f1, _b_f0, X##_f[2], Y##_f[2]);				    \
28862306a36Sopenharmony_ci    doit(_c_f1, _c_f0, X##_f[1], Y##_f[3]);				    \
28962306a36Sopenharmony_ci    doit(_d_f1, _d_f0, X##_f[3], Y##_f[1]);				    \
29062306a36Sopenharmony_ci    doit(_e_f1, _e_f0, X##_f[2], Y##_f[3]);				    \
29162306a36Sopenharmony_ci    doit(_f_f1, _f_f0, X##_f[3], Y##_f[2]);				    \
29262306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),	    \
29362306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,4), 0,_b_f1,_b_f0,		    \
29462306a36Sopenharmony_ci		    0,_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4));	    \
29562306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),	    \
29662306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,4), 0,_c_f1,_c_f0,		    \
29762306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),	    \
29862306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,4));				    \
29962306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),	    \
30062306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,4), 0,_d_f1,_d_f0,		    \
30162306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),	    \
30262306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,4));				    \
30362306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6),	    \
30462306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,5), 0,_e_f1,_e_f0,		    \
30562306a36Sopenharmony_ci		    0,_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5));	    \
30662306a36Sopenharmony_ci    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6),	    \
30762306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,5), 0,_f_f1,_f_f0,		    \
30862306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6),	    \
30962306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,5));				    \
31062306a36Sopenharmony_ci    doit(_b_f1, _b_f0, X##_f[3], Y##_f[3]);				    \
31162306a36Sopenharmony_ci    __FP_FRAC_ADD_2(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6),	    \
31262306a36Sopenharmony_ci		    _b_f1,_b_f0,					    \
31362306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6));	    \
31462306a36Sopenharmony_ci									    \
31562306a36Sopenharmony_ci    /* Normalize since we know where the msb of the multiplicands	    \
31662306a36Sopenharmony_ci       were (bit B), we know that the msb of the of the product is	    \
31762306a36Sopenharmony_ci       at either 2B or 2B-1.  */					    \
31862306a36Sopenharmony_ci    _FP_FRAC_SRS_8(_z, wfracbits-1, 2*wfracbits);			    \
31962306a36Sopenharmony_ci    __FP_FRAC_SET_4(R, _FP_FRAC_WORD_8(_z,3), _FP_FRAC_WORD_8(_z,2),	    \
32062306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0));	    \
32162306a36Sopenharmony_ci  } while (0)
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci#define _FP_MUL_MEAT_4_gmp(wfracbits, R, X, Y)				    \
32462306a36Sopenharmony_ci  do {									    \
32562306a36Sopenharmony_ci    _FP_FRAC_DECL_8(_z);						    \
32662306a36Sopenharmony_ci									    \
32762306a36Sopenharmony_ci    mpn_mul_n(_z_f, _x_f, _y_f, 4);					    \
32862306a36Sopenharmony_ci									    \
32962306a36Sopenharmony_ci    /* Normalize since we know where the msb of the multiplicands	    \
33062306a36Sopenharmony_ci       were (bit B), we know that the msb of the of the product is	    \
33162306a36Sopenharmony_ci       at either 2B or 2B-1.  */					    \
33262306a36Sopenharmony_ci    _FP_FRAC_SRS_8(_z, wfracbits-1, 2*wfracbits);	 		    \
33362306a36Sopenharmony_ci    __FP_FRAC_SET_4(R, _FP_FRAC_WORD_8(_z,3), _FP_FRAC_WORD_8(_z,2),	    \
33462306a36Sopenharmony_ci		    _FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0));	    \
33562306a36Sopenharmony_ci  } while (0)
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci/*
33862306a36Sopenharmony_ci * Helper utility for _FP_DIV_MEAT_4_udiv:
33962306a36Sopenharmony_ci * pppp = m * nnn
34062306a36Sopenharmony_ci */
34162306a36Sopenharmony_ci#define umul_ppppmnnn(p3,p2,p1,p0,m,n2,n1,n0)				    \
34262306a36Sopenharmony_ci  do {									    \
34362306a36Sopenharmony_ci    UWtype _t;								    \
34462306a36Sopenharmony_ci    umul_ppmm(p1,p0,m,n0);						    \
34562306a36Sopenharmony_ci    umul_ppmm(p2,_t,m,n1);						    \
34662306a36Sopenharmony_ci    __FP_FRAC_ADDI_2(p2,p1,_t);						    \
34762306a36Sopenharmony_ci    umul_ppmm(p3,_t,m,n2);						    \
34862306a36Sopenharmony_ci    __FP_FRAC_ADDI_2(p3,p2,_t);						    \
34962306a36Sopenharmony_ci  } while (0)
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci/*
35262306a36Sopenharmony_ci * Division algorithms:
35362306a36Sopenharmony_ci */
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci#define _FP_DIV_MEAT_4_udiv(fs, R, X, Y)				    \
35662306a36Sopenharmony_ci  do {									    \
35762306a36Sopenharmony_ci    int _i;								    \
35862306a36Sopenharmony_ci    _FP_FRAC_DECL_4(_n); _FP_FRAC_DECL_4(_m);				    \
35962306a36Sopenharmony_ci    _FP_FRAC_SET_4(_n, _FP_ZEROFRAC_4);					    \
36062306a36Sopenharmony_ci    if (_FP_FRAC_GT_4(X, Y))						    \
36162306a36Sopenharmony_ci      {									    \
36262306a36Sopenharmony_ci	_n_f[3] = X##_f[0] << (_FP_W_TYPE_SIZE - 1);			    \
36362306a36Sopenharmony_ci	_FP_FRAC_SRL_4(X, 1);						    \
36462306a36Sopenharmony_ci      }									    \
36562306a36Sopenharmony_ci    else								    \
36662306a36Sopenharmony_ci      R##_e--;								    \
36762306a36Sopenharmony_ci									    \
36862306a36Sopenharmony_ci    /* Normalize, i.e. make the most significant bit of the 		    \
36962306a36Sopenharmony_ci       denominator set. */						    \
37062306a36Sopenharmony_ci    _FP_FRAC_SLL_4(Y, _FP_WFRACXBITS_##fs);				    \
37162306a36Sopenharmony_ci									    \
37262306a36Sopenharmony_ci    for (_i = 3; ; _i--)						    \
37362306a36Sopenharmony_ci      {									    \
37462306a36Sopenharmony_ci        if (X##_f[3] == Y##_f[3])					    \
37562306a36Sopenharmony_ci          {								    \
37662306a36Sopenharmony_ci            /* This is a special case, not an optimization		    \
37762306a36Sopenharmony_ci               (X##_f[3]/Y##_f[3] would not fit into UWtype).		    \
37862306a36Sopenharmony_ci               As X## is guaranteed to be < Y,  R##_f[_i] can be either	    \
37962306a36Sopenharmony_ci               (UWtype)-1 or (UWtype)-2.  */				    \
38062306a36Sopenharmony_ci            R##_f[_i] = -1;						    \
38162306a36Sopenharmony_ci            if (!_i)							    \
38262306a36Sopenharmony_ci	      break;							    \
38362306a36Sopenharmony_ci            __FP_FRAC_SUB_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0],	    \
38462306a36Sopenharmony_ci			    Y##_f[2], Y##_f[1], Y##_f[0], 0,		    \
38562306a36Sopenharmony_ci			    X##_f[2], X##_f[1], X##_f[0], _n_f[_i]);	    \
38662306a36Sopenharmony_ci            _FP_FRAC_SUB_4(X, Y, X);					    \
38762306a36Sopenharmony_ci            if (X##_f[3] > Y##_f[3])					    \
38862306a36Sopenharmony_ci              {								    \
38962306a36Sopenharmony_ci                R##_f[_i] = -2;						    \
39062306a36Sopenharmony_ci                _FP_FRAC_ADD_4(X, Y, X);				    \
39162306a36Sopenharmony_ci              }								    \
39262306a36Sopenharmony_ci          }								    \
39362306a36Sopenharmony_ci        else								    \
39462306a36Sopenharmony_ci          {								    \
39562306a36Sopenharmony_ci            udiv_qrnnd(R##_f[_i], X##_f[3], X##_f[3], X##_f[2], Y##_f[3]);  \
39662306a36Sopenharmony_ci            umul_ppppmnnn(_m_f[3], _m_f[2], _m_f[1], _m_f[0],		    \
39762306a36Sopenharmony_ci			  R##_f[_i], Y##_f[2], Y##_f[1], Y##_f[0]);	    \
39862306a36Sopenharmony_ci            X##_f[2] = X##_f[1];					    \
39962306a36Sopenharmony_ci            X##_f[1] = X##_f[0];					    \
40062306a36Sopenharmony_ci            X##_f[0] = _n_f[_i];					    \
40162306a36Sopenharmony_ci            if (_FP_FRAC_GT_4(_m, X))					    \
40262306a36Sopenharmony_ci              {								    \
40362306a36Sopenharmony_ci                R##_f[_i]--;						    \
40462306a36Sopenharmony_ci                _FP_FRAC_ADD_4(X, Y, X);				    \
40562306a36Sopenharmony_ci                if (_FP_FRAC_GE_4(X, Y) && _FP_FRAC_GT_4(_m, X))	    \
40662306a36Sopenharmony_ci                  {							    \
40762306a36Sopenharmony_ci		    R##_f[_i]--;					    \
40862306a36Sopenharmony_ci		    _FP_FRAC_ADD_4(X, Y, X);				    \
40962306a36Sopenharmony_ci                  }							    \
41062306a36Sopenharmony_ci              }								    \
41162306a36Sopenharmony_ci            _FP_FRAC_DEC_4(X, _m);					    \
41262306a36Sopenharmony_ci            if (!_i)							    \
41362306a36Sopenharmony_ci	      {								    \
41462306a36Sopenharmony_ci		if (!_FP_FRAC_EQ_4(X, _m))				    \
41562306a36Sopenharmony_ci		  R##_f[0] |= _FP_WORK_STICKY;				    \
41662306a36Sopenharmony_ci		break;							    \
41762306a36Sopenharmony_ci	      }								    \
41862306a36Sopenharmony_ci          }								    \
41962306a36Sopenharmony_ci      }									    \
42062306a36Sopenharmony_ci  } while (0)
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci/*
42462306a36Sopenharmony_ci * Square root algorithms:
42562306a36Sopenharmony_ci * We have just one right now, maybe Newton approximation
42662306a36Sopenharmony_ci * should be added for those machines where division is fast.
42762306a36Sopenharmony_ci */
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci#define _FP_SQRT_MEAT_4(R, S, T, X, q)				\
43062306a36Sopenharmony_ci  do {								\
43162306a36Sopenharmony_ci    while (q)							\
43262306a36Sopenharmony_ci      {								\
43362306a36Sopenharmony_ci	T##_f[3] = S##_f[3] + q;				\
43462306a36Sopenharmony_ci	if (T##_f[3] <= X##_f[3])				\
43562306a36Sopenharmony_ci	  {							\
43662306a36Sopenharmony_ci	    S##_f[3] = T##_f[3] + q;				\
43762306a36Sopenharmony_ci	    X##_f[3] -= T##_f[3];				\
43862306a36Sopenharmony_ci	    R##_f[3] += q;					\
43962306a36Sopenharmony_ci	  }							\
44062306a36Sopenharmony_ci	_FP_FRAC_SLL_4(X, 1);					\
44162306a36Sopenharmony_ci	q >>= 1;						\
44262306a36Sopenharmony_ci      }								\
44362306a36Sopenharmony_ci    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);			\
44462306a36Sopenharmony_ci    while (q)							\
44562306a36Sopenharmony_ci      {								\
44662306a36Sopenharmony_ci	T##_f[2] = S##_f[2] + q;				\
44762306a36Sopenharmony_ci	T##_f[3] = S##_f[3];					\
44862306a36Sopenharmony_ci	if (T##_f[3] < X##_f[3] || 				\
44962306a36Sopenharmony_ci	    (T##_f[3] == X##_f[3] && T##_f[2] <= X##_f[2]))	\
45062306a36Sopenharmony_ci	  {							\
45162306a36Sopenharmony_ci	    S##_f[2] = T##_f[2] + q;				\
45262306a36Sopenharmony_ci	    S##_f[3] += (T##_f[2] > S##_f[2]);			\
45362306a36Sopenharmony_ci	    __FP_FRAC_DEC_2(X##_f[3], X##_f[2],			\
45462306a36Sopenharmony_ci			    T##_f[3], T##_f[2]);		\
45562306a36Sopenharmony_ci	    R##_f[2] += q;					\
45662306a36Sopenharmony_ci	  }							\
45762306a36Sopenharmony_ci	_FP_FRAC_SLL_4(X, 1);					\
45862306a36Sopenharmony_ci	q >>= 1;						\
45962306a36Sopenharmony_ci      }								\
46062306a36Sopenharmony_ci    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);			\
46162306a36Sopenharmony_ci    while (q)							\
46262306a36Sopenharmony_ci      {								\
46362306a36Sopenharmony_ci	T##_f[1] = S##_f[1] + q;				\
46462306a36Sopenharmony_ci	T##_f[2] = S##_f[2];					\
46562306a36Sopenharmony_ci	T##_f[3] = S##_f[3];					\
46662306a36Sopenharmony_ci	if (T##_f[3] < X##_f[3] || 				\
46762306a36Sopenharmony_ci	    (T##_f[3] == X##_f[3] && (T##_f[2] < X##_f[2] ||	\
46862306a36Sopenharmony_ci	     (T##_f[2] == X##_f[2] && T##_f[1] <= X##_f[1]))))	\
46962306a36Sopenharmony_ci	  {							\
47062306a36Sopenharmony_ci	    S##_f[1] = T##_f[1] + q;				\
47162306a36Sopenharmony_ci	    S##_f[2] += (T##_f[1] > S##_f[1]);			\
47262306a36Sopenharmony_ci	    S##_f[3] += (T##_f[2] > S##_f[2]);			\
47362306a36Sopenharmony_ci	    __FP_FRAC_DEC_3(X##_f[3], X##_f[2], X##_f[1],	\
47462306a36Sopenharmony_ci	    		    T##_f[3], T##_f[2], T##_f[1]);	\
47562306a36Sopenharmony_ci	    R##_f[1] += q;					\
47662306a36Sopenharmony_ci	  }							\
47762306a36Sopenharmony_ci	_FP_FRAC_SLL_4(X, 1);					\
47862306a36Sopenharmony_ci	q >>= 1;						\
47962306a36Sopenharmony_ci      }								\
48062306a36Sopenharmony_ci    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);			\
48162306a36Sopenharmony_ci    while (q != _FP_WORK_ROUND)					\
48262306a36Sopenharmony_ci      {								\
48362306a36Sopenharmony_ci	T##_f[0] = S##_f[0] + q;				\
48462306a36Sopenharmony_ci	T##_f[1] = S##_f[1];					\
48562306a36Sopenharmony_ci	T##_f[2] = S##_f[2];					\
48662306a36Sopenharmony_ci	T##_f[3] = S##_f[3];					\
48762306a36Sopenharmony_ci	if (_FP_FRAC_GE_4(X,T))					\
48862306a36Sopenharmony_ci	  {							\
48962306a36Sopenharmony_ci	    S##_f[0] = T##_f[0] + q;				\
49062306a36Sopenharmony_ci	    S##_f[1] += (T##_f[0] > S##_f[0]);			\
49162306a36Sopenharmony_ci	    S##_f[2] += (T##_f[1] > S##_f[1]);			\
49262306a36Sopenharmony_ci	    S##_f[3] += (T##_f[2] > S##_f[2]);			\
49362306a36Sopenharmony_ci	    _FP_FRAC_DEC_4(X, T);				\
49462306a36Sopenharmony_ci	    R##_f[0] += q;					\
49562306a36Sopenharmony_ci	  }							\
49662306a36Sopenharmony_ci	_FP_FRAC_SLL_4(X, 1);					\
49762306a36Sopenharmony_ci	q >>= 1;						\
49862306a36Sopenharmony_ci      }								\
49962306a36Sopenharmony_ci    if (!_FP_FRAC_ZEROP_4(X))					\
50062306a36Sopenharmony_ci      {								\
50162306a36Sopenharmony_ci	if (_FP_FRAC_GT_4(X,S))					\
50262306a36Sopenharmony_ci	  R##_f[0] |= _FP_WORK_ROUND;				\
50362306a36Sopenharmony_ci	R##_f[0] |= _FP_WORK_STICKY;				\
50462306a36Sopenharmony_ci      }								\
50562306a36Sopenharmony_ci  } while (0)
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci/*
50962306a36Sopenharmony_ci * Internals
51062306a36Sopenharmony_ci */
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci#define __FP_FRAC_SET_4(X,I3,I2,I1,I0)					\
51362306a36Sopenharmony_ci  (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0)
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci#ifndef __FP_FRAC_ADD_3
51662306a36Sopenharmony_ci#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)		\
51762306a36Sopenharmony_ci  do {								\
51862306a36Sopenharmony_ci    int _c1, _c2;							\
51962306a36Sopenharmony_ci    r0 = x0 + y0;						\
52062306a36Sopenharmony_ci    _c1 = r0 < x0;						\
52162306a36Sopenharmony_ci    r1 = x1 + y1;						\
52262306a36Sopenharmony_ci    _c2 = r1 < x1;						\
52362306a36Sopenharmony_ci    r1 += _c1;							\
52462306a36Sopenharmony_ci    _c2 |= r1 < _c1;						\
52562306a36Sopenharmony_ci    r2 = x2 + y2 + _c2;						\
52662306a36Sopenharmony_ci  } while (0)
52762306a36Sopenharmony_ci#endif
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci#ifndef __FP_FRAC_ADD_4
53062306a36Sopenharmony_ci#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)	\
53162306a36Sopenharmony_ci  do {								\
53262306a36Sopenharmony_ci    int _c1, _c2, _c3;						\
53362306a36Sopenharmony_ci    r0 = x0 + y0;						\
53462306a36Sopenharmony_ci    _c1 = r0 < x0;						\
53562306a36Sopenharmony_ci    r1 = x1 + y1;						\
53662306a36Sopenharmony_ci    _c2 = r1 < x1;						\
53762306a36Sopenharmony_ci    r1 += _c1;							\
53862306a36Sopenharmony_ci    _c2 |= r1 < _c1;						\
53962306a36Sopenharmony_ci    r2 = x2 + y2;						\
54062306a36Sopenharmony_ci    _c3 = r2 < x2;						\
54162306a36Sopenharmony_ci    r2 += _c2;							\
54262306a36Sopenharmony_ci    _c3 |= r2 < _c2;						\
54362306a36Sopenharmony_ci    r3 = x3 + y3 + _c3;						\
54462306a36Sopenharmony_ci  } while (0)
54562306a36Sopenharmony_ci#endif
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci#ifndef __FP_FRAC_SUB_3
54862306a36Sopenharmony_ci#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)		\
54962306a36Sopenharmony_ci  do {								\
55062306a36Sopenharmony_ci    int _c1, _c2;							\
55162306a36Sopenharmony_ci    r0 = x0 - y0;						\
55262306a36Sopenharmony_ci    _c1 = r0 > x0;						\
55362306a36Sopenharmony_ci    r1 = x1 - y1;						\
55462306a36Sopenharmony_ci    _c2 = r1 > x1;						\
55562306a36Sopenharmony_ci    r1 -= _c1;							\
55662306a36Sopenharmony_ci    _c2 |= r1 > _c1;						\
55762306a36Sopenharmony_ci    r2 = x2 - y2 - _c2;						\
55862306a36Sopenharmony_ci  } while (0)
55962306a36Sopenharmony_ci#endif
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci#ifndef __FP_FRAC_SUB_4
56262306a36Sopenharmony_ci#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)	\
56362306a36Sopenharmony_ci  do {								\
56462306a36Sopenharmony_ci    int _c1, _c2, _c3;						\
56562306a36Sopenharmony_ci    r0 = x0 - y0;						\
56662306a36Sopenharmony_ci    _c1 = r0 > x0;						\
56762306a36Sopenharmony_ci    r1 = x1 - y1;						\
56862306a36Sopenharmony_ci    _c2 = r1 > x1;						\
56962306a36Sopenharmony_ci    r1 -= _c1;							\
57062306a36Sopenharmony_ci    _c2 |= r1 > _c1;						\
57162306a36Sopenharmony_ci    r2 = x2 - y2;						\
57262306a36Sopenharmony_ci    _c3 = r2 > x2;						\
57362306a36Sopenharmony_ci    r2 -= _c2;							\
57462306a36Sopenharmony_ci    _c3 |= r2 > _c2;						\
57562306a36Sopenharmony_ci    r3 = x3 - y3 - _c3;						\
57662306a36Sopenharmony_ci  } while (0)
57762306a36Sopenharmony_ci#endif
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci#ifndef __FP_FRAC_DEC_3
58062306a36Sopenharmony_ci#define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0)				\
58162306a36Sopenharmony_ci  do {									\
58262306a36Sopenharmony_ci    UWtype _t0, _t1, _t2;						\
58362306a36Sopenharmony_ci    _t0 = x0, _t1 = x1, _t2 = x2;					\
58462306a36Sopenharmony_ci    __FP_FRAC_SUB_3 (x2, x1, x0, _t2, _t1, _t0, y2, y1, y0);		\
58562306a36Sopenharmony_ci  } while (0)
58662306a36Sopenharmony_ci#endif
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci#ifndef __FP_FRAC_DEC_4
58962306a36Sopenharmony_ci#define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0)			\
59062306a36Sopenharmony_ci  do {									\
59162306a36Sopenharmony_ci    UWtype _t0, _t1, _t2, _t3;						\
59262306a36Sopenharmony_ci    _t0 = x0, _t1 = x1, _t2 = x2, _t3 = x3;				\
59362306a36Sopenharmony_ci    __FP_FRAC_SUB_4 (x3,x2,x1,x0,_t3,_t2,_t1,_t0, y3,y2,y1,y0);		\
59462306a36Sopenharmony_ci  } while (0)
59562306a36Sopenharmony_ci#endif
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci#ifndef __FP_FRAC_ADDI_4
59862306a36Sopenharmony_ci#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i)					\
59962306a36Sopenharmony_ci  do {									\
60062306a36Sopenharmony_ci    UWtype _t;								\
60162306a36Sopenharmony_ci    _t = ((x0 += i) < i);						\
60262306a36Sopenharmony_ci    x1 += _t; _t = (x1 < _t);						\
60362306a36Sopenharmony_ci    x2 += _t; _t = (x2 < _t);						\
60462306a36Sopenharmony_ci    x3 += _t;								\
60562306a36Sopenharmony_ci  } while (0)
60662306a36Sopenharmony_ci#endif
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci/* Convert FP values between word sizes. This appears to be more
60962306a36Sopenharmony_ci * complicated than I'd have expected it to be, so these might be
61062306a36Sopenharmony_ci * wrong... These macros are in any case somewhat bogus because they
61162306a36Sopenharmony_ci * use information about what various FRAC_n variables look like
61262306a36Sopenharmony_ci * internally [eg, that 2 word vars are X_f0 and x_f1]. But so do
61362306a36Sopenharmony_ci * the ones in op-2.h and op-1.h.
61462306a36Sopenharmony_ci */
61562306a36Sopenharmony_ci#define _FP_FRAC_CONV_1_4(dfs, sfs, D, S)				\
61662306a36Sopenharmony_ci   do {									\
61762306a36Sopenharmony_ci     if (S##_c != FP_CLS_NAN)						\
61862306a36Sopenharmony_ci       _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),	\
61962306a36Sopenharmony_ci			  _FP_WFRACBITS_##sfs);				\
62062306a36Sopenharmony_ci     else								\
62162306a36Sopenharmony_ci       _FP_FRAC_SRL_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs));	\
62262306a36Sopenharmony_ci     D##_f = S##_f[0];							\
62362306a36Sopenharmony_ci  } while (0)
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci#define _FP_FRAC_CONV_2_4(dfs, sfs, D, S)				\
62662306a36Sopenharmony_ci   do {									\
62762306a36Sopenharmony_ci     if (S##_c != FP_CLS_NAN)						\
62862306a36Sopenharmony_ci       _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),	\
62962306a36Sopenharmony_ci		      _FP_WFRACBITS_##sfs);				\
63062306a36Sopenharmony_ci     else								\
63162306a36Sopenharmony_ci       _FP_FRAC_SRL_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs));	\
63262306a36Sopenharmony_ci     D##_f0 = S##_f[0];							\
63362306a36Sopenharmony_ci     D##_f1 = S##_f[1];							\
63462306a36Sopenharmony_ci  } while (0)
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci/* Assembly/disassembly for converting to/from integral types.
63762306a36Sopenharmony_ci * No shifting or overflow handled here.
63862306a36Sopenharmony_ci */
63962306a36Sopenharmony_ci/* Put the FP value X into r, which is an integer of size rsize. */
64062306a36Sopenharmony_ci#define _FP_FRAC_ASSEMBLE_4(r, X, rsize)				\
64162306a36Sopenharmony_ci  do {									\
64262306a36Sopenharmony_ci    if (rsize <= _FP_W_TYPE_SIZE)					\
64362306a36Sopenharmony_ci      r = X##_f[0];							\
64462306a36Sopenharmony_ci    else if (rsize <= 2*_FP_W_TYPE_SIZE)				\
64562306a36Sopenharmony_ci    {									\
64662306a36Sopenharmony_ci      r = X##_f[1];							\
64762306a36Sopenharmony_ci      r <<= _FP_W_TYPE_SIZE;						\
64862306a36Sopenharmony_ci      r += X##_f[0];							\
64962306a36Sopenharmony_ci    }									\
65062306a36Sopenharmony_ci    else								\
65162306a36Sopenharmony_ci    {									\
65262306a36Sopenharmony_ci      /* I'm feeling lazy so we deal with int == 3words (implausible)*/	\
65362306a36Sopenharmony_ci      /* and int == 4words as a single case.			 */	\
65462306a36Sopenharmony_ci      r = X##_f[3];							\
65562306a36Sopenharmony_ci      r <<= _FP_W_TYPE_SIZE;						\
65662306a36Sopenharmony_ci      r += X##_f[2];							\
65762306a36Sopenharmony_ci      r <<= _FP_W_TYPE_SIZE;						\
65862306a36Sopenharmony_ci      r += X##_f[1];							\
65962306a36Sopenharmony_ci      r <<= _FP_W_TYPE_SIZE;						\
66062306a36Sopenharmony_ci      r += X##_f[0];							\
66162306a36Sopenharmony_ci    }									\
66262306a36Sopenharmony_ci  } while (0)
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci/* "No disassemble Number Five!" */
66562306a36Sopenharmony_ci/* move an integer of size rsize into X's fractional part. We rely on
66662306a36Sopenharmony_ci * the _f[] array consisting of words of size _FP_W_TYPE_SIZE to avoid
66762306a36Sopenharmony_ci * having to mask the values we store into it.
66862306a36Sopenharmony_ci */
66962306a36Sopenharmony_ci#define _FP_FRAC_DISASSEMBLE_4(X, r, rsize)				\
67062306a36Sopenharmony_ci  do {									\
67162306a36Sopenharmony_ci    X##_f[0] = r;							\
67262306a36Sopenharmony_ci    X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE);	\
67362306a36Sopenharmony_ci    X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \
67462306a36Sopenharmony_ci    X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \
67562306a36Sopenharmony_ci  } while (0)
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S)				\
67862306a36Sopenharmony_ci   do {									\
67962306a36Sopenharmony_ci     D##_f[0] = S##_f;							\
68062306a36Sopenharmony_ci     D##_f[1] = D##_f[2] = D##_f[3] = 0;				\
68162306a36Sopenharmony_ci     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));	\
68262306a36Sopenharmony_ci   } while (0)
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci#define _FP_FRAC_CONV_4_2(dfs, sfs, D, S)				\
68562306a36Sopenharmony_ci   do {									\
68662306a36Sopenharmony_ci     D##_f[0] = S##_f0;							\
68762306a36Sopenharmony_ci     D##_f[1] = S##_f1;							\
68862306a36Sopenharmony_ci     D##_f[2] = D##_f[3] = 0;						\
68962306a36Sopenharmony_ci     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));	\
69062306a36Sopenharmony_ci   } while (0)
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci#endif
693