documentation: convert the Documentation directory to UTF-8
[sfrench/cifs-2.6.git] / include / math-emu / op-common.h
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 truely 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)                                 \
37 do {                                                                    \
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);                              \
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)                           \
90 do {                                                            \
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             _FP_ROUND(wc, X);                                   \
143             if (_FP_FRAC_HIGH_##fs(X)                           \
144                 & (_FP_OVERFLOW_##fs >> 1))                     \
145               {                                                 \
146                 X##_e = 1;                                      \
147                 _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);        \
148               }                                                 \
149             else                                                \
150               {                                                 \
151                 X##_e = 0;                                      \
152                 _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);             \
153                 FP_SET_EXCEPTION(FP_EX_UNDERFLOW);              \
154               }                                                 \
155           }                                                     \
156         else                                                    \
157           {                                                     \
158             /* underflow to zero */                             \
159             X##_e = 0;                                          \
160             if (!_FP_FRAC_ZEROP_##wc(X))                        \
161               {                                                 \
162                 _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);         \
163                 _FP_ROUND(wc, X);                               \
164                 _FP_FRAC_LOW_##wc(X) >>= (_FP_WORKBITS);        \
165               }                                                 \
166             FP_SET_EXCEPTION(FP_EX_UNDERFLOW);                  \
167           }                                                     \
168       }                                                         \
169     break;                                                      \
170                                                                 \
171   case FP_CLS_ZERO:                                             \
172     X##_e = 0;                                                  \
173     _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                    \
174     break;                                                      \
175                                                                 \
176   case FP_CLS_INF:                                              \
177     X##_e = _FP_EXPMAX_##fs;                                    \
178     _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                    \
179     break;                                                      \
180                                                                 \
181   case FP_CLS_NAN:                                              \
182     X##_e = _FP_EXPMAX_##fs;                                    \
183     if (!_FP_KEEPNANFRACP)                                      \
184       {                                                         \
185         _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs);                 \
186         X##_s = _FP_NANSIGN_##fs;                               \
187       }                                                         \
188     else                                                        \
189       _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs;            \
190     break;                                                      \
191   }                                                             \
192 } while (0)
193
194 /* This one accepts raw argument and not cooked,  returns
195  * 1 if X is a signaling NaN.
196  */
197 #define _FP_ISSIGNAN(fs, wc, X)                                 \
198 ({                                                              \
199   int __ret = 0;                                                \
200   if (X##_e == _FP_EXPMAX_##fs)                                 \
201     {                                                           \
202       if (!_FP_FRAC_ZEROP_##wc(X)                               \
203           && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))   \
204         __ret = 1;                                              \
205     }                                                           \
206   __ret;                                                        \
207 })
208
209
210
211
212
213 /*
214  * Main addition routine.  The input values should be cooked.
215  */
216
217 #define _FP_ADD_INTERNAL(fs, wc, R, X, Y, OP)                                \
218 do {                                                                         \
219   switch (_FP_CLS_COMBINE(X##_c, Y##_c))                                     \
220   {                                                                          \
221   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):                         \
222     {                                                                        \
223       /* shift the smaller number so that its exponent matches the larger */ \
224       _FP_I_TYPE diff = X##_e - Y##_e;                                       \
225                                                                              \
226       if (diff < 0)                                                          \
227         {                                                                    \
228           diff = -diff;                                                      \
229           if (diff <= _FP_WFRACBITS_##fs)                                    \
230             _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs);                  \
231           else if (!_FP_FRAC_ZEROP_##wc(X))                                  \
232             _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);                          \
233           R##_e = Y##_e;                                                     \
234         }                                                                    \
235       else                                                                   \
236         {                                                                    \
237           if (diff > 0)                                                      \
238             {                                                                \
239               if (diff <= _FP_WFRACBITS_##fs)                                \
240                 _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs);              \
241               else if (!_FP_FRAC_ZEROP_##wc(Y))                              \
242                 _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc);                      \
243             }                                                                \
244           R##_e = X##_e;                                                     \
245         }                                                                    \
246                                                                              \
247       R##_c = FP_CLS_NORMAL;                                                 \
248                                                                              \
249       if (X##_s == Y##_s)                                                    \
250         {                                                                    \
251           R##_s = X##_s;                                                     \
252           _FP_FRAC_ADD_##wc(R, X, Y);                                        \
253           if (_FP_FRAC_OVERP_##wc(fs, R))                                    \
254             {                                                                \
255               _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);                   \
256               R##_e++;                                                       \
257             }                                                                \
258         }                                                                    \
259       else                                                                   \
260         {                                                                    \
261           R##_s = X##_s;                                                     \
262           _FP_FRAC_SUB_##wc(R, X, Y);                                        \
263           if (_FP_FRAC_ZEROP_##wc(R))                                        \
264             {                                                                \
265               /* return an exact zero */                                     \
266               if (FP_ROUNDMODE == FP_RND_MINF)                               \
267                 R##_s |= Y##_s;                                              \
268               else                                                           \
269                 R##_s &= Y##_s;                                              \
270               R##_c = FP_CLS_ZERO;                                           \
271             }                                                                \
272           else                                                               \
273             {                                                                \
274               if (_FP_FRAC_NEGP_##wc(R))                                     \
275                 {                                                            \
276                   _FP_FRAC_SUB_##wc(R, Y, X);                                \
277                   R##_s = Y##_s;                                             \
278                 }                                                            \
279                                                                              \
280               /* renormalize after subtraction */                            \
281               _FP_FRAC_CLZ_##wc(diff, R);                                    \
282               diff -= _FP_WFRACXBITS_##fs;                                   \
283               if (diff)                                                      \
284                 {                                                            \
285                   R##_e -= diff;                                             \
286                   _FP_FRAC_SLL_##wc(R, diff);                                \
287                 }                                                            \
288             }                                                                \
289         }                                                                    \
290       break;                                                                 \
291     }                                                                        \
292                                                                              \
293   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):                               \
294     _FP_CHOOSENAN(fs, wc, R, X, Y, OP);                                      \
295     break;                                                                   \
296                                                                              \
297   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):                           \
298     R##_e = X##_e;                                                           \
299   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):                            \
300   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):                               \
301   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):                              \
302     _FP_FRAC_COPY_##wc(R, X);                                                \
303     R##_s = X##_s;                                                           \
304     R##_c = X##_c;                                                           \
305     break;                                                                   \
306                                                                              \
307   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):                           \
308     R##_e = Y##_e;                                                           \
309   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):                            \
310   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):                               \
311   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):                              \
312     _FP_FRAC_COPY_##wc(R, Y);                                                \
313     R##_s = Y##_s;                                                           \
314     R##_c = Y##_c;                                                           \
315     break;                                                                   \
316                                                                              \
317   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):                               \
318     if (X##_s != Y##_s)                                                      \
319       {                                                                      \
320         /* +INF + -INF => NAN */                                             \
321         _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                              \
322         R##_s = _FP_NANSIGN_##fs;                                            \
323         R##_c = FP_CLS_NAN;                                                  \
324         FP_SET_EXCEPTION(FP_EX_INVALID);                                     \
325         break;                                                               \
326       }                                                                      \
327     /* FALLTHRU */                                                           \
328                                                                              \
329   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):                            \
330   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):                              \
331     R##_s = X##_s;                                                           \
332     R##_c = FP_CLS_INF;                                                      \
333     break;                                                                   \
334                                                                              \
335   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):                            \
336   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):                              \
337     R##_s = Y##_s;                                                           \
338     R##_c = FP_CLS_INF;                                                      \
339     break;                                                                   \
340                                                                              \
341   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):                             \
342     /* make sure the sign is correct */                                      \
343     if (FP_ROUNDMODE == FP_RND_MINF)                                         \
344       R##_s = X##_s | Y##_s;                                                 \
345     else                                                                     \
346       R##_s = X##_s & Y##_s;                                                 \
347     R##_c = FP_CLS_ZERO;                                                     \
348     break;                                                                   \
349                                                                              \
350   default:                                                                   \
351     abort();                                                                 \
352   }                                                                          \
353 } while (0)
354
355 #define _FP_ADD(fs, wc, R, X, Y) _FP_ADD_INTERNAL(fs, wc, R, X, Y, '+')
356 #define _FP_SUB(fs, wc, R, X, Y)                                             \
357   do {                                                                       \
358     if (Y##_c != FP_CLS_NAN) Y##_s ^= 1;                                     \
359     _FP_ADD_INTERNAL(fs, wc, R, X, Y, '-');                                  \
360   } while (0)
361
362
363 /*
364  * Main negation routine.  FIXME -- when we care about setting exception
365  * bits reliably, this will not do.  We should examine all of the fp classes.
366  */
367
368 #define _FP_NEG(fs, wc, R, X)           \
369   do {                                  \
370     _FP_FRAC_COPY_##wc(R, X);           \
371     R##_c = X##_c;                      \
372     R##_e = X##_e;                      \
373     R##_s = 1 ^ X##_s;                  \
374   } while (0)
375
376
377 /*
378  * Main multiplication routine.  The input values should be cooked.
379  */
380
381 #define _FP_MUL(fs, wc, R, X, Y)                        \
382 do {                                                    \
383   R##_s = X##_s ^ Y##_s;                                \
384   switch (_FP_CLS_COMBINE(X##_c, Y##_c))                \
385   {                                                     \
386   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):    \
387     R##_c = FP_CLS_NORMAL;                              \
388     R##_e = X##_e + Y##_e + 1;                          \
389                                                         \
390     _FP_MUL_MEAT_##fs(R,X,Y);                           \
391                                                         \
392     if (_FP_FRAC_OVERP_##wc(fs, R))                     \
393       _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);      \
394     else                                                \
395       R##_e--;                                          \
396     break;                                              \
397                                                         \
398   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):          \
399     _FP_CHOOSENAN(fs, wc, R, X, Y, '*');                \
400     break;                                              \
401                                                         \
402   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):       \
403   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):          \
404   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):         \
405     R##_s = X##_s;                                      \
406                                                         \
407   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):          \
408   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):       \
409   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):      \
410   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):        \
411     _FP_FRAC_COPY_##wc(R, X);                           \
412     R##_c = X##_c;                                      \
413     break;                                              \
414                                                         \
415   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):       \
416   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):          \
417   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):         \
418     R##_s = Y##_s;                                      \
419                                                         \
420   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):       \
421   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):      \
422     _FP_FRAC_COPY_##wc(R, Y);                           \
423     R##_c = Y##_c;                                      \
424     break;                                              \
425                                                         \
426   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):         \
427   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):         \
428     R##_s = _FP_NANSIGN_##fs;                           \
429     R##_c = FP_CLS_NAN;                                 \
430     _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);             \
431     FP_SET_EXCEPTION(FP_EX_INVALID);                    \
432     break;                                              \
433                                                         \
434   default:                                              \
435     abort();                                            \
436   }                                                     \
437 } while (0)
438
439
440 /*
441  * Main division routine.  The input values should be cooked.
442  */
443
444 #define _FP_DIV(fs, wc, R, X, Y)                        \
445 do {                                                    \
446   R##_s = X##_s ^ Y##_s;                                \
447   switch (_FP_CLS_COMBINE(X##_c, Y##_c))                \
448   {                                                     \
449   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):    \
450     R##_c = FP_CLS_NORMAL;                              \
451     R##_e = X##_e - Y##_e;                              \
452                                                         \
453     _FP_DIV_MEAT_##fs(R,X,Y);                           \
454     break;                                              \
455                                                         \
456   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):          \
457     _FP_CHOOSENAN(fs, wc, R, X, Y, '/');                \
458     break;                                              \
459                                                         \
460   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):       \
461   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):          \
462   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):         \
463     R##_s = X##_s;                                      \
464     _FP_FRAC_COPY_##wc(R, X);                           \
465     R##_c = X##_c;                                      \
466     break;                                              \
467                                                         \
468   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):       \
469   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):          \
470   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):         \
471     R##_s = Y##_s;                                      \
472     _FP_FRAC_COPY_##wc(R, Y);                           \
473     R##_c = Y##_c;                                      \
474     break;                                              \
475                                                         \
476   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):       \
477   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):         \
478   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):      \
479     R##_c = FP_CLS_ZERO;                                \
480     break;                                              \
481                                                         \
482   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):      \
483     FP_SET_EXCEPTION(FP_EX_DIVZERO);                    \
484   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):         \
485   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):       \
486     R##_c = FP_CLS_INF;                                 \
487     break;                                              \
488                                                         \
489   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):          \
490   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):        \
491     R##_s = _FP_NANSIGN_##fs;                           \
492     R##_c = FP_CLS_NAN;                                 \
493     _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);             \
494     FP_SET_EXCEPTION(FP_EX_INVALID);                    \
495     break;                                              \
496                                                         \
497   default:                                              \
498     abort();                                            \
499   }                                                     \
500 } while (0)
501
502
503 /*
504  * Main differential comparison routine.  The inputs should be raw not
505  * cooked.  The return is -1,0,1 for normal values, 2 otherwise.
506  */
507
508 #define _FP_CMP(fs, wc, ret, X, Y, un)                                  \
509   do {                                                                  \
510     /* NANs are unordered */                                            \
511     if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))           \
512         || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))       \
513       {                                                                 \
514         ret = un;                                                       \
515       }                                                                 \
516     else                                                                \
517       {                                                                 \
518         int __is_zero_x;                                                \
519         int __is_zero_y;                                                \
520                                                                         \
521         __is_zero_x = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0;       \
522         __is_zero_y = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0;       \
523                                                                         \
524         if (__is_zero_x && __is_zero_y)                                 \
525                 ret = 0;                                                \
526         else if (__is_zero_x)                                           \
527                 ret = Y##_s ? 1 : -1;                                   \
528         else if (__is_zero_y)                                           \
529                 ret = X##_s ? -1 : 1;                                   \
530         else if (X##_s != Y##_s)                                        \
531           ret = X##_s ? -1 : 1;                                         \
532         else if (X##_e > Y##_e)                                         \
533           ret = X##_s ? -1 : 1;                                         \
534         else if (X##_e < Y##_e)                                         \
535           ret = X##_s ? 1 : -1;                                         \
536         else if (_FP_FRAC_GT_##wc(X, Y))                                \
537           ret = X##_s ? -1 : 1;                                         \
538         else if (_FP_FRAC_GT_##wc(Y, X))                                \
539           ret = X##_s ? 1 : -1;                                         \
540         else                                                            \
541           ret = 0;                                                      \
542       }                                                                 \
543   } while (0)
544
545
546 /* Simplification for strict equality.  */
547
548 #define _FP_CMP_EQ(fs, wc, ret, X, Y)                                     \
549   do {                                                                    \
550     /* NANs are unordered */                                              \
551     if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))             \
552         || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))         \
553       {                                                                   \
554         ret = 1;                                                          \
555       }                                                                   \
556     else                                                                  \
557       {                                                                   \
558         ret = !(X##_e == Y##_e                                            \
559                 && _FP_FRAC_EQ_##wc(X, Y)                                 \
560                 && (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \
561       }                                                                   \
562   } while (0)
563
564 /*
565  * Main square root routine.  The input value should be cooked.
566  */
567
568 #define _FP_SQRT(fs, wc, R, X)                                          \
569 do {                                                                    \
570     _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S);                       \
571     _FP_W_TYPE q;                                                       \
572     switch (X##_c)                                                      \
573     {                                                                   \
574     case FP_CLS_NAN:                                                    \
575         _FP_FRAC_COPY_##wc(R, X);                                       \
576         R##_s = X##_s;                                                  \
577         R##_c = FP_CLS_NAN;                                             \
578         break;                                                          \
579     case FP_CLS_INF:                                                    \
580         if (X##_s)                                                      \
581           {                                                             \
582             R##_s = _FP_NANSIGN_##fs;                                   \
583             R##_c = FP_CLS_NAN; /* NAN */                               \
584             _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                     \
585             FP_SET_EXCEPTION(FP_EX_INVALID);                            \
586           }                                                             \
587         else                                                            \
588           {                                                             \
589             R##_s = 0;                                                  \
590             R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */                 \
591           }                                                             \
592         break;                                                          \
593     case FP_CLS_ZERO:                                                   \
594         R##_s = X##_s;                                                  \
595         R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */                      \
596         break;                                                          \
597     case FP_CLS_NORMAL:                                                 \
598         R##_s = 0;                                                      \
599         if (X##_s)                                                      \
600           {                                                             \
601             R##_c = FP_CLS_NAN; /* sNAN */                              \
602             R##_s = _FP_NANSIGN_##fs;                                   \
603             _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                     \
604             FP_SET_EXCEPTION(FP_EX_INVALID);                            \
605             break;                                                      \
606           }                                                             \
607         R##_c = FP_CLS_NORMAL;                                          \
608         if (X##_e & 1)                                                  \
609           _FP_FRAC_SLL_##wc(X, 1);                                      \
610         R##_e = X##_e >> 1;                                             \
611         _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc);                        \
612         _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc);                        \
613         q = _FP_OVERFLOW_##fs >> 1;                                     \
614         _FP_SQRT_MEAT_##wc(R, S, T, X, q);                              \
615     }                                                                   \
616   } while (0)
617
618 /*
619  * Convert from FP to integer
620  */
621
622 /* RSIGNED can have following values:
623  * 0:  the number is required to be 0..(2^rsize)-1, if not, NV is set plus
624  *     the result is either 0 or (2^rsize)-1 depending on the sign in such case.
625  * 1:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is
626  *     set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
627  *     on the sign in such case.
628  * 2:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is
629  *     set plus the result is truncated to fit into destination.
630  * -1: the number is required to be -(2^(rsize-1))..(2^rsize)-1, if not, NV is
631  *     set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
632  *     on the sign in such case.
633  */
634 #define _FP_TO_INT(fs, wc, r, X, rsize, rsigned)                                \
635   do {                                                                          \
636     switch (X##_c)                                                              \
637       {                                                                         \
638       case FP_CLS_NORMAL:                                                       \
639         if (X##_e < 0)                                                          \
640           {                                                                     \
641             FP_SET_EXCEPTION(FP_EX_INEXACT);                                    \
642           case FP_CLS_ZERO:                                                     \
643             r = 0;                                                              \
644           }                                                                     \
645         else if (X##_e >= rsize - (rsigned > 0 || X##_s)                        \
646                  || (!rsigned && X##_s))                                        \
647           {     /* overflow */                                                  \
648           case FP_CLS_NAN:                                                      \
649           case FP_CLS_INF:                                                      \
650             if (rsigned == 2)                                                   \
651               {                                                                 \
652                 if (X##_c != FP_CLS_NORMAL                                      \
653                     || X##_e >= rsize - 1 + _FP_WFRACBITS_##fs)                 \
654                   r = 0;                                                        \
655                 else                                                            \
656                   {                                                             \
657                     _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));     \
658                     _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                        \
659                   }                                                             \
660               }                                                                 \
661             else if (rsigned)                                                   \
662               {                                                                 \
663                 r = 1;                                                          \
664                 r <<= rsize - 1;                                                \
665                 r -= 1 - X##_s;                                                 \
666               }                                                                 \
667             else                                                                \
668               {                                                                 \
669                 r = 0;                                                          \
670                 if (X##_s)                                                      \
671                   r = ~r;                                                       \
672               }                                                                 \
673             FP_SET_EXCEPTION(FP_EX_INVALID);                                    \
674           }                                                                     \
675         else                                                                    \
676           {                                                                     \
677             if (_FP_W_TYPE_SIZE*wc < rsize)                                     \
678               {                                                                 \
679                 _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                            \
680                 r <<= X##_e - _FP_WFRACBITS_##fs;                               \
681               }                                                                 \
682             else                                                                \
683               {                                                                 \
684                 if (X##_e >= _FP_WFRACBITS_##fs)                                \
685                   _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));       \
686                 else if (X##_e < _FP_WFRACBITS_##fs - 1)                        \
687                   {                                                             \
688                     _FP_FRAC_SRS_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 2),      \
689                                       _FP_WFRACBITS_##fs);                      \
690                     if (_FP_FRAC_LOW_##wc(X) & 1)                               \
691                       FP_SET_EXCEPTION(FP_EX_INEXACT);                          \
692                     _FP_FRAC_SRL_##wc(X, 1);                                    \
693                   }                                                             \
694                 _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                            \
695               }                                                                 \
696             if (rsigned && X##_s)                                               \
697               r = -r;                                                           \
698           }                                                                     \
699         break;                                                                  \
700       }                                                                         \
701   } while (0)
702
703 #define _FP_TO_INT_ROUND(fs, wc, r, X, rsize, rsigned)                          \
704   do {                                                                          \
705     r = 0;                                                                      \
706     switch (X##_c)                                                              \
707       {                                                                         \
708       case FP_CLS_NORMAL:                                                       \
709         if (X##_e >= _FP_FRACBITS_##fs - 1)                                     \
710           {                                                                     \
711             if (X##_e < rsize - 1 + _FP_WFRACBITS_##fs)                         \
712               {                                                                 \
713                 if (X##_e >= _FP_WFRACBITS_##fs - 1)                            \
714                   {                                                             \
715                     _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                        \
716                     r <<= X##_e - _FP_WFRACBITS_##fs + 1;                       \
717                   }                                                             \
718                 else                                                            \
719                   {                                                             \
720                     _FP_FRAC_SRL_##wc(X, _FP_WORKBITS - X##_e                   \
721                                       + _FP_FRACBITS_##fs - 1);                 \
722                     _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                        \
723                   }                                                             \
724               }                                                                 \
725           }                                                                     \
726         else                                                                    \
727           {                                                                     \
728             if (X##_e <= -_FP_WORKBITS - 1)                                     \
729               _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);                           \
730             else                                                                \
731               _FP_FRAC_SRS_##wc(X, _FP_FRACBITS_##fs - 1 - X##_e,               \
732                                 _FP_WFRACBITS_##fs);                            \
733             _FP_ROUND(wc, X);                                                   \
734             _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);                                 \
735             _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                                \
736           }                                                                     \
737         if (rsigned && X##_s)                                                   \
738           r = -r;                                                               \
739         if (X##_e >= rsize - (rsigned > 0 || X##_s)                             \
740             || (!rsigned && X##_s))                                             \
741           {     /* overflow */                                                  \
742           case FP_CLS_NAN:                                                      \
743           case FP_CLS_INF:                                                      \
744             if (!rsigned)                                                       \
745               {                                                                 \
746                 r = 0;                                                          \
747                 if (X##_s)                                                      \
748                   r = ~r;                                                       \
749               }                                                                 \
750             else if (rsigned != 2)                                              \
751               {                                                                 \
752                 r = 1;                                                          \
753                 r <<= rsize - 1;                                                \
754                 r -= 1 - X##_s;                                                 \
755               }                                                                 \
756             FP_SET_EXCEPTION(FP_EX_INVALID);                                    \
757           }                                                                     \
758         break;                                                                  \
759       case FP_CLS_ZERO:                                                         \
760         break;                                                                  \
761       }                                                                         \
762   } while (0)
763
764 #define _FP_FROM_INT(fs, wc, X, r, rsize, rtype)                        \
765   do {                                                                  \
766     if (r)                                                              \
767       {                                                                 \
768         unsigned rtype ur_;                                             \
769         X##_c = FP_CLS_NORMAL;                                          \
770                                                                         \
771         if ((X##_s = (r < 0)))                                          \
772           ur_ = (unsigned rtype) -r;                                    \
773         else                                                            \
774           ur_ = (unsigned rtype) r;                                     \
775         if (rsize <= _FP_W_TYPE_SIZE)                                   \
776           __FP_CLZ(X##_e, ur_);                                         \
777         else                                                            \
778           __FP_CLZ_2(X##_e, (_FP_W_TYPE)(ur_ >> _FP_W_TYPE_SIZE),       \
779                      (_FP_W_TYPE)ur_);                                  \
780         if (rsize < _FP_W_TYPE_SIZE)                                    \
781                 X##_e -= (_FP_W_TYPE_SIZE - rsize);                     \
782         X##_e = rsize - X##_e - 1;                                      \
783                                                                         \
784         if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e)    \
785           __FP_FRAC_SRS_1(ur_, (X##_e - _FP_WFRACBITS_##fs + 1), rsize);\
786         _FP_FRAC_DISASSEMBLE_##wc(X, ur_, rsize);                       \
787         if ((_FP_WFRACBITS_##fs - X##_e - 1) > 0)                       \
788           _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));       \
789       }                                                                 \
790     else                                                                \
791       {                                                                 \
792         X##_c = FP_CLS_ZERO, X##_s = 0;                                 \
793       }                                                                 \
794   } while (0)
795
796
797 #define FP_CONV(dfs,sfs,dwc,swc,D,S)                    \
798   do {                                                  \
799     _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S);        \
800     D##_e = S##_e;                                      \
801     D##_c = S##_c;                                      \
802     D##_s = S##_s;                                      \
803   } while (0)
804
805 /*
806  * Helper primitives.
807  */
808
809 /* Count leading zeros in a word.  */
810
811 #ifndef __FP_CLZ
812 #if _FP_W_TYPE_SIZE < 64
813 /* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */
814 #define __FP_CLZ(r, x)                          \
815   do {                                          \
816     _FP_W_TYPE _t = (x);                        \
817     r = _FP_W_TYPE_SIZE - 1;                    \
818     if (_t > 0xffff) r -= 16;                   \
819     if (_t > 0xffff) _t >>= 16;                 \
820     if (_t > 0xff) r -= 8;                      \
821     if (_t > 0xff) _t >>= 8;                    \
822     if (_t & 0xf0) r -= 4;                      \
823     if (_t & 0xf0) _t >>= 4;                    \
824     if (_t & 0xc) r -= 2;                       \
825     if (_t & 0xc) _t >>= 2;                     \
826     if (_t & 0x2) r -= 1;                       \
827   } while (0)
828 #else /* not _FP_W_TYPE_SIZE < 64 */
829 #define __FP_CLZ(r, x)                          \
830   do {                                          \
831     _FP_W_TYPE _t = (x);                        \
832     r = _FP_W_TYPE_SIZE - 1;                    \
833     if (_t > 0xffffffff) r -= 32;               \
834     if (_t > 0xffffffff) _t >>= 32;             \
835     if (_t > 0xffff) r -= 16;                   \
836     if (_t > 0xffff) _t >>= 16;                 \
837     if (_t > 0xff) r -= 8;                      \
838     if (_t > 0xff) _t >>= 8;                    \
839     if (_t & 0xf0) r -= 4;                      \
840     if (_t & 0xf0) _t >>= 4;                    \
841     if (_t & 0xc) r -= 2;                       \
842     if (_t & 0xc) _t >>= 2;                     \
843     if (_t & 0x2) r -= 1;                       \
844   } while (0)
845 #endif /* not _FP_W_TYPE_SIZE < 64 */
846 #endif /* ndef __FP_CLZ */
847
848 #define _FP_DIV_HELP_imm(q, r, n, d)            \
849   do {                                          \
850     q = n / d, r = n % d;                       \
851   } while (0)
852
853 #endif /* __MATH_EMU_OP_COMMON_H__ */