xref: /openbmc/qemu/target/m68k/softfloat.c (revision 7eceff5b5a1faa394929cacfd3520caa5b3edf42)
1 /*
2  * Ported from a work by Andreas Grabher for Previous, NeXT Computer Emulator,
3  * derived from NetBSD M68040 FPSP functions,
4  * derived from release 2a of the SoftFloat IEC/IEEE Floating-point Arithmetic
5  * Package. Those parts of the code (and some later contributions) are
6  * provided under that license, as detailed below.
7  * It has subsequently been modified by contributors to the QEMU Project,
8  * so some portions are provided under:
9  *  the SoftFloat-2a license
10  *  the BSD license
11  *  GPL-v2-or-later
12  *
13  * Any future contributions to this file will be taken to be licensed under
14  * the Softfloat-2a license unless specifically indicated otherwise.
15  */
16 
17 /* Portions of this work are licensed under the terms of the GNU GPL,
18  * version 2 or later. See the COPYING file in the top-level directory.
19  */
20 
21 #include "qemu/osdep.h"
22 #include "softfloat.h"
23 #include "fpu/softfloat-macros.h"
24 #include "softfloat_fpsp_tables.h"
25 
26 static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status)
27 {
28     if (floatx80_is_signaling_nan(a, status)) {
29         float_raise(float_flag_invalid, status);
30     }
31 
32     if (status->default_nan_mode) {
33         return floatx80_default_nan(status);
34     }
35 
36     return floatx80_maybe_silence_nan(a, status);
37 }
38 
39 /*----------------------------------------------------------------------------
40  | Returns the modulo remainder of the extended double-precision floating-point
41  | value `a' with respect to the corresponding value `b'.
42  *----------------------------------------------------------------------------*/
43 
44 floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status)
45 {
46     flag aSign, zSign;
47     int32_t aExp, bExp, expDiff;
48     uint64_t aSig0, aSig1, bSig;
49     uint64_t qTemp, term0, term1;
50 
51     aSig0 = extractFloatx80Frac(a);
52     aExp = extractFloatx80Exp(a);
53     aSign = extractFloatx80Sign(a);
54     bSig = extractFloatx80Frac(b);
55     bExp = extractFloatx80Exp(b);
56 
57     if (aExp == 0x7FFF) {
58         if ((uint64_t) (aSig0 << 1)
59             || ((bExp == 0x7FFF) && (uint64_t) (bSig << 1))) {
60             return propagateFloatx80NaN(a, b, status);
61         }
62         goto invalid;
63     }
64     if (bExp == 0x7FFF) {
65         if ((uint64_t) (bSig << 1)) {
66             return propagateFloatx80NaN(a, b, status);
67         }
68         return a;
69     }
70     if (bExp == 0) {
71         if (bSig == 0) {
72         invalid:
73             float_raise(float_flag_invalid, status);
74             return floatx80_default_nan(status);
75         }
76         normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
77     }
78     if (aExp == 0) {
79         if ((uint64_t) (aSig0 << 1) == 0) {
80             return a;
81         }
82         normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
83     }
84     bSig |= LIT64(0x8000000000000000);
85     zSign = aSign;
86     expDiff = aExp - bExp;
87     aSig1 = 0;
88     if (expDiff < 0) {
89         return a;
90     }
91     qTemp = (bSig <= aSig0);
92     if (qTemp) {
93         aSig0 -= bSig;
94     }
95     expDiff -= 64;
96     while (0 < expDiff) {
97         qTemp = estimateDiv128To64(aSig0, aSig1, bSig);
98         qTemp = (2 < qTemp) ? qTemp - 2 : 0;
99         mul64To128(bSig, qTemp, &term0, &term1);
100         sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1);
101         shortShift128Left(aSig0, aSig1, 62, &aSig0, &aSig1);
102     }
103     expDiff += 64;
104     if (0 < expDiff) {
105         qTemp = estimateDiv128To64(aSig0, aSig1, bSig);
106         qTemp = (2 < qTemp) ? qTemp - 2 : 0;
107         qTemp >>= 64 - expDiff;
108         mul64To128(bSig, qTemp << (64 - expDiff), &term0, &term1);
109         sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1);
110         shortShift128Left(0, bSig, 64 - expDiff, &term0, &term1);
111         while (le128(term0, term1, aSig0, aSig1)) {
112             ++qTemp;
113             sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1);
114         }
115     }
116     return
117         normalizeRoundAndPackFloatx80(
118             80, zSign, bExp + expDiff, aSig0, aSig1, status);
119 }
120 
121 /*----------------------------------------------------------------------------
122  | Returns the mantissa of the extended double-precision floating-point
123  | value `a'.
124  *----------------------------------------------------------------------------*/
125 
126 floatx80 floatx80_getman(floatx80 a, float_status *status)
127 {
128     flag aSign;
129     int32_t aExp;
130     uint64_t aSig;
131 
132     aSig = extractFloatx80Frac(a);
133     aExp = extractFloatx80Exp(a);
134     aSign = extractFloatx80Sign(a);
135 
136     if (aExp == 0x7FFF) {
137         if ((uint64_t) (aSig << 1)) {
138             return propagateFloatx80NaNOneArg(a , status);
139         }
140         float_raise(float_flag_invalid , status);
141         return floatx80_default_nan(status);
142     }
143 
144     if (aExp == 0) {
145         if (aSig == 0) {
146             return packFloatx80(aSign, 0, 0);
147         }
148         normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
149     }
150 
151     return roundAndPackFloatx80(status->floatx80_rounding_precision, aSign,
152                                 0x3FFF, aSig, 0, status);
153 }
154 
155 /*----------------------------------------------------------------------------
156  | Returns the exponent of the extended double-precision floating-point
157  | value `a' as an extended double-precision value.
158  *----------------------------------------------------------------------------*/
159 
160 floatx80 floatx80_getexp(floatx80 a, float_status *status)
161 {
162     flag aSign;
163     int32_t aExp;
164     uint64_t aSig;
165 
166     aSig = extractFloatx80Frac(a);
167     aExp = extractFloatx80Exp(a);
168     aSign = extractFloatx80Sign(a);
169 
170     if (aExp == 0x7FFF) {
171         if ((uint64_t) (aSig << 1)) {
172             return propagateFloatx80NaNOneArg(a , status);
173         }
174         float_raise(float_flag_invalid , status);
175         return floatx80_default_nan(status);
176     }
177 
178     if (aExp == 0) {
179         if (aSig == 0) {
180             return packFloatx80(aSign, 0, 0);
181         }
182         normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
183     }
184 
185     return int32_to_floatx80(aExp - 0x3FFF, status);
186 }
187 
188 /*----------------------------------------------------------------------------
189  | Scales extended double-precision floating-point value in operand `a' by
190  | value `b'. The function truncates the value in the second operand 'b' to
191  | an integral value and adds that value to the exponent of the operand 'a'.
192  | The operation performed according to the IEC/IEEE Standard for Binary
193  | Floating-Point Arithmetic.
194  *----------------------------------------------------------------------------*/
195 
196 floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status)
197 {
198     flag aSign, bSign;
199     int32_t aExp, bExp, shiftCount;
200     uint64_t aSig, bSig;
201 
202     aSig = extractFloatx80Frac(a);
203     aExp = extractFloatx80Exp(a);
204     aSign = extractFloatx80Sign(a);
205     bSig = extractFloatx80Frac(b);
206     bExp = extractFloatx80Exp(b);
207     bSign = extractFloatx80Sign(b);
208 
209     if (bExp == 0x7FFF) {
210         if ((uint64_t) (bSig << 1) ||
211             ((aExp == 0x7FFF) && (uint64_t) (aSig << 1))) {
212             return propagateFloatx80NaN(a, b, status);
213         }
214         float_raise(float_flag_invalid , status);
215         return floatx80_default_nan(status);
216     }
217     if (aExp == 0x7FFF) {
218         if ((uint64_t) (aSig << 1)) {
219             return propagateFloatx80NaN(a, b, status);
220         }
221         return packFloatx80(aSign, floatx80_infinity.high,
222                             floatx80_infinity.low);
223     }
224     if (aExp == 0) {
225         if (aSig == 0) {
226             return packFloatx80(aSign, 0, 0);
227         }
228         if (bExp < 0x3FFF) {
229             return a;
230         }
231         normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
232     }
233 
234     if (bExp < 0x3FFF) {
235         return a;
236     }
237 
238     if (0x400F < bExp) {
239         aExp = bSign ? -0x6001 : 0xE000;
240         return roundAndPackFloatx80(status->floatx80_rounding_precision,
241                                     aSign, aExp, aSig, 0, status);
242     }
243 
244     shiftCount = 0x403E - bExp;
245     bSig >>= shiftCount;
246     aExp = bSign ? (aExp - bSig) : (aExp + bSig);
247 
248     return roundAndPackFloatx80(status->floatx80_rounding_precision,
249                                 aSign, aExp, aSig, 0, status);
250 }
251 
252 floatx80 floatx80_move(floatx80 a, float_status *status)
253 {
254     flag aSign;
255     int32_t aExp;
256     uint64_t aSig;
257 
258     aSig = extractFloatx80Frac(a);
259     aExp = extractFloatx80Exp(a);
260     aSign = extractFloatx80Sign(a);
261 
262     if (aExp == 0x7FFF) {
263         if ((uint64_t)(aSig << 1)) {
264             return propagateFloatx80NaNOneArg(a, status);
265         }
266         return a;
267     }
268     if (aExp == 0) {
269         if (aSig == 0) {
270             return a;
271         }
272         normalizeRoundAndPackFloatx80(status->floatx80_rounding_precision,
273                                       aSign, aExp, aSig, 0, status);
274     }
275     return roundAndPackFloatx80(status->floatx80_rounding_precision, aSign,
276                                 aExp, aSig, 0, status);
277 }
278 
279 /*----------------------------------------------------------------------------
280 | Algorithms for transcendental functions supported by MC68881 and MC68882
281 | mathematical coprocessors. The functions are derived from FPSP library.
282 *----------------------------------------------------------------------------*/
283 
284 #define one_exp     0x3FFF
285 #define one_sig     LIT64(0x8000000000000000)
286 
287 /*----------------------------------------------------------------------------
288  | Function for compactifying extended double-precision floating point values.
289  *----------------------------------------------------------------------------*/
290 
291 static int32_t floatx80_make_compact(int32_t aExp, uint64_t aSig)
292 {
293     return (aExp << 16) | (aSig >> 48);
294 }
295 
296 /*----------------------------------------------------------------------------
297  | Log base e of x plus 1
298  *----------------------------------------------------------------------------*/
299 
300 floatx80 floatx80_lognp1(floatx80 a, float_status *status)
301 {
302     flag aSign;
303     int32_t aExp;
304     uint64_t aSig, fSig;
305 
306     int8_t user_rnd_mode, user_rnd_prec;
307 
308     int32_t compact, j, k;
309     floatx80 fp0, fp1, fp2, fp3, f, logof2, klog2, saveu;
310 
311     aSig = extractFloatx80Frac(a);
312     aExp = extractFloatx80Exp(a);
313     aSign = extractFloatx80Sign(a);
314 
315     if (aExp == 0x7FFF) {
316         if ((uint64_t) (aSig << 1)) {
317             propagateFloatx80NaNOneArg(a, status);
318         }
319         if (aSign) {
320             float_raise(float_flag_invalid, status);
321             return floatx80_default_nan(status);
322         }
323         return packFloatx80(0, floatx80_infinity.high, floatx80_infinity.low);
324     }
325 
326     if (aExp == 0 && aSig == 0) {
327         return packFloatx80(aSign, 0, 0);
328     }
329 
330     if (aSign && aExp >= one_exp) {
331         if (aExp == one_exp && aSig == one_sig) {
332             float_raise(float_flag_divbyzero, status);
333             packFloatx80(aSign, floatx80_infinity.high, floatx80_infinity.low);
334         }
335         float_raise(float_flag_invalid, status);
336         return floatx80_default_nan(status);
337     }
338 
339     if (aExp < 0x3f99 || (aExp == 0x3f99 && aSig == one_sig)) {
340         /* <= min threshold */
341         float_raise(float_flag_inexact, status);
342         return floatx80_move(a, status);
343     }
344 
345     user_rnd_mode = status->float_rounding_mode;
346     user_rnd_prec = status->floatx80_rounding_precision;
347     status->float_rounding_mode = float_round_nearest_even;
348     status->floatx80_rounding_precision = 80;
349 
350     compact = floatx80_make_compact(aExp, aSig);
351 
352     fp0 = a; /* Z */
353     fp1 = a;
354 
355     fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
356                        status), status); /* X = (1+Z) */
357 
358     aExp = extractFloatx80Exp(fp0);
359     aSig = extractFloatx80Frac(fp0);
360 
361     compact = floatx80_make_compact(aExp, aSig);
362 
363     if (compact < 0x3FFE8000 || compact > 0x3FFFC000) {
364         /* |X| < 1/2 or |X| > 3/2 */
365         k = aExp - 0x3FFF;
366         fp1 = int32_to_floatx80(k, status);
367 
368         fSig = (aSig & LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
369         j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
370 
371         f = packFloatx80(0, 0x3FFF, fSig); /* F */
372         fp0 = packFloatx80(0, 0x3FFF, aSig); /* Y */
373 
374         fp0 = floatx80_sub(fp0, f, status); /* Y-F */
375 
376     lp1cont1:
377         /* LP1CONT1 */
378         fp0 = floatx80_mul(fp0, log_tbl[j], status); /* FP0 IS U = (Y-F)/F */
379         logof2 = packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC));
380         klog2 = floatx80_mul(fp1, logof2, status); /* FP1 IS K*LOG2 */
381         fp2 = floatx80_mul(fp0, fp0, status); /* FP2 IS V=U*U */
382 
383         fp3 = fp2;
384         fp1 = fp2;
385 
386         fp1 = floatx80_mul(fp1, float64_to_floatx80(
387                            make_float64(0x3FC2499AB5E4040B), status),
388                            status); /* V*A6 */
389         fp2 = floatx80_mul(fp2, float64_to_floatx80(
390                            make_float64(0xBFC555B5848CB7DB), status),
391                            status); /* V*A5 */
392         fp1 = floatx80_add(fp1, float64_to_floatx80(
393                            make_float64(0x3FC99999987D8730), status),
394                            status); /* A4+V*A6 */
395         fp2 = floatx80_add(fp2, float64_to_floatx80(
396                            make_float64(0xBFCFFFFFFF6F7E97), status),
397                            status); /* A3+V*A5 */
398         fp1 = floatx80_mul(fp1, fp3, status); /* V*(A4+V*A6) */
399         fp2 = floatx80_mul(fp2, fp3, status); /* V*(A3+V*A5) */
400         fp1 = floatx80_add(fp1, float64_to_floatx80(
401                            make_float64(0x3FD55555555555A4), status),
402                            status); /* A2+V*(A4+V*A6) */
403         fp2 = floatx80_add(fp2, float64_to_floatx80(
404                            make_float64(0xBFE0000000000008), status),
405                            status); /* A1+V*(A3+V*A5) */
406         fp1 = floatx80_mul(fp1, fp3, status); /* V*(A2+V*(A4+V*A6)) */
407         fp2 = floatx80_mul(fp2, fp3, status); /* V*(A1+V*(A3+V*A5)) */
408         fp1 = floatx80_mul(fp1, fp0, status); /* U*V*(A2+V*(A4+V*A6)) */
409         fp0 = floatx80_add(fp0, fp2, status); /* U+V*(A1+V*(A3+V*A5)) */
410 
411         fp1 = floatx80_add(fp1, log_tbl[j + 1],
412                            status); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
413         fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */
414 
415         status->float_rounding_mode = user_rnd_mode;
416         status->floatx80_rounding_precision = user_rnd_prec;
417 
418         a = floatx80_add(fp0, klog2, status);
419 
420         float_raise(float_flag_inexact, status);
421 
422         return a;
423     } else if (compact < 0x3FFEF07D || compact > 0x3FFF8841) {
424         /* |X| < 1/16 or |X| > -1/16 */
425         /* LP1CARE */
426         fSig = (aSig & LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
427         f = packFloatx80(0, 0x3FFF, fSig); /* F */
428         j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
429 
430         if (compact >= 0x3FFF8000) { /* 1+Z >= 1 */
431             /* KISZERO */
432             fp0 = floatx80_sub(float32_to_floatx80(make_float32(0x3F800000),
433                                status), f, status); /* 1-F */
434             fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS Y-F = (1-F)+Z */
435             fp1 = packFloatx80(0, 0, 0); /* K = 0 */
436         } else {
437             /* KISNEG */
438             fp0 = floatx80_sub(float32_to_floatx80(make_float32(0x40000000),
439                                status), f, status); /* 2-F */
440             fp1 = floatx80_add(fp1, fp1, status); /* 2Z */
441             fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS Y-F = (2-F)+2Z */
442             fp1 = packFloatx80(1, one_exp, one_sig); /* K = -1 */
443         }
444         goto lp1cont1;
445     } else {
446         /* LP1ONE16 */
447         fp1 = floatx80_add(fp1, fp1, status); /* FP1 IS 2Z */
448         fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
449                            status), status); /* FP0 IS 1+X */
450 
451         /* LP1CONT2 */
452         fp1 = floatx80_div(fp1, fp0, status); /* U */
453         saveu = fp1;
454         fp0 = floatx80_mul(fp1, fp1, status); /* FP0 IS V = U*U */
455         fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS W = V*V */
456 
457         fp3 = float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
458                                   status); /* B5 */
459         fp2 = float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
460                                   status); /* B4 */
461         fp3 = floatx80_mul(fp3, fp1, status); /* W*B5 */
462         fp2 = floatx80_mul(fp2, fp1, status); /* W*B4 */
463         fp3 = floatx80_add(fp3, float64_to_floatx80(
464                            make_float64(0x3F624924928BCCFF), status),
465                            status); /* B3+W*B5 */
466         fp2 = floatx80_add(fp2, float64_to_floatx80(
467                            make_float64(0x3F899999999995EC), status),
468                            status); /* B2+W*B4 */
469         fp1 = floatx80_mul(fp1, fp3, status); /* W*(B3+W*B5) */
470         fp2 = floatx80_mul(fp2, fp0, status); /* V*(B2+W*B4) */
471         fp1 = floatx80_add(fp1, float64_to_floatx80(
472                            make_float64(0x3FB5555555555555), status),
473                            status); /* B1+W*(B3+W*B5) */
474 
475         fp0 = floatx80_mul(fp0, saveu, status); /* FP0 IS U*V */
476         fp1 = floatx80_add(fp1, fp2,
477                            status); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
478         fp0 = floatx80_mul(fp0, fp1,
479                            status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
480 
481         status->float_rounding_mode = user_rnd_mode;
482         status->floatx80_rounding_precision = user_rnd_prec;
483 
484         a = floatx80_add(fp0, saveu, status);
485 
486         /*if (!floatx80_is_zero(a)) { */
487             float_raise(float_flag_inexact, status);
488         /*} */
489 
490         return a;
491     }
492 }
493 
494 /*----------------------------------------------------------------------------
495  | Log base e
496  *----------------------------------------------------------------------------*/
497 
498 floatx80 floatx80_logn(floatx80 a, float_status *status)
499 {
500     flag aSign;
501     int32_t aExp;
502     uint64_t aSig, fSig;
503 
504     int8_t user_rnd_mode, user_rnd_prec;
505 
506     int32_t compact, j, k, adjk;
507     floatx80 fp0, fp1, fp2, fp3, f, logof2, klog2, saveu;
508 
509     aSig = extractFloatx80Frac(a);
510     aExp = extractFloatx80Exp(a);
511     aSign = extractFloatx80Sign(a);
512 
513     if (aExp == 0x7FFF) {
514         if ((uint64_t) (aSig << 1)) {
515             propagateFloatx80NaNOneArg(a, status);
516         }
517         if (aSign == 0) {
518             return packFloatx80(0, floatx80_infinity.high,
519                                 floatx80_infinity.low);
520         }
521     }
522 
523     adjk = 0;
524 
525     if (aExp == 0) {
526         if (aSig == 0) { /* zero */
527             float_raise(float_flag_divbyzero, status);
528             return packFloatx80(1, floatx80_infinity.high,
529                                 floatx80_infinity.low);
530         }
531         if ((aSig & one_sig) == 0) { /* denormal */
532             normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
533             adjk = -100;
534             aExp += 100;
535             a = packFloatx80(aSign, aExp, aSig);
536         }
537     }
538 
539     if (aSign) {
540         float_raise(float_flag_invalid, status);
541         return floatx80_default_nan(status);
542     }
543 
544     user_rnd_mode = status->float_rounding_mode;
545     user_rnd_prec = status->floatx80_rounding_precision;
546     status->float_rounding_mode = float_round_nearest_even;
547     status->floatx80_rounding_precision = 80;
548 
549     compact = floatx80_make_compact(aExp, aSig);
550 
551     if (compact < 0x3FFEF07D || compact > 0x3FFF8841) {
552         /* |X| < 15/16 or |X| > 17/16 */
553         k = aExp - 0x3FFF;
554         k += adjk;
555         fp1 = int32_to_floatx80(k, status);
556 
557         fSig = (aSig & LIT64(0xFE00000000000000)) | LIT64(0x0100000000000000);
558         j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
559 
560         f = packFloatx80(0, 0x3FFF, fSig); /* F */
561         fp0 = packFloatx80(0, 0x3FFF, aSig); /* Y */
562 
563         fp0 = floatx80_sub(fp0, f, status); /* Y-F */
564 
565         /* LP1CONT1 */
566         fp0 = floatx80_mul(fp0, log_tbl[j], status); /* FP0 IS U = (Y-F)/F */
567         logof2 = packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC));
568         klog2 = floatx80_mul(fp1, logof2, status); /* FP1 IS K*LOG2 */
569         fp2 = floatx80_mul(fp0, fp0, status); /* FP2 IS V=U*U */
570 
571         fp3 = fp2;
572         fp1 = fp2;
573 
574         fp1 = floatx80_mul(fp1, float64_to_floatx80(
575                            make_float64(0x3FC2499AB5E4040B), status),
576                            status); /* V*A6 */
577         fp2 = floatx80_mul(fp2, float64_to_floatx80(
578                            make_float64(0xBFC555B5848CB7DB), status),
579                            status); /* V*A5 */
580         fp1 = floatx80_add(fp1, float64_to_floatx80(
581                            make_float64(0x3FC99999987D8730), status),
582                            status); /* A4+V*A6 */
583         fp2 = floatx80_add(fp2, float64_to_floatx80(
584                            make_float64(0xBFCFFFFFFF6F7E97), status),
585                            status); /* A3+V*A5 */
586         fp1 = floatx80_mul(fp1, fp3, status); /* V*(A4+V*A6) */
587         fp2 = floatx80_mul(fp2, fp3, status); /* V*(A3+V*A5) */
588         fp1 = floatx80_add(fp1, float64_to_floatx80(
589                            make_float64(0x3FD55555555555A4), status),
590                            status); /* A2+V*(A4+V*A6) */
591         fp2 = floatx80_add(fp2, float64_to_floatx80(
592                            make_float64(0xBFE0000000000008), status),
593                            status); /* A1+V*(A3+V*A5) */
594         fp1 = floatx80_mul(fp1, fp3, status); /* V*(A2+V*(A4+V*A6)) */
595         fp2 = floatx80_mul(fp2, fp3, status); /* V*(A1+V*(A3+V*A5)) */
596         fp1 = floatx80_mul(fp1, fp0, status); /* U*V*(A2+V*(A4+V*A6)) */
597         fp0 = floatx80_add(fp0, fp2, status); /* U+V*(A1+V*(A3+V*A5)) */
598 
599         fp1 = floatx80_add(fp1, log_tbl[j + 1],
600                            status); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
601         fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */
602 
603         status->float_rounding_mode = user_rnd_mode;
604         status->floatx80_rounding_precision = user_rnd_prec;
605 
606         a = floatx80_add(fp0, klog2, status);
607 
608         float_raise(float_flag_inexact, status);
609 
610         return a;
611     } else { /* |X-1| >= 1/16 */
612         fp0 = a;
613         fp1 = a;
614         fp1 = floatx80_sub(fp1, float32_to_floatx80(make_float32(0x3F800000),
615                            status), status); /* FP1 IS X-1 */
616         fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
617                            status), status); /* FP0 IS X+1 */
618         fp1 = floatx80_add(fp1, fp1, status); /* FP1 IS 2(X-1) */
619 
620         /* LP1CONT2 */
621         fp1 = floatx80_div(fp1, fp0, status); /* U */
622         saveu = fp1;
623         fp0 = floatx80_mul(fp1, fp1, status); /* FP0 IS V = U*U */
624         fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS W = V*V */
625 
626         fp3 = float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
627                                   status); /* B5 */
628         fp2 = float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
629                                   status); /* B4 */
630         fp3 = floatx80_mul(fp3, fp1, status); /* W*B5 */
631         fp2 = floatx80_mul(fp2, fp1, status); /* W*B4 */
632         fp3 = floatx80_add(fp3, float64_to_floatx80(
633                            make_float64(0x3F624924928BCCFF), status),
634                            status); /* B3+W*B5 */
635         fp2 = floatx80_add(fp2, float64_to_floatx80(
636                            make_float64(0x3F899999999995EC), status),
637                            status); /* B2+W*B4 */
638         fp1 = floatx80_mul(fp1, fp3, status); /* W*(B3+W*B5) */
639         fp2 = floatx80_mul(fp2, fp0, status); /* V*(B2+W*B4) */
640         fp1 = floatx80_add(fp1, float64_to_floatx80(
641                            make_float64(0x3FB5555555555555), status),
642                            status); /* B1+W*(B3+W*B5) */
643 
644         fp0 = floatx80_mul(fp0, saveu, status); /* FP0 IS U*V */
645         fp1 = floatx80_add(fp1, fp2, status); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
646         fp0 = floatx80_mul(fp0, fp1,
647                            status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
648 
649         status->float_rounding_mode = user_rnd_mode;
650         status->floatx80_rounding_precision = user_rnd_prec;
651 
652         a = floatx80_add(fp0, saveu, status);
653 
654         /*if (!floatx80_is_zero(a)) { */
655             float_raise(float_flag_inexact, status);
656         /*} */
657 
658         return a;
659     }
660 }
661 
662 /*----------------------------------------------------------------------------
663  | Log base 10
664  *----------------------------------------------------------------------------*/
665 
666 floatx80 floatx80_log10(floatx80 a, float_status *status)
667 {
668     flag aSign;
669     int32_t aExp;
670     uint64_t aSig;
671 
672     int8_t user_rnd_mode, user_rnd_prec;
673 
674     floatx80 fp0, fp1;
675 
676     aSig = extractFloatx80Frac(a);
677     aExp = extractFloatx80Exp(a);
678     aSign = extractFloatx80Sign(a);
679 
680     if (aExp == 0x7FFF) {
681         if ((uint64_t) (aSig << 1)) {
682             propagateFloatx80NaNOneArg(a, status);
683         }
684         if (aSign == 0) {
685             return packFloatx80(0, floatx80_infinity.high,
686                                 floatx80_infinity.low);
687         }
688     }
689 
690     if (aExp == 0 && aSig == 0) {
691         float_raise(float_flag_divbyzero, status);
692         return packFloatx80(1, floatx80_infinity.high,
693                             floatx80_infinity.low);
694     }
695 
696     if (aSign) {
697         float_raise(float_flag_invalid, status);
698         return floatx80_default_nan(status);
699     }
700 
701     user_rnd_mode = status->float_rounding_mode;
702     user_rnd_prec = status->floatx80_rounding_precision;
703     status->float_rounding_mode = float_round_nearest_even;
704     status->floatx80_rounding_precision = 80;
705 
706     fp0 = floatx80_logn(a, status);
707     fp1 = packFloatx80(0, 0x3FFD, LIT64(0xDE5BD8A937287195)); /* INV_L10 */
708 
709     status->float_rounding_mode = user_rnd_mode;
710     status->floatx80_rounding_precision = user_rnd_prec;
711 
712     a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L10 */
713 
714     float_raise(float_flag_inexact, status);
715 
716     return a;
717 }
718 
719 /*----------------------------------------------------------------------------
720  | Log base 2
721  *----------------------------------------------------------------------------*/
722 
723 floatx80 floatx80_log2(floatx80 a, float_status *status)
724 {
725     flag aSign;
726     int32_t aExp;
727     uint64_t aSig;
728 
729     int8_t user_rnd_mode, user_rnd_prec;
730 
731     floatx80 fp0, fp1;
732 
733     aSig = extractFloatx80Frac(a);
734     aExp = extractFloatx80Exp(a);
735     aSign = extractFloatx80Sign(a);
736 
737     if (aExp == 0x7FFF) {
738         if ((uint64_t) (aSig << 1)) {
739             propagateFloatx80NaNOneArg(a, status);
740         }
741         if (aSign == 0) {
742             return packFloatx80(0, floatx80_infinity.high,
743                                 floatx80_infinity.low);
744         }
745     }
746 
747     if (aExp == 0) {
748         if (aSig == 0) {
749             float_raise(float_flag_divbyzero, status);
750             return packFloatx80(1, floatx80_infinity.high,
751                                 floatx80_infinity.low);
752         }
753         normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
754     }
755 
756     if (aSign) {
757         float_raise(float_flag_invalid, status);
758         return floatx80_default_nan(status);
759     }
760 
761     user_rnd_mode = status->float_rounding_mode;
762     user_rnd_prec = status->floatx80_rounding_precision;
763     status->float_rounding_mode = float_round_nearest_even;
764     status->floatx80_rounding_precision = 80;
765 
766     if (aSig == one_sig) { /* X is 2^k */
767         status->float_rounding_mode = user_rnd_mode;
768         status->floatx80_rounding_precision = user_rnd_prec;
769 
770         a = int32_to_floatx80(aExp - 0x3FFF, status);
771     } else {
772         fp0 = floatx80_logn(a, status);
773         fp1 = packFloatx80(0, 0x3FFF, LIT64(0xB8AA3B295C17F0BC)); /* INV_L2 */
774 
775         status->float_rounding_mode = user_rnd_mode;
776         status->floatx80_rounding_precision = user_rnd_prec;
777 
778         a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L2 */
779     }
780 
781     float_raise(float_flag_inexact, status);
782 
783     return a;
784 }
785 
786 /*----------------------------------------------------------------------------
787  | e to x
788  *----------------------------------------------------------------------------*/
789 
790 floatx80 floatx80_etox(floatx80 a, float_status *status)
791 {
792     flag aSign;
793     int32_t aExp;
794     uint64_t aSig;
795 
796     int8_t user_rnd_mode, user_rnd_prec;
797 
798     int32_t compact, n, j, k, m, m1;
799     floatx80 fp0, fp1, fp2, fp3, l2, scale, adjscale;
800     flag adjflag;
801 
802     aSig = extractFloatx80Frac(a);
803     aExp = extractFloatx80Exp(a);
804     aSign = extractFloatx80Sign(a);
805 
806     if (aExp == 0x7FFF) {
807         if ((uint64_t) (aSig << 1)) {
808             return propagateFloatx80NaNOneArg(a, status);
809         }
810         if (aSign) {
811             return packFloatx80(0, 0, 0);
812         }
813         return packFloatx80(0, floatx80_infinity.high,
814                             floatx80_infinity.low);
815     }
816 
817     if (aExp == 0 && aSig == 0) {
818         return packFloatx80(0, one_exp, one_sig);
819     }
820 
821     user_rnd_mode = status->float_rounding_mode;
822     user_rnd_prec = status->floatx80_rounding_precision;
823     status->float_rounding_mode = float_round_nearest_even;
824     status->floatx80_rounding_precision = 80;
825 
826     adjflag = 0;
827 
828     if (aExp >= 0x3FBE) { /* |X| >= 2^(-65) */
829         compact = floatx80_make_compact(aExp, aSig);
830 
831         if (compact < 0x400CB167) { /* |X| < 16380 log2 */
832             fp0 = a;
833             fp1 = a;
834             fp0 = floatx80_mul(fp0, float32_to_floatx80(
835                                make_float32(0x42B8AA3B), status),
836                                status); /* 64/log2 * X */
837             adjflag = 0;
838             n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
839             fp0 = int32_to_floatx80(n, status);
840 
841             j = n & 0x3F; /* J = N mod 64 */
842             m = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
843             if (n < 0 && j) {
844                 /* arithmetic right shift is division and
845                  * round towards minus infinity
846                  */
847                 m--;
848             }
849             m += 0x3FFF; /* biased exponent of 2^(M) */
850 
851         expcont1:
852             fp2 = fp0; /* N */
853             fp0 = floatx80_mul(fp0, float32_to_floatx80(
854                                make_float32(0xBC317218), status),
855                                status); /* N * L1, L1 = lead(-log2/64) */
856             l2 = packFloatx80(0, 0x3FDC, LIT64(0x82E308654361C4C6));
857             fp2 = floatx80_mul(fp2, l2, status); /* N * L2, L1+L2 = -log2/64 */
858             fp0 = floatx80_add(fp0, fp1, status); /* X + N*L1 */
859             fp0 = floatx80_add(fp0, fp2, status); /* R */
860 
861             fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
862             fp2 = float32_to_floatx80(make_float32(0x3AB60B70),
863                                       status); /* A5 */
864             fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*A5 */
865             fp3 = floatx80_mul(float32_to_floatx80(make_float32(0x3C088895),
866                                status), fp1,
867                                status); /* fp3 is S*A4 */
868             fp2 = floatx80_add(fp2, float64_to_floatx80(make_float64(
869                                0x3FA5555555554431), status),
870                                status); /* fp2 is A3+S*A5 */
871             fp3 = floatx80_add(fp3, float64_to_floatx80(make_float64(
872                                0x3FC5555555554018), status),
873                                status); /* fp3 is A2+S*A4 */
874             fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*(A3+S*A5) */
875             fp3 = floatx80_mul(fp3, fp1, status); /* fp3 is S*(A2+S*A4) */
876             fp2 = floatx80_add(fp2, float32_to_floatx80(
877                                make_float32(0x3F000000), status),
878                                status); /* fp2 is A1+S*(A3+S*A5) */
879             fp3 = floatx80_mul(fp3, fp0, status); /* fp3 IS R*S*(A2+S*A4) */
880             fp2 = floatx80_mul(fp2, fp1,
881                                status); /* fp2 IS S*(A1+S*(A3+S*A5)) */
882             fp0 = floatx80_add(fp0, fp3, status); /* fp0 IS R+R*S*(A2+S*A4) */
883             fp0 = floatx80_add(fp0, fp2, status); /* fp0 IS EXP(R) - 1 */
884 
885             fp1 = exp_tbl[j];
886             fp0 = floatx80_mul(fp0, fp1, status); /* 2^(J/64)*(Exp(R)-1) */
887             fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j], status),
888                                status); /* accurate 2^(J/64) */
889             fp0 = floatx80_add(fp0, fp1,
890                                status); /* 2^(J/64) + 2^(J/64)*(Exp(R)-1) */
891 
892             scale = packFloatx80(0, m, one_sig);
893             if (adjflag) {
894                 adjscale = packFloatx80(0, m1, one_sig);
895                 fp0 = floatx80_mul(fp0, adjscale, status);
896             }
897 
898             status->float_rounding_mode = user_rnd_mode;
899             status->floatx80_rounding_precision = user_rnd_prec;
900 
901             a = floatx80_mul(fp0, scale, status);
902 
903             float_raise(float_flag_inexact, status);
904 
905             return a;
906         } else { /* |X| >= 16380 log2 */
907             if (compact > 0x400CB27C) { /* |X| >= 16480 log2 */
908                 status->float_rounding_mode = user_rnd_mode;
909                 status->floatx80_rounding_precision = user_rnd_prec;
910                 if (aSign) {
911                     a = roundAndPackFloatx80(
912                                            status->floatx80_rounding_precision,
913                                            0, -0x1000, aSig, 0, status);
914                 } else {
915                     a = roundAndPackFloatx80(
916                                            status->floatx80_rounding_precision,
917                                            0, 0x8000, aSig, 0, status);
918                 }
919                 float_raise(float_flag_inexact, status);
920 
921                 return a;
922             } else {
923                 fp0 = a;
924                 fp1 = a;
925                 fp0 = floatx80_mul(fp0, float32_to_floatx80(
926                                    make_float32(0x42B8AA3B), status),
927                                    status); /* 64/log2 * X */
928                 adjflag = 1;
929                 n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
930                 fp0 = int32_to_floatx80(n, status);
931 
932                 j = n & 0x3F; /* J = N mod 64 */
933                 /* NOTE: this is really arithmetic right shift by 6 */
934                 k = n / 64;
935                 if (n < 0 && j) {
936                     /* arithmetic right shift is division and
937                      * round towards minus infinity
938                      */
939                     k--;
940                 }
941                 /* NOTE: this is really arithmetic right shift by 1 */
942                 m1 = k / 2;
943                 if (k < 0 && (k & 1)) {
944                     /* arithmetic right shift is division and
945                      * round towards minus infinity
946                      */
947                     m1--;
948                 }
949                 m = k - m1;
950                 m1 += 0x3FFF; /* biased exponent of 2^(M1) */
951                 m += 0x3FFF; /* biased exponent of 2^(M) */
952 
953                 goto expcont1;
954             }
955         }
956     } else { /* |X| < 2^(-65) */
957         status->float_rounding_mode = user_rnd_mode;
958         status->floatx80_rounding_precision = user_rnd_prec;
959 
960         a = floatx80_add(a, float32_to_floatx80(make_float32(0x3F800000),
961                          status), status); /* 1 + X */
962 
963         float_raise(float_flag_inexact, status);
964 
965         return a;
966     }
967 }
968 
969 /*----------------------------------------------------------------------------
970  | 2 to x
971  *----------------------------------------------------------------------------*/
972 
973 floatx80 floatx80_twotox(floatx80 a, float_status *status)
974 {
975     flag aSign;
976     int32_t aExp;
977     uint64_t aSig;
978 
979     int8_t user_rnd_mode, user_rnd_prec;
980 
981     int32_t compact, n, j, l, m, m1;
982     floatx80 fp0, fp1, fp2, fp3, adjfact, fact1, fact2;
983 
984     aSig = extractFloatx80Frac(a);
985     aExp = extractFloatx80Exp(a);
986     aSign = extractFloatx80Sign(a);
987 
988     if (aExp == 0x7FFF) {
989         if ((uint64_t) (aSig << 1)) {
990             return propagateFloatx80NaNOneArg(a, status);
991         }
992         if (aSign) {
993             return packFloatx80(0, 0, 0);
994         }
995         return packFloatx80(0, floatx80_infinity.high,
996                             floatx80_infinity.low);
997     }
998 
999     if (aExp == 0 && aSig == 0) {
1000         return packFloatx80(0, one_exp, one_sig);
1001     }
1002 
1003     user_rnd_mode = status->float_rounding_mode;
1004     user_rnd_prec = status->floatx80_rounding_precision;
1005     status->float_rounding_mode = float_round_nearest_even;
1006     status->floatx80_rounding_precision = 80;
1007 
1008     fp0 = a;
1009 
1010     compact = floatx80_make_compact(aExp, aSig);
1011 
1012     if (compact < 0x3FB98000 || compact > 0x400D80C0) {
1013         /* |X| > 16480 or |X| < 2^(-70) */
1014         if (compact > 0x3FFF8000) { /* |X| > 16480 */
1015             status->float_rounding_mode = user_rnd_mode;
1016             status->floatx80_rounding_precision = user_rnd_prec;
1017 
1018             if (aSign) {
1019                 return roundAndPackFloatx80(status->floatx80_rounding_precision,
1020                                             0, -0x1000, aSig, 0, status);
1021             } else {
1022                 return roundAndPackFloatx80(status->floatx80_rounding_precision,
1023                                             0, 0x8000, aSig, 0, status);
1024             }
1025         } else { /* |X| < 2^(-70) */
1026             status->float_rounding_mode = user_rnd_mode;
1027             status->floatx80_rounding_precision = user_rnd_prec;
1028 
1029             a = floatx80_add(fp0, float32_to_floatx80(
1030                              make_float32(0x3F800000), status),
1031                              status); /* 1 + X */
1032 
1033             float_raise(float_flag_inexact, status);
1034 
1035             return a;
1036         }
1037     } else { /* 2^(-70) <= |X| <= 16480 */
1038         fp1 = fp0; /* X */
1039         fp1 = floatx80_mul(fp1, float32_to_floatx80(
1040                            make_float32(0x42800000), status),
1041                            status); /* X * 64 */
1042         n = floatx80_to_int32(fp1, status);
1043         fp1 = int32_to_floatx80(n, status);
1044         j = n & 0x3F;
1045         l = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
1046         if (n < 0 && j) {
1047             /* arithmetic right shift is division and
1048              * round towards minus infinity
1049              */
1050             l--;
1051         }
1052         m = l / 2; /* NOTE: this is really arithmetic right shift by 1 */
1053         if (l < 0 && (l & 1)) {
1054             /* arithmetic right shift is division and
1055              * round towards minus infinity
1056              */
1057             m--;
1058         }
1059         m1 = l - m;
1060         m1 += 0x3FFF; /* ADJFACT IS 2^(M') */
1061 
1062         adjfact = packFloatx80(0, m1, one_sig);
1063         fact1 = exp2_tbl[j];
1064         fact1.high += m;
1065         fact2.high = exp2_tbl2[j] >> 16;
1066         fact2.high += m;
1067         fact2.low = (uint64_t)(exp2_tbl2[j] & 0xFFFF);
1068         fact2.low <<= 48;
1069 
1070         fp1 = floatx80_mul(fp1, float32_to_floatx80(
1071                            make_float32(0x3C800000), status),
1072                            status); /* (1/64)*N */
1073         fp0 = floatx80_sub(fp0, fp1, status); /* X - (1/64)*INT(64 X) */
1074         fp2 = packFloatx80(0, 0x3FFE, LIT64(0xB17217F7D1CF79AC)); /* LOG2 */
1075         fp0 = floatx80_mul(fp0, fp2, status); /* R */
1076 
1077         /* EXPR */
1078         fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1079         fp2 = float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1080                                   status); /* A5 */
1081         fp3 = float64_to_floatx80(make_float64(0x3F811112302C712C),
1082                                   status); /* A4 */
1083         fp2 = floatx80_mul(fp2, fp1, status); /* S*A5 */
1084         fp3 = floatx80_mul(fp3, fp1, status); /* S*A4 */
1085         fp2 = floatx80_add(fp2, float64_to_floatx80(
1086                            make_float64(0x3FA5555555554CC1), status),
1087                            status); /* A3+S*A5 */
1088         fp3 = floatx80_add(fp3, float64_to_floatx80(
1089                            make_float64(0x3FC5555555554A54), status),
1090                            status); /* A2+S*A4 */
1091         fp2 = floatx80_mul(fp2, fp1, status); /* S*(A3+S*A5) */
1092         fp3 = floatx80_mul(fp3, fp1, status); /* S*(A2+S*A4) */
1093         fp2 = floatx80_add(fp2, float64_to_floatx80(
1094                            make_float64(0x3FE0000000000000), status),
1095                            status); /* A1+S*(A3+S*A5) */
1096         fp3 = floatx80_mul(fp3, fp0, status); /* R*S*(A2+S*A4) */
1097 
1098         fp2 = floatx80_mul(fp2, fp1, status); /* S*(A1+S*(A3+S*A5)) */
1099         fp0 = floatx80_add(fp0, fp3, status); /* R+R*S*(A2+S*A4) */
1100         fp0 = floatx80_add(fp0, fp2, status); /* EXP(R) - 1 */
1101 
1102         fp0 = floatx80_mul(fp0, fact1, status);
1103         fp0 = floatx80_add(fp0, fact2, status);
1104         fp0 = floatx80_add(fp0, fact1, status);
1105 
1106         status->float_rounding_mode = user_rnd_mode;
1107         status->floatx80_rounding_precision = user_rnd_prec;
1108 
1109         a = floatx80_mul(fp0, adjfact, status);
1110 
1111         float_raise(float_flag_inexact, status);
1112 
1113         return a;
1114     }
1115 }
1116 
1117 /*----------------------------------------------------------------------------
1118  | 10 to x
1119  *----------------------------------------------------------------------------*/
1120 
1121 floatx80 floatx80_tentox(floatx80 a, float_status *status)
1122 {
1123     flag aSign;
1124     int32_t aExp;
1125     uint64_t aSig;
1126 
1127     int8_t user_rnd_mode, user_rnd_prec;
1128 
1129     int32_t compact, n, j, l, m, m1;
1130     floatx80 fp0, fp1, fp2, fp3, adjfact, fact1, fact2;
1131 
1132     aSig = extractFloatx80Frac(a);
1133     aExp = extractFloatx80Exp(a);
1134     aSign = extractFloatx80Sign(a);
1135 
1136     if (aExp == 0x7FFF) {
1137         if ((uint64_t) (aSig << 1)) {
1138             return propagateFloatx80NaNOneArg(a, status);
1139         }
1140         if (aSign) {
1141             return packFloatx80(0, 0, 0);
1142         }
1143         return packFloatx80(0, floatx80_infinity.high,
1144                             floatx80_infinity.low);
1145     }
1146 
1147     if (aExp == 0 && aSig == 0) {
1148         return packFloatx80(0, one_exp, one_sig);
1149     }
1150 
1151     user_rnd_mode = status->float_rounding_mode;
1152     user_rnd_prec = status->floatx80_rounding_precision;
1153     status->float_rounding_mode = float_round_nearest_even;
1154     status->floatx80_rounding_precision = 80;
1155 
1156     fp0 = a;
1157 
1158     compact = floatx80_make_compact(aExp, aSig);
1159 
1160     if (compact < 0x3FB98000 || compact > 0x400B9B07) {
1161         /* |X| > 16480 LOG2/LOG10 or |X| < 2^(-70) */
1162         if (compact > 0x3FFF8000) { /* |X| > 16480 */
1163             status->float_rounding_mode = user_rnd_mode;
1164             status->floatx80_rounding_precision = user_rnd_prec;
1165 
1166             if (aSign) {
1167                 return roundAndPackFloatx80(status->floatx80_rounding_precision,
1168                                             0, -0x1000, aSig, 0, status);
1169             } else {
1170                 return roundAndPackFloatx80(status->floatx80_rounding_precision,
1171                                             0, 0x8000, aSig, 0, status);
1172             }
1173         } else { /* |X| < 2^(-70) */
1174             status->float_rounding_mode = user_rnd_mode;
1175             status->floatx80_rounding_precision = user_rnd_prec;
1176 
1177             a = floatx80_add(fp0, float32_to_floatx80(
1178                              make_float32(0x3F800000), status),
1179                              status); /* 1 + X */
1180 
1181             float_raise(float_flag_inexact, status);
1182 
1183             return a;
1184         }
1185     } else { /* 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10 */
1186         fp1 = fp0; /* X */
1187         fp1 = floatx80_mul(fp1, float64_to_floatx80(
1188                            make_float64(0x406A934F0979A371),
1189                            status), status); /* X*64*LOG10/LOG2 */
1190         n = floatx80_to_int32(fp1, status); /* N=INT(X*64*LOG10/LOG2) */
1191         fp1 = int32_to_floatx80(n, status);
1192 
1193         j = n & 0x3F;
1194         l = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
1195         if (n < 0 && j) {
1196             /* arithmetic right shift is division and
1197              * round towards minus infinity
1198              */
1199             l--;
1200         }
1201         m = l / 2; /* NOTE: this is really arithmetic right shift by 1 */
1202         if (l < 0 && (l & 1)) {
1203             /* arithmetic right shift is division and
1204              * round towards minus infinity
1205              */
1206             m--;
1207         }
1208         m1 = l - m;
1209         m1 += 0x3FFF; /* ADJFACT IS 2^(M') */
1210 
1211         adjfact = packFloatx80(0, m1, one_sig);
1212         fact1 = exp2_tbl[j];
1213         fact1.high += m;
1214         fact2.high = exp2_tbl2[j] >> 16;
1215         fact2.high += m;
1216         fact2.low = (uint64_t)(exp2_tbl2[j] & 0xFFFF);
1217         fact2.low <<= 48;
1218 
1219         fp2 = fp1; /* N */
1220         fp1 = floatx80_mul(fp1, float64_to_floatx80(
1221                            make_float64(0x3F734413509F8000), status),
1222                            status); /* N*(LOG2/64LOG10)_LEAD */
1223         fp3 = packFloatx80(1, 0x3FCD, LIT64(0xC0219DC1DA994FD2));
1224         fp2 = floatx80_mul(fp2, fp3, status); /* N*(LOG2/64LOG10)_TRAIL */
1225         fp0 = floatx80_sub(fp0, fp1, status); /* X - N L_LEAD */
1226         fp0 = floatx80_sub(fp0, fp2, status); /* X - N L_TRAIL */
1227         fp2 = packFloatx80(0, 0x4000, LIT64(0x935D8DDDAAA8AC17)); /* LOG10 */
1228         fp0 = floatx80_mul(fp0, fp2, status); /* R */
1229 
1230         /* EXPR */
1231         fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1232         fp2 = float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1233                                   status); /* A5 */
1234         fp3 = float64_to_floatx80(make_float64(0x3F811112302C712C),
1235                                   status); /* A4 */
1236         fp2 = floatx80_mul(fp2, fp1, status); /* S*A5 */
1237         fp3 = floatx80_mul(fp3, fp1, status); /* S*A4 */
1238         fp2 = floatx80_add(fp2, float64_to_floatx80(
1239                            make_float64(0x3FA5555555554CC1), status),
1240                            status); /* A3+S*A5 */
1241         fp3 = floatx80_add(fp3, float64_to_floatx80(
1242                            make_float64(0x3FC5555555554A54), status),
1243                            status); /* A2+S*A4 */
1244         fp2 = floatx80_mul(fp2, fp1, status); /* S*(A3+S*A5) */
1245         fp3 = floatx80_mul(fp3, fp1, status); /* S*(A2+S*A4) */
1246         fp2 = floatx80_add(fp2, float64_to_floatx80(
1247                            make_float64(0x3FE0000000000000), status),
1248                            status); /* A1+S*(A3+S*A5) */
1249         fp3 = floatx80_mul(fp3, fp0, status); /* R*S*(A2+S*A4) */
1250 
1251         fp2 = floatx80_mul(fp2, fp1, status); /* S*(A1+S*(A3+S*A5)) */
1252         fp0 = floatx80_add(fp0, fp3, status); /* R+R*S*(A2+S*A4) */
1253         fp0 = floatx80_add(fp0, fp2, status); /* EXP(R) - 1 */
1254 
1255         fp0 = floatx80_mul(fp0, fact1, status);
1256         fp0 = floatx80_add(fp0, fact2, status);
1257         fp0 = floatx80_add(fp0, fact1, status);
1258 
1259         status->float_rounding_mode = user_rnd_mode;
1260         status->floatx80_rounding_precision = user_rnd_prec;
1261 
1262         a = floatx80_mul(fp0, adjfact, status);
1263 
1264         float_raise(float_flag_inexact, status);
1265 
1266         return a;
1267     }
1268 }
1269