Floating-point implementation in software.
[kopensolaris-gnu/glibc.git] / soft-fp / 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 #define _FP_DECL(wc, X)                 \
25   _FP_I_TYPE X##_c, X##_s, X##_e;       \
26   _FP_FRAC_DECL_##wc(X)
27
28 /*
29  * Finish truely unpacking a native fp value by classifying the kind
30  * of fp value and normalizing both the exponent and the fraction.
31  */
32
33 #define _FP_UNPACK_CANONICAL(fs, wc, X)                                 \
34 do {                                                                    \
35   switch (X##_e)                                                        \
36   {                                                                     \
37   default:                                                              \
38     _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_IMPLBIT_##fs;                      \
39     _FP_FRAC_SLL_##wc(X, _FP_WORKBITS);                                 \
40     X##_e -= _FP_EXPBIAS_##fs;                                          \
41     X##_c = FP_CLS_NORMAL;                                              \
42     break;                                                              \
43                                                                         \
44   case 0:                                                               \
45     if (_FP_FRAC_ZEROP_##wc(X))                                         \
46       X##_c = FP_CLS_ZERO;                                              \
47     else                                                                \
48       {                                                                 \
49         /* a denormalized number */                                     \
50         _FP_I_TYPE _shift;                                              \
51         _FP_FRAC_CLZ_##wc(_shift, X);                                   \
52         _shift -= _FP_FRACXBITS_##fs;                                   \
53         _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS));                    \
54         X##_e -= _FP_EXPBIAS_##fs - 1 + _shift;                         \
55         X##_c = FP_CLS_NORMAL;                                          \
56         FP_SET_EXCEPTION(FP_EX_DENORM);                                 \
57       }                                                                 \
58     break;                                                              \
59                                                                         \
60   case _FP_EXPMAX_##fs:                                                 \
61     if (_FP_FRAC_ZEROP_##wc(X))                                         \
62       X##_c = FP_CLS_INF;                                               \
63     else                                                                \
64       {                                                                 \
65         X##_c = FP_CLS_NAN;                                             \
66         /* Check for signaling NaN */                                   \
67         if (!(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))            \
68           FP_SET_EXCEPTION(FP_EX_INVALID);                              \
69       }                                                                 \
70     break;                                                              \
71   }                                                                     \
72 } while (0)
73
74 /*
75  * Before packing the bits back into the native fp result, take care
76  * of such mundane things as rounding and overflow.  Also, for some
77  * kinds of fp values, the original parts may not have been fully
78  * extracted -- but that is ok, we can regenerate them now.
79  */
80
81 #define _FP_PACK_CANONICAL(fs, wc, X)                           \
82 do {                                                            \
83   switch (X##_c)                                                \
84   {                                                             \
85   case FP_CLS_NORMAL:                                           \
86     X##_e += _FP_EXPBIAS_##fs;                                  \
87     if (X##_e > 0)                                              \
88       {                                                         \
89         _FP_ROUND(wc, X);                                       \
90         if (_FP_FRAC_OVERP_##wc(fs, X))                         \
91           {                                                     \
92             _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1));             \
93             X##_e++;                                            \
94           }                                                     \
95         else                                                    \
96           _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);                   \
97         if (X##_e >= _FP_EXPMAX_##fs)                           \
98           {                                                     \
99             /* overflow */                                      \
100             switch (FP_ROUNDMODE)                               \
101               {                                                 \
102               case FP_RND_NEAREST:                              \
103                 X##_c = FP_CLS_INF;                             \
104                 break;                                          \
105               case FP_RND_PINF:                                 \
106                 if (!X##_s) X##_c = FP_CLS_INF;                 \
107                 break;                                          \
108               case FP_RND_MINF:                                 \
109                 if (X##_s) X##_c = FP_CLS_INF;                  \
110                 break;                                          \
111               }                                                 \
112             if (X##_c == FP_CLS_INF)                            \
113               {                                                 \
114                 /* Overflow to infinity */                      \
115                 X##_e = _FP_EXPMAX_##fs;                        \
116                 _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);        \
117               }                                                 \
118             else                                                \
119               {                                                 \
120                 /* Overflow to maximum normal */                \
121                 X##_e = _FP_EXPMAX_##fs - 1;                    \
122                 _FP_FRAC_SET_##wc(X, _FP_MAXFRAC_##wc);         \
123               }                                                 \
124             FP_SET_EXCEPTION(FP_EX_OVERFLOW);                   \
125             FP_SET_EXCEPTION(FP_EX_INEXACT);                    \
126           }                                                     \
127       }                                                         \
128     else                                                        \
129       {                                                         \
130         /* we've got a denormalized number */                   \
131         X##_e = -X##_e + 1;                                     \
132         if (X##_e <= _FP_WFRACBITS_##fs)                        \
133           {                                                     \
134             _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs);    \
135             _FP_ROUND(wc, X);                                   \
136             if (_FP_FRAC_HIGH_##fs(X)                           \
137                 & (_FP_OVERFLOW_##fs >> 1))                     \
138               {                                                 \
139                 X##_e = 1;                                      \
140                 _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);        \
141               }                                                 \
142             else                                                \
143               {                                                 \
144                 X##_e = 0;                                      \
145                 _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);             \
146                 FP_SET_EXCEPTION(FP_EX_UNDERFLOW);              \
147               }                                                 \
148           }                                                     \
149         else                                                    \
150           {                                                     \
151             /* underflow to zero */                             \
152             X##_e = 0;                                          \
153             if (!_FP_FRAC_ZEROP_##wc(X))                        \
154               {                                                 \
155                 _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);         \
156                 _FP_ROUND(wc, X);                               \
157                 _FP_FRAC_LOW_##wc(X) >>= (_FP_WORKBITS);        \
158               }                                                 \
159             FP_SET_EXCEPTION(FP_EX_UNDERFLOW);                  \
160           }                                                     \
161       }                                                         \
162     break;                                                      \
163                                                                 \
164   case FP_CLS_ZERO:                                             \
165     X##_e = 0;                                                  \
166     _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                    \
167     break;                                                      \
168                                                                 \
169   case FP_CLS_INF:                                              \
170     X##_e = _FP_EXPMAX_##fs;                                    \
171     _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                    \
172     break;                                                      \
173                                                                 \
174   case FP_CLS_NAN:                                              \
175     X##_e = _FP_EXPMAX_##fs;                                    \
176     if (!_FP_KEEPNANFRACP)                                      \
177       {                                                         \
178         _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs);                 \
179         X##_s = _FP_NANSIGN_##fs;                               \
180       }                                                         \
181     else                                                        \
182       _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs;            \
183     break;                                                      \
184   }                                                             \
185 } while (0)
186
187 /* This one accepts raw argument and not cooked,  returns
188  * 1 if X is a signaling NaN.
189  */
190 #define _FP_ISSIGNAN(fs, wc, X)                                 \
191 ({                                                              \
192   int __ret = 0;                                                \
193   if (X##_e == _FP_EXPMAX_##fs)                                 \
194     {                                                           \
195       if (!_FP_FRAC_ZEROP_##wc(X)                               \
196           && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))   \
197         __ret = 1;                                              \
198     }                                                           \
199   __ret;                                                        \
200 })
201
202
203
204
205
206 /*
207  * Main addition routine.  The input values should be cooked.
208  */
209
210 #define _FP_ADD_INTERNAL(fs, wc, R, X, Y, OP)                                \
211 do {                                                                         \
212   switch (_FP_CLS_COMBINE(X##_c, Y##_c))                                     \
213   {                                                                          \
214   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):                         \
215     {                                                                        \
216       /* shift the smaller number so that its exponent matches the larger */ \
217       _FP_I_TYPE diff = X##_e - Y##_e;                                       \
218                                                                              \
219       if (diff < 0)                                                          \
220         {                                                                    \
221           diff = -diff;                                                      \
222           if (diff <= _FP_WFRACBITS_##fs)                                    \
223             _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs);                  \
224           else if (!_FP_FRAC_ZEROP_##wc(X))                                  \
225             _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);                          \
226           R##_e = Y##_e;                                                     \
227         }                                                                    \
228       else                                                                   \
229         {                                                                    \
230           if (diff > 0)                                                      \
231             {                                                                \
232               if (diff <= _FP_WFRACBITS_##fs)                                \
233                 _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs);              \
234               else if (!_FP_FRAC_ZEROP_##wc(Y))                              \
235                 _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc);                      \
236             }                                                                \
237           R##_e = X##_e;                                                     \
238         }                                                                    \
239                                                                              \
240       R##_c = FP_CLS_NORMAL;                                                 \
241                                                                              \
242       if (X##_s == Y##_s)                                                    \
243         {                                                                    \
244           R##_s = X##_s;                                                     \
245           _FP_FRAC_ADD_##wc(R, X, Y);                                        \
246           if (_FP_FRAC_OVERP_##wc(fs, R))                                    \
247             {                                                                \
248               _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);                   \
249               R##_e++;                                                       \
250             }                                                                \
251         }                                                                    \
252       else                                                                   \
253         {                                                                    \
254           R##_s = X##_s;                                                     \
255           _FP_FRAC_SUB_##wc(R, X, Y);                                        \
256           if (_FP_FRAC_ZEROP_##wc(R))                                        \
257             {                                                                \
258               /* return an exact zero */                                     \
259               if (FP_ROUNDMODE == FP_RND_MINF)                               \
260                 R##_s |= Y##_s;                                              \
261               else                                                           \
262                 R##_s &= Y##_s;                                              \
263               R##_c = FP_CLS_ZERO;                                           \
264             }                                                                \
265           else                                                               \
266             {                                                                \
267               if (_FP_FRAC_NEGP_##wc(R))                                     \
268                 {                                                            \
269                   _FP_FRAC_SUB_##wc(R, Y, X);                                \
270                   R##_s = Y##_s;                                             \
271                 }                                                            \
272                                                                              \
273               /* renormalize after subtraction */                            \
274               _FP_FRAC_CLZ_##wc(diff, R);                                    \
275               diff -= _FP_WFRACXBITS_##fs;                                   \
276               if (diff)                                                      \
277                 {                                                            \
278                   R##_e -= diff;                                             \
279                   _FP_FRAC_SLL_##wc(R, diff);                                \
280                 }                                                            \
281             }                                                                \
282         }                                                                    \
283       break;                                                                 \
284     }                                                                        \
285                                                                              \
286   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):                               \
287     _FP_CHOOSENAN(fs, wc, R, X, Y, OP);                                      \
288     break;                                                                   \
289                                                                              \
290   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):                           \
291     R##_e = X##_e;                                                           \
292   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):                            \
293   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):                               \
294   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):                              \
295     _FP_FRAC_COPY_##wc(R, X);                                                \
296     R##_s = X##_s;                                                           \
297     R##_c = X##_c;                                                           \
298     break;                                                                   \
299                                                                              \
300   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):                           \
301     R##_e = Y##_e;                                                           \
302   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):                            \
303   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):                               \
304   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):                              \
305     _FP_FRAC_COPY_##wc(R, Y);                                                \
306     R##_s = Y##_s;                                                           \
307     R##_c = Y##_c;                                                           \
308     break;                                                                   \
309                                                                              \
310   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):                               \
311     if (X##_s != Y##_s)                                                      \
312       {                                                                      \
313         /* +INF + -INF => NAN */                                             \
314         _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                              \
315         R##_s = _FP_NANSIGN_##fs;                                            \
316         R##_c = FP_CLS_NAN;                                                  \
317         FP_SET_EXCEPTION(FP_EX_INVALID);                                     \
318         break;                                                               \
319       }                                                                      \
320     /* FALLTHRU */                                                           \
321                                                                              \
322   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):                            \
323   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):                              \
324     R##_s = X##_s;                                                           \
325     R##_c = FP_CLS_INF;                                                      \
326     break;                                                                   \
327                                                                              \
328   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):                            \
329   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):                              \
330     R##_s = Y##_s;                                                           \
331     R##_c = FP_CLS_INF;                                                      \
332     break;                                                                   \
333                                                                              \
334   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):                             \
335     /* make sure the sign is correct */                                      \
336     if (FP_ROUNDMODE == FP_RND_MINF)                                         \
337       R##_s = X##_s | Y##_s;                                                 \
338     else                                                                     \
339       R##_s = X##_s & Y##_s;                                                 \
340     R##_c = FP_CLS_ZERO;                                                     \
341     break;                                                                   \
342                                                                              \
343   default:                                                                   \
344     abort();                                                                 \
345   }                                                                          \
346 } while (0)
347
348 #define _FP_ADD(fs, wc, R, X, Y) _FP_ADD_INTERNAL(fs, wc, R, X, Y, '+')
349 #define _FP_SUB(fs, wc, R, X, Y)                                             \
350   do {                                                                       \
351     if (Y##_c != FP_CLS_NAN) Y##_s ^= 1;                                     \
352     _FP_ADD_INTERNAL(fs, wc, R, X, Y, '-');                                  \
353   } while (0)
354
355
356 /*
357  * Main negation routine.  FIXME -- when we care about setting exception
358  * bits reliably, this will not do.  We should examine all of the fp classes.
359  */
360
361 #define _FP_NEG(fs, wc, R, X)           \
362   do {                                  \
363     _FP_FRAC_COPY_##wc(R, X);           \
364     R##_c = X##_c;                      \
365     R##_e = X##_e;                      \
366     R##_s = 1 ^ X##_s;                  \
367   } while (0)
368
369
370 /*
371  * Main multiplication routine.  The input values should be cooked.
372  */
373
374 #define _FP_MUL(fs, wc, R, X, Y)                        \
375 do {                                                    \
376   R##_s = X##_s ^ Y##_s;                                \
377   switch (_FP_CLS_COMBINE(X##_c, Y##_c))                \
378   {                                                     \
379   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):    \
380     R##_c = FP_CLS_NORMAL;                              \
381     R##_e = X##_e + Y##_e + 1;                          \
382                                                         \
383     _FP_MUL_MEAT_##fs(R,X,Y);                           \
384                                                         \
385     if (_FP_FRAC_OVERP_##wc(fs, R))                     \
386       _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs);      \
387     else                                                \
388       R##_e--;                                          \
389     break;                                              \
390                                                         \
391   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):          \
392     _FP_CHOOSENAN(fs, wc, R, X, Y, '*');                \
393     break;                                              \
394                                                         \
395   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):       \
396   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):          \
397   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):         \
398     R##_s = X##_s;                                      \
399                                                         \
400   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):          \
401   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):       \
402   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):      \
403   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):        \
404     _FP_FRAC_COPY_##wc(R, X);                           \
405     R##_c = X##_c;                                      \
406     break;                                              \
407                                                         \
408   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):       \
409   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):          \
410   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):         \
411     R##_s = Y##_s;                                      \
412                                                         \
413   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):       \
414   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):      \
415     _FP_FRAC_COPY_##wc(R, Y);                           \
416     R##_c = Y##_c;                                      \
417     break;                                              \
418                                                         \
419   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):         \
420   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):         \
421     R##_s = _FP_NANSIGN_##fs;                           \
422     R##_c = FP_CLS_NAN;                                 \
423     _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);             \
424     FP_SET_EXCEPTION(FP_EX_INVALID);                    \
425     break;                                              \
426                                                         \
427   default:                                              \
428     abort();                                            \
429   }                                                     \
430 } while (0)
431
432
433 /*
434  * Main division routine.  The input values should be cooked.
435  */
436
437 #define _FP_DIV(fs, wc, R, X, Y)                        \
438 do {                                                    \
439   R##_s = X##_s ^ Y##_s;                                \
440   switch (_FP_CLS_COMBINE(X##_c, Y##_c))                \
441   {                                                     \
442   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL):    \
443     R##_c = FP_CLS_NORMAL;                              \
444     R##_e = X##_e - Y##_e;                              \
445                                                         \
446     _FP_DIV_MEAT_##fs(R,X,Y);                           \
447     break;                                              \
448                                                         \
449   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN):          \
450     _FP_CHOOSENAN(fs, wc, R, X, Y, '/');                \
451     break;                                              \
452                                                         \
453   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL):       \
454   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF):          \
455   case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO):         \
456     R##_s = X##_s;                                      \
457     _FP_FRAC_COPY_##wc(R, X);                           \
458     R##_c = X##_c;                                      \
459     break;                                              \
460                                                         \
461   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN):       \
462   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN):          \
463   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN):         \
464     R##_s = Y##_s;                                      \
465     _FP_FRAC_COPY_##wc(R, Y);                           \
466     R##_c = Y##_c;                                      \
467     break;                                              \
468                                                         \
469   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF):       \
470   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):         \
471   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL):      \
472     R##_c = FP_CLS_ZERO;                                \
473     break;                                              \
474                                                         \
475   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):      \
476     FP_SET_EXCEPTION(FP_EX_DIVZERO);                    \
477   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):         \
478   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):       \
479     R##_c = FP_CLS_INF;                                 \
480     break;                                              \
481                                                         \
482   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):          \
483   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):        \
484     R##_s = _FP_NANSIGN_##fs;                           \
485     R##_c = FP_CLS_NAN;                                 \
486     _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);             \
487     FP_SET_EXCEPTION(FP_EX_INVALID);                    \
488     break;                                              \
489                                                         \
490   default:                                              \
491     abort();                                            \
492   }                                                     \
493 } while (0)
494
495
496 /*
497  * Main differential comparison routine.  The inputs should be raw not
498  * cooked.  The return is -1,0,1 for normal values, 2 otherwise.
499  */
500
501 #define _FP_CMP(fs, wc, ret, X, Y, un)                                  \
502   do {                                                                  \
503     /* NANs are unordered */                                            \
504     if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))           \
505         || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))       \
506       {                                                                 \
507         ret = un;                                                       \
508       }                                                                 \
509     else                                                                \
510       {                                                                 \
511         int __is_zero_x;                                                \
512         int __is_zero_y;                                                \
513                                                                         \
514         __is_zero_x = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0;       \
515         __is_zero_y = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0;       \
516                                                                         \
517         if (__is_zero_x && __is_zero_y)                                 \
518                 ret = 0;                                                \
519         else if (__is_zero_x)                                           \
520                 ret = Y##_s ? 1 : -1;                                   \
521         else if (__is_zero_y)                                           \
522                 ret = X##_s ? -1 : 1;                                   \
523         else if (X##_s != Y##_s)                                        \
524           ret = X##_s ? -1 : 1;                                         \
525         else if (X##_e > Y##_e)                                         \
526           ret = X##_s ? -1 : 1;                                         \
527         else if (X##_e < Y##_e)                                         \
528           ret = X##_s ? 1 : -1;                                         \
529         else if (_FP_FRAC_GT_##wc(X, Y))                                \
530           ret = X##_s ? -1 : 1;                                         \
531         else if (_FP_FRAC_GT_##wc(Y, X))                                \
532           ret = X##_s ? 1 : -1;                                         \
533         else                                                            \
534           ret = 0;                                                      \
535       }                                                                 \
536   } while (0)
537
538
539 /* Simplification for strict equality.  */
540
541 #define _FP_CMP_EQ(fs, wc, ret, X, Y)                                     \
542   do {                                                                    \
543     /* NANs are unordered */                                              \
544     if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X))             \
545         || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y)))         \
546       {                                                                   \
547         ret = 1;                                                          \
548       }                                                                   \
549     else                                                                  \
550       {                                                                   \
551         ret = !(X##_e == Y##_e                                            \
552                 && _FP_FRAC_EQ_##wc(X, Y)                                 \
553                 && (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \
554       }                                                                   \
555   } while (0)
556
557 /*
558  * Main square root routine.  The input value should be cooked.
559  */
560
561 #define _FP_SQRT(fs, wc, R, X)                                          \
562 do {                                                                    \
563     _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S);                       \
564     _FP_W_TYPE q;                                                       \
565     switch (X##_c)                                                      \
566     {                                                                   \
567     case FP_CLS_NAN:                                                    \
568         _FP_FRAC_COPY_##wc(R, X);                                       \
569         R##_s = X##_s;                                                  \
570         R##_c = FP_CLS_NAN;                                             \
571         break;                                                          \
572     case FP_CLS_INF:                                                    \
573         if (X##_s)                                                      \
574           {                                                             \
575             R##_s = _FP_NANSIGN_##fs;                                   \
576             R##_c = FP_CLS_NAN; /* NAN */                               \
577             _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                     \
578             FP_SET_EXCEPTION(FP_EX_INVALID);                            \
579           }                                                             \
580         else                                                            \
581           {                                                             \
582             R##_s = 0;                                                  \
583             R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */                 \
584           }                                                             \
585         break;                                                          \
586     case FP_CLS_ZERO:                                                   \
587         R##_s = X##_s;                                                  \
588         R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */                      \
589         break;                                                          \
590     case FP_CLS_NORMAL:                                                 \
591         R##_s = 0;                                                      \
592         if (X##_s)                                                      \
593           {                                                             \
594             R##_c = FP_CLS_NAN; /* sNAN */                              \
595             R##_s = _FP_NANSIGN_##fs;                                   \
596             _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                     \
597             FP_SET_EXCEPTION(FP_EX_INVALID);                            \
598             break;                                                      \
599           }                                                             \
600         R##_c = FP_CLS_NORMAL;                                          \
601         if (X##_e & 1)                                                  \
602           _FP_FRAC_SLL_##wc(X, 1);                                      \
603         R##_e = X##_e >> 1;                                             \
604         _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc);                        \
605         _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc);                        \
606         q = _FP_OVERFLOW_##fs >> 1;                                     \
607         _FP_SQRT_MEAT_##wc(R, S, T, X, q);                              \
608     }                                                                   \
609   } while (0)
610
611 /*
612  * Convert from FP to integer
613  */
614
615 /* RSIGNED can have following values:
616  * 0:  the number is required to be 0..(2^rsize)-1, if not, NV is set plus
617  *     the result is either 0 or (2^rsize)-1 depending on the sign in such case.
618  * 1:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is
619  *     set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
620  *     on the sign in such case.
621  * -1: the number is required to be -(2^(rsize-1))..(2^rsize)-1, if not, NV is
622  *     set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
623  *     on the sign in such case.
624  */
625 #define _FP_TO_INT(fs, wc, r, X, rsize, rsigned)                                \
626   do {                                                                          \
627     switch (X##_c)                                                              \
628       {                                                                         \
629       case FP_CLS_NORMAL:                                                       \
630         if (X##_e < 0)                                                          \
631           {                                                                     \
632             FP_SET_EXCEPTION(FP_EX_INEXACT);                                    \
633           case FP_CLS_ZERO:                                                     \
634             r = 0;                                                              \
635           }                                                                     \
636         else if (X##_e >= rsize - (rsigned > 0 || X##_s)                        \
637                  || (!rsigned && X##_s))                                        \
638           {     /* overflow */                                                  \
639           case FP_CLS_NAN:                                                      \
640           case FP_CLS_INF:                                                      \
641             if (rsigned)                                                        \
642               {                                                                 \
643                 r = 1;                                                          \
644                 r <<= rsize - 1;                                                \
645                 r -= 1 - X##_s;                                                 \
646               } else {                                                          \
647                 r = 0;                                                          \
648                 if (X##_s)                                                      \
649                   r = ~r;                                                       \
650               }                                                                 \
651             FP_SET_EXCEPTION(FP_EX_INVALID);                                    \
652           }                                                                     \
653         else                                                                    \
654           {                                                                     \
655             if (_FP_W_TYPE_SIZE*wc < rsize)                                     \
656               {                                                                 \
657                 _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                            \
658                 r <<= X##_e - _FP_WFRACBITS_##fs;                               \
659               }                                                                 \
660             else                                                                \
661               {                                                                 \
662                 if (X##_e >= _FP_WFRACBITS_##fs)                                \
663                   _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));       \
664                 else if (X##_e < _FP_WFRACBITS_##fs - 1)                        \
665                   {                                                             \
666                     _FP_FRAC_SRS_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 2),      \
667                                       _FP_WFRACBITS_##fs);                      \
668                     if (_FP_FRAC_LOW_##wc(X) & 1)                               \
669                       FP_SET_EXCEPTION(FP_EX_INEXACT);                          \
670                     _FP_FRAC_SRL_##wc(X, 1);                                    \
671                   }                                                             \
672                 _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                            \
673               }                                                                 \
674             if (rsigned && X##_s)                                               \
675               r = -r;                                                           \
676           }                                                                     \
677         break;                                                                  \
678       }                                                                         \
679   } while (0)
680
681 #define _FP_FROM_INT(fs, wc, X, r, rsize, rtype)                        \
682   do {                                                                  \
683     if (r)                                                              \
684       {                                                                 \
685         X##_c = FP_CLS_NORMAL;                                          \
686                                                                         \
687         if ((X##_s = (r < 0)))                                          \
688           r = -r;                                                       \
689                                                                         \
690         if (rsize <= _FP_W_TYPE_SIZE)                                   \
691           __FP_CLZ(X##_e, r);                                           \
692         else                                                            \
693           __FP_CLZ_2(X##_e, (_FP_W_TYPE)(r >> _FP_W_TYPE_SIZE),         \
694                      (_FP_W_TYPE)r);                                    \
695         if (rsize < _FP_W_TYPE_SIZE)                                    \
696                 X##_e -= (_FP_W_TYPE_SIZE - rsize);                     \
697         X##_e = rsize - X##_e - 1;                                      \
698                                                                         \
699         if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e)    \
700           __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize);      \
701         r &= ~((rtype)1 << X##_e);                                      \
702         _FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize);       \
703         _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));         \
704       }                                                                 \
705     else                                                                \
706       {                                                                 \
707         X##_c = FP_CLS_ZERO, X##_s = 0;                                 \
708       }                                                                 \
709   } while (0)
710
711
712 #define FP_CONV(dfs,sfs,dwc,swc,D,S)                    \
713   do {                                                  \
714     _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S);        \
715     D##_e = S##_e;                                      \
716     D##_c = S##_c;                                      \
717     D##_s = S##_s;                                      \
718   } while (0)
719
720 /*
721  * Helper primitives.
722  */
723
724 /* Count leading zeros in a word.  */
725
726 #ifndef __FP_CLZ
727 #if _FP_W_TYPE_SIZE < 64
728 /* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */
729 #define __FP_CLZ(r, x)                          \
730   do {                                          \
731     _FP_W_TYPE _t = (x);                        \
732     r = _FP_W_TYPE_SIZE - 1;                    \
733     if (_t > 0xffff) r -= 16;                   \
734     if (_t > 0xffff) _t >>= 16;                 \
735     if (_t > 0xff) r -= 8;                      \
736     if (_t > 0xff) _t >>= 8;                    \
737     if (_t & 0xf0) r -= 4;                      \
738     if (_t & 0xf0) _t >>= 4;                    \
739     if (_t & 0xc) r -= 2;                       \
740     if (_t & 0xc) _t >>= 2;                     \
741     if (_t & 0x2) r -= 1;                       \
742   } while (0)
743 #else /* not _FP_W_TYPE_SIZE < 64 */
744 #define __FP_CLZ(r, x)                          \
745   do {                                          \
746     _FP_W_TYPE _t = (x);                        \
747     r = _FP_W_TYPE_SIZE - 1;                    \
748     if (_t > 0xffffffff) r -= 32;               \
749     if (_t > 0xffffffff) _t >>= 32;             \
750     if (_t > 0xffff) r -= 16;                   \
751     if (_t > 0xffff) _t >>= 16;                 \
752     if (_t > 0xff) r -= 8;                      \
753     if (_t > 0xff) _t >>= 8;                    \
754     if (_t & 0xf0) r -= 4;                      \
755     if (_t & 0xf0) _t >>= 4;                    \
756     if (_t & 0xc) r -= 2;                       \
757     if (_t & 0xc) _t >>= 2;                     \
758     if (_t & 0x2) r -= 1;                       \
759   } while (0)
760 #endif /* not _FP_W_TYPE_SIZE < 64 */
761 #endif /* ndef __FP_CLZ */
762
763 #define _FP_DIV_HELP_imm(q, r, n, d)            \
764   do {                                          \
765     q = n / d, r = n % d;                       \
766   } while (0)
767