xref: /openbmc/qemu/target/m68k/softfloat.c (revision 1cbd2d91)
1591596b7SLaurent Vivier /*
2591596b7SLaurent Vivier  * Ported from a work by Andreas Grabher for Previous, NeXT Computer Emulator,
3591596b7SLaurent Vivier  * derived from NetBSD M68040 FPSP functions,
4591596b7SLaurent Vivier  * derived from release 2a of the SoftFloat IEC/IEEE Floating-point Arithmetic
5591596b7SLaurent Vivier  * Package. Those parts of the code (and some later contributions) are
6591596b7SLaurent Vivier  * provided under that license, as detailed below.
7591596b7SLaurent Vivier  * It has subsequently been modified by contributors to the QEMU Project,
8591596b7SLaurent Vivier  * so some portions are provided under:
9591596b7SLaurent Vivier  *  the SoftFloat-2a license
10591596b7SLaurent Vivier  *  the BSD license
11591596b7SLaurent Vivier  *  GPL-v2-or-later
12591596b7SLaurent Vivier  *
13591596b7SLaurent Vivier  * Any future contributions to this file will be taken to be licensed under
14591596b7SLaurent Vivier  * the Softfloat-2a license unless specifically indicated otherwise.
15591596b7SLaurent Vivier  */
16591596b7SLaurent Vivier 
17808d77bcSLucien Murray-Pitts /*
18808d77bcSLucien Murray-Pitts  * Portions of this work are licensed under the terms of the GNU GPL,
19591596b7SLaurent Vivier  * version 2 or later. See the COPYING file in the top-level directory.
20591596b7SLaurent Vivier  */
21591596b7SLaurent Vivier 
22591596b7SLaurent Vivier #include "qemu/osdep.h"
23591596b7SLaurent Vivier #include "softfloat.h"
24591596b7SLaurent Vivier #include "fpu/softfloat-macros.h"
254b5c65b8SLaurent Vivier #include "softfloat_fpsp_tables.h"
26591596b7SLaurent Vivier 
27c84813b8SLaurent Vivier #define pi_exp      0x4000
288c992abcSLaurent Vivier #define piby2_exp   0x3FFF
29e2326300SAlex Bennée #define pi_sig      UINT64_C(0xc90fdaa22168c235)
308c992abcSLaurent Vivier 
propagateFloatx80NaNOneArg(floatx80 a,float_status * status)310d379c17SLaurent Vivier static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status)
320d379c17SLaurent Vivier {
330d379c17SLaurent Vivier     if (floatx80_is_signaling_nan(a, status)) {
340d379c17SLaurent Vivier         float_raise(float_flag_invalid, status);
351c0c951fSRichard Henderson         a = floatx80_silence_nan(a, status);
360d379c17SLaurent Vivier     }
370d379c17SLaurent Vivier 
380d379c17SLaurent Vivier     if (status->default_nan_mode) {
390d379c17SLaurent Vivier         return floatx80_default_nan(status);
400d379c17SLaurent Vivier     }
410d379c17SLaurent Vivier 
421c0c951fSRichard Henderson     return a;
430d379c17SLaurent Vivier }
440d379c17SLaurent Vivier 
45808d77bcSLucien Murray-Pitts /*
46808d77bcSLucien Murray-Pitts  * Returns the mantissa of the extended double-precision floating-point
47808d77bcSLucien Murray-Pitts  * value `a'.
48808d77bcSLucien Murray-Pitts  */
490d379c17SLaurent Vivier 
floatx80_getman(floatx80 a,float_status * status)500d379c17SLaurent Vivier floatx80 floatx80_getman(floatx80 a, float_status *status)
510d379c17SLaurent Vivier {
52c120391cSRichard Henderson     bool aSign;
530d379c17SLaurent Vivier     int32_t aExp;
540d379c17SLaurent Vivier     uint64_t aSig;
550d379c17SLaurent Vivier 
560d379c17SLaurent Vivier     aSig = extractFloatx80Frac(a);
570d379c17SLaurent Vivier     aExp = extractFloatx80Exp(a);
580d379c17SLaurent Vivier     aSign = extractFloatx80Sign(a);
590d379c17SLaurent Vivier 
600d379c17SLaurent Vivier     if (aExp == 0x7FFF) {
610d379c17SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
620d379c17SLaurent Vivier             return propagateFloatx80NaNOneArg(a , status);
630d379c17SLaurent Vivier         }
640d379c17SLaurent Vivier         float_raise(float_flag_invalid , status);
650d379c17SLaurent Vivier         return floatx80_default_nan(status);
660d379c17SLaurent Vivier     }
670d379c17SLaurent Vivier 
680d379c17SLaurent Vivier     if (aExp == 0) {
690d379c17SLaurent Vivier         if (aSig == 0) {
700d379c17SLaurent Vivier             return packFloatx80(aSign, 0, 0);
710d379c17SLaurent Vivier         }
720d379c17SLaurent Vivier         normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
730d379c17SLaurent Vivier     }
740d379c17SLaurent Vivier 
750d379c17SLaurent Vivier     return roundAndPackFloatx80(status->floatx80_rounding_precision, aSign,
760d379c17SLaurent Vivier                                 0x3FFF, aSig, 0, status);
770d379c17SLaurent Vivier }
780d379c17SLaurent Vivier 
79808d77bcSLucien Murray-Pitts /*
80808d77bcSLucien Murray-Pitts  * Returns the exponent of the extended double-precision floating-point
81808d77bcSLucien Murray-Pitts  * value `a' as an extended double-precision value.
82808d77bcSLucien Murray-Pitts  */
830d379c17SLaurent Vivier 
floatx80_getexp(floatx80 a,float_status * status)840d379c17SLaurent Vivier floatx80 floatx80_getexp(floatx80 a, float_status *status)
850d379c17SLaurent Vivier {
86c120391cSRichard Henderson     bool aSign;
870d379c17SLaurent Vivier     int32_t aExp;
880d379c17SLaurent Vivier     uint64_t aSig;
890d379c17SLaurent Vivier 
900d379c17SLaurent Vivier     aSig = extractFloatx80Frac(a);
910d379c17SLaurent Vivier     aExp = extractFloatx80Exp(a);
920d379c17SLaurent Vivier     aSign = extractFloatx80Sign(a);
930d379c17SLaurent Vivier 
940d379c17SLaurent Vivier     if (aExp == 0x7FFF) {
950d379c17SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
960d379c17SLaurent Vivier             return propagateFloatx80NaNOneArg(a , status);
970d379c17SLaurent Vivier         }
980d379c17SLaurent Vivier         float_raise(float_flag_invalid , status);
990d379c17SLaurent Vivier         return floatx80_default_nan(status);
1000d379c17SLaurent Vivier     }
1010d379c17SLaurent Vivier 
1020d379c17SLaurent Vivier     if (aExp == 0) {
1030d379c17SLaurent Vivier         if (aSig == 0) {
1040d379c17SLaurent Vivier             return packFloatx80(aSign, 0, 0);
1050d379c17SLaurent Vivier         }
1060d379c17SLaurent Vivier         normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
1070d379c17SLaurent Vivier     }
1080d379c17SLaurent Vivier 
1090d379c17SLaurent Vivier     return int32_to_floatx80(aExp - 0x3FFF, status);
1100d379c17SLaurent Vivier }
1110d379c17SLaurent Vivier 
112808d77bcSLucien Murray-Pitts /*
113808d77bcSLucien Murray-Pitts  * Scales extended double-precision floating-point value in operand `a' by
114808d77bcSLucien Murray-Pitts  * value `b'. The function truncates the value in the second operand 'b' to
115808d77bcSLucien Murray-Pitts  * an integral value and adds that value to the exponent of the operand 'a'.
116808d77bcSLucien Murray-Pitts  * The operation performed according to the IEC/IEEE Standard for Binary
117808d77bcSLucien Murray-Pitts  * Floating-Point Arithmetic.
118808d77bcSLucien Murray-Pitts  */
1190d379c17SLaurent Vivier 
floatx80_scale(floatx80 a,floatx80 b,float_status * status)1200d379c17SLaurent Vivier floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status)
1210d379c17SLaurent Vivier {
122c120391cSRichard Henderson     bool aSign, bSign;
1230d379c17SLaurent Vivier     int32_t aExp, bExp, shiftCount;
1240d379c17SLaurent Vivier     uint64_t aSig, bSig;
1250d379c17SLaurent Vivier 
1260d379c17SLaurent Vivier     aSig = extractFloatx80Frac(a);
1270d379c17SLaurent Vivier     aExp = extractFloatx80Exp(a);
1280d379c17SLaurent Vivier     aSign = extractFloatx80Sign(a);
1290d379c17SLaurent Vivier     bSig = extractFloatx80Frac(b);
1300d379c17SLaurent Vivier     bExp = extractFloatx80Exp(b);
1310d379c17SLaurent Vivier     bSign = extractFloatx80Sign(b);
1320d379c17SLaurent Vivier 
1330d379c17SLaurent Vivier     if (bExp == 0x7FFF) {
1340d379c17SLaurent Vivier         if ((uint64_t) (bSig << 1) ||
1350d379c17SLaurent Vivier             ((aExp == 0x7FFF) && (uint64_t) (aSig << 1))) {
1360d379c17SLaurent Vivier             return propagateFloatx80NaN(a, b, status);
1370d379c17SLaurent Vivier         }
1380d379c17SLaurent Vivier         float_raise(float_flag_invalid , status);
1390d379c17SLaurent Vivier         return floatx80_default_nan(status);
1400d379c17SLaurent Vivier     }
1410d379c17SLaurent Vivier     if (aExp == 0x7FFF) {
1420d379c17SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
1430d379c17SLaurent Vivier             return propagateFloatx80NaN(a, b, status);
1440d379c17SLaurent Vivier         }
1450d379c17SLaurent Vivier         return packFloatx80(aSign, floatx80_infinity.high,
1460d379c17SLaurent Vivier                             floatx80_infinity.low);
1470d379c17SLaurent Vivier     }
1480d379c17SLaurent Vivier     if (aExp == 0) {
1490d379c17SLaurent Vivier         if (aSig == 0) {
1500d379c17SLaurent Vivier             return packFloatx80(aSign, 0, 0);
1510d379c17SLaurent Vivier         }
1520d379c17SLaurent Vivier         if (bExp < 0x3FFF) {
1530d379c17SLaurent Vivier             return a;
1540d379c17SLaurent Vivier         }
1550d379c17SLaurent Vivier         normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
1560d379c17SLaurent Vivier     }
1570d379c17SLaurent Vivier 
1580d379c17SLaurent Vivier     if (bExp < 0x3FFF) {
1590d379c17SLaurent Vivier         return a;
1600d379c17SLaurent Vivier     }
1610d379c17SLaurent Vivier 
1620d379c17SLaurent Vivier     if (0x400F < bExp) {
1630d379c17SLaurent Vivier         aExp = bSign ? -0x6001 : 0xE000;
1640d379c17SLaurent Vivier         return roundAndPackFloatx80(status->floatx80_rounding_precision,
1650d379c17SLaurent Vivier                                     aSign, aExp, aSig, 0, status);
1660d379c17SLaurent Vivier     }
1670d379c17SLaurent Vivier 
1680d379c17SLaurent Vivier     shiftCount = 0x403E - bExp;
1690d379c17SLaurent Vivier     bSig >>= shiftCount;
1700d379c17SLaurent Vivier     aExp = bSign ? (aExp - bSig) : (aExp + bSig);
1710d379c17SLaurent Vivier 
1720d379c17SLaurent Vivier     return roundAndPackFloatx80(status->floatx80_rounding_precision,
1730d379c17SLaurent Vivier                                 aSign, aExp, aSig, 0, status);
1740d379c17SLaurent Vivier }
1759a069775SLaurent Vivier 
floatx80_move(floatx80 a,float_status * status)1769a069775SLaurent Vivier floatx80 floatx80_move(floatx80 a, float_status *status)
1779a069775SLaurent Vivier {
178c120391cSRichard Henderson     bool aSign;
1799a069775SLaurent Vivier     int32_t aExp;
1809a069775SLaurent Vivier     uint64_t aSig;
1819a069775SLaurent Vivier 
1829a069775SLaurent Vivier     aSig = extractFloatx80Frac(a);
1839a069775SLaurent Vivier     aExp = extractFloatx80Exp(a);
1849a069775SLaurent Vivier     aSign = extractFloatx80Sign(a);
1859a069775SLaurent Vivier 
1869a069775SLaurent Vivier     if (aExp == 0x7FFF) {
1879a069775SLaurent Vivier         if ((uint64_t)(aSig << 1)) {
1889a069775SLaurent Vivier             return propagateFloatx80NaNOneArg(a, status);
1899a069775SLaurent Vivier         }
1909a069775SLaurent Vivier         return a;
1919a069775SLaurent Vivier     }
1929a069775SLaurent Vivier     if (aExp == 0) {
1939a069775SLaurent Vivier         if (aSig == 0) {
1949a069775SLaurent Vivier             return a;
1959a069775SLaurent Vivier         }
1969a069775SLaurent Vivier         normalizeRoundAndPackFloatx80(status->floatx80_rounding_precision,
1979a069775SLaurent Vivier                                       aSign, aExp, aSig, 0, status);
1989a069775SLaurent Vivier     }
1999a069775SLaurent Vivier     return roundAndPackFloatx80(status->floatx80_rounding_precision, aSign,
2009a069775SLaurent Vivier                                 aExp, aSig, 0, status);
2019a069775SLaurent Vivier }
2024b5c65b8SLaurent Vivier 
203808d77bcSLucien Murray-Pitts /*
204808d77bcSLucien Murray-Pitts  * Algorithms for transcendental functions supported by MC68881 and MC68882
205808d77bcSLucien Murray-Pitts  * mathematical coprocessors. The functions are derived from FPSP library.
206808d77bcSLucien Murray-Pitts  */
2074b5c65b8SLaurent Vivier 
2084b5c65b8SLaurent Vivier #define one_exp     0x3FFF
209e2326300SAlex Bennée #define one_sig     UINT64_C(0x8000000000000000)
2104b5c65b8SLaurent Vivier 
211808d77bcSLucien Murray-Pitts /*
212808d77bcSLucien Murray-Pitts  * Function for compactifying extended double-precision floating point values.
213808d77bcSLucien Murray-Pitts  */
2144b5c65b8SLaurent Vivier 
floatx80_make_compact(int32_t aExp,uint64_t aSig)2154b5c65b8SLaurent Vivier static int32_t floatx80_make_compact(int32_t aExp, uint64_t aSig)
2164b5c65b8SLaurent Vivier {
2174b5c65b8SLaurent Vivier     return (aExp << 16) | (aSig >> 48);
2184b5c65b8SLaurent Vivier }
2194b5c65b8SLaurent Vivier 
220808d77bcSLucien Murray-Pitts /*
221808d77bcSLucien Murray-Pitts  * Log base e of x plus 1
222808d77bcSLucien Murray-Pitts  */
2234b5c65b8SLaurent Vivier 
floatx80_lognp1(floatx80 a,float_status * status)2244b5c65b8SLaurent Vivier floatx80 floatx80_lognp1(floatx80 a, float_status *status)
2254b5c65b8SLaurent Vivier {
226c120391cSRichard Henderson     bool aSign;
2274b5c65b8SLaurent Vivier     int32_t aExp;
2284b5c65b8SLaurent Vivier     uint64_t aSig, fSig;
2294b5c65b8SLaurent Vivier 
230*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
231*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
2324b5c65b8SLaurent Vivier 
2334b5c65b8SLaurent Vivier     int32_t compact, j, k;
2344b5c65b8SLaurent Vivier     floatx80 fp0, fp1, fp2, fp3, f, logof2, klog2, saveu;
2354b5c65b8SLaurent Vivier 
2364b5c65b8SLaurent Vivier     aSig = extractFloatx80Frac(a);
2374b5c65b8SLaurent Vivier     aExp = extractFloatx80Exp(a);
2384b5c65b8SLaurent Vivier     aSign = extractFloatx80Sign(a);
2394b5c65b8SLaurent Vivier 
2404b5c65b8SLaurent Vivier     if (aExp == 0x7FFF) {
2414b5c65b8SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
2424b5c65b8SLaurent Vivier             propagateFloatx80NaNOneArg(a, status);
2434b5c65b8SLaurent Vivier         }
2444b5c65b8SLaurent Vivier         if (aSign) {
2454b5c65b8SLaurent Vivier             float_raise(float_flag_invalid, status);
2464b5c65b8SLaurent Vivier             return floatx80_default_nan(status);
2474b5c65b8SLaurent Vivier         }
2484b5c65b8SLaurent Vivier         return packFloatx80(0, floatx80_infinity.high, floatx80_infinity.low);
2494b5c65b8SLaurent Vivier     }
2504b5c65b8SLaurent Vivier 
2514b5c65b8SLaurent Vivier     if (aExp == 0 && aSig == 0) {
2524b5c65b8SLaurent Vivier         return packFloatx80(aSign, 0, 0);
2534b5c65b8SLaurent Vivier     }
2544b5c65b8SLaurent Vivier 
2554b5c65b8SLaurent Vivier     if (aSign && aExp >= one_exp) {
2564b5c65b8SLaurent Vivier         if (aExp == one_exp && aSig == one_sig) {
2574b5c65b8SLaurent Vivier             float_raise(float_flag_divbyzero, status);
258981348afSLaurent Vivier             return packFloatx80(aSign, floatx80_infinity.high,
259981348afSLaurent Vivier                                 floatx80_infinity.low);
2604b5c65b8SLaurent Vivier         }
2614b5c65b8SLaurent Vivier         float_raise(float_flag_invalid, status);
2624b5c65b8SLaurent Vivier         return floatx80_default_nan(status);
2634b5c65b8SLaurent Vivier     }
2644b5c65b8SLaurent Vivier 
2654b5c65b8SLaurent Vivier     if (aExp < 0x3f99 || (aExp == 0x3f99 && aSig == one_sig)) {
2664b5c65b8SLaurent Vivier         /* <= min threshold */
2674b5c65b8SLaurent Vivier         float_raise(float_flag_inexact, status);
2684b5c65b8SLaurent Vivier         return floatx80_move(a, status);
2694b5c65b8SLaurent Vivier     }
2704b5c65b8SLaurent Vivier 
2714b5c65b8SLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
2724b5c65b8SLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
2734b5c65b8SLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
274*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
2754b5c65b8SLaurent Vivier 
2764b5c65b8SLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
2774b5c65b8SLaurent Vivier 
2784b5c65b8SLaurent Vivier     fp0 = a; /* Z */
2794b5c65b8SLaurent Vivier     fp1 = a;
2804b5c65b8SLaurent Vivier 
2814b5c65b8SLaurent Vivier     fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
2824b5c65b8SLaurent Vivier                        status), status); /* X = (1+Z) */
2834b5c65b8SLaurent Vivier 
2844b5c65b8SLaurent Vivier     aExp = extractFloatx80Exp(fp0);
2854b5c65b8SLaurent Vivier     aSig = extractFloatx80Frac(fp0);
2864b5c65b8SLaurent Vivier 
2874b5c65b8SLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
2884b5c65b8SLaurent Vivier 
2894b5c65b8SLaurent Vivier     if (compact < 0x3FFE8000 || compact > 0x3FFFC000) {
2904b5c65b8SLaurent Vivier         /* |X| < 1/2 or |X| > 3/2 */
2914b5c65b8SLaurent Vivier         k = aExp - 0x3FFF;
2924b5c65b8SLaurent Vivier         fp1 = int32_to_floatx80(k, status);
2934b5c65b8SLaurent Vivier 
294e2326300SAlex Bennée         fSig = (aSig & UINT64_C(0xFE00000000000000)) | UINT64_C(0x0100000000000000);
2954b5c65b8SLaurent Vivier         j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
2964b5c65b8SLaurent Vivier 
2974b5c65b8SLaurent Vivier         f = packFloatx80(0, 0x3FFF, fSig); /* F */
2984b5c65b8SLaurent Vivier         fp0 = packFloatx80(0, 0x3FFF, aSig); /* Y */
2994b5c65b8SLaurent Vivier 
3004b5c65b8SLaurent Vivier         fp0 = floatx80_sub(fp0, f, status); /* Y-F */
3014b5c65b8SLaurent Vivier 
3024b5c65b8SLaurent Vivier     lp1cont1:
3034b5c65b8SLaurent Vivier         /* LP1CONT1 */
3044b5c65b8SLaurent Vivier         fp0 = floatx80_mul(fp0, log_tbl[j], status); /* FP0 IS U = (Y-F)/F */
305e2326300SAlex Bennée         logof2 = packFloatx80(0, 0x3FFE, UINT64_C(0xB17217F7D1CF79AC));
3064b5c65b8SLaurent Vivier         klog2 = floatx80_mul(fp1, logof2, status); /* FP1 IS K*LOG2 */
3074b5c65b8SLaurent Vivier         fp2 = floatx80_mul(fp0, fp0, status); /* FP2 IS V=U*U */
3084b5c65b8SLaurent Vivier 
3094b5c65b8SLaurent Vivier         fp3 = fp2;
3104b5c65b8SLaurent Vivier         fp1 = fp2;
3114b5c65b8SLaurent Vivier 
3124b5c65b8SLaurent Vivier         fp1 = floatx80_mul(fp1, float64_to_floatx80(
3134b5c65b8SLaurent Vivier                            make_float64(0x3FC2499AB5E4040B), status),
3144b5c65b8SLaurent Vivier                            status); /* V*A6 */
3154b5c65b8SLaurent Vivier         fp2 = floatx80_mul(fp2, float64_to_floatx80(
3164b5c65b8SLaurent Vivier                            make_float64(0xBFC555B5848CB7DB), status),
3174b5c65b8SLaurent Vivier                            status); /* V*A5 */
3184b5c65b8SLaurent Vivier         fp1 = floatx80_add(fp1, float64_to_floatx80(
3194b5c65b8SLaurent Vivier                            make_float64(0x3FC99999987D8730), status),
3204b5c65b8SLaurent Vivier                            status); /* A4+V*A6 */
3214b5c65b8SLaurent Vivier         fp2 = floatx80_add(fp2, float64_to_floatx80(
3224b5c65b8SLaurent Vivier                            make_float64(0xBFCFFFFFFF6F7E97), status),
3234b5c65b8SLaurent Vivier                            status); /* A3+V*A5 */
3244b5c65b8SLaurent Vivier         fp1 = floatx80_mul(fp1, fp3, status); /* V*(A4+V*A6) */
3254b5c65b8SLaurent Vivier         fp2 = floatx80_mul(fp2, fp3, status); /* V*(A3+V*A5) */
3264b5c65b8SLaurent Vivier         fp1 = floatx80_add(fp1, float64_to_floatx80(
3274b5c65b8SLaurent Vivier                            make_float64(0x3FD55555555555A4), status),
3284b5c65b8SLaurent Vivier                            status); /* A2+V*(A4+V*A6) */
3294b5c65b8SLaurent Vivier         fp2 = floatx80_add(fp2, float64_to_floatx80(
3304b5c65b8SLaurent Vivier                            make_float64(0xBFE0000000000008), status),
3314b5c65b8SLaurent Vivier                            status); /* A1+V*(A3+V*A5) */
3324b5c65b8SLaurent Vivier         fp1 = floatx80_mul(fp1, fp3, status); /* V*(A2+V*(A4+V*A6)) */
3334b5c65b8SLaurent Vivier         fp2 = floatx80_mul(fp2, fp3, status); /* V*(A1+V*(A3+V*A5)) */
3344b5c65b8SLaurent Vivier         fp1 = floatx80_mul(fp1, fp0, status); /* U*V*(A2+V*(A4+V*A6)) */
3354b5c65b8SLaurent Vivier         fp0 = floatx80_add(fp0, fp2, status); /* U+V*(A1+V*(A3+V*A5)) */
3364b5c65b8SLaurent Vivier 
3374b5c65b8SLaurent Vivier         fp1 = floatx80_add(fp1, log_tbl[j + 1],
3384b5c65b8SLaurent Vivier                            status); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
3394b5c65b8SLaurent Vivier         fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */
3404b5c65b8SLaurent Vivier 
3414b5c65b8SLaurent Vivier         status->float_rounding_mode = user_rnd_mode;
3424b5c65b8SLaurent Vivier         status->floatx80_rounding_precision = user_rnd_prec;
3434b5c65b8SLaurent Vivier 
3444b5c65b8SLaurent Vivier         a = floatx80_add(fp0, klog2, status);
3454b5c65b8SLaurent Vivier 
3464b5c65b8SLaurent Vivier         float_raise(float_flag_inexact, status);
3474b5c65b8SLaurent Vivier 
3484b5c65b8SLaurent Vivier         return a;
3494b5c65b8SLaurent Vivier     } else if (compact < 0x3FFEF07D || compact > 0x3FFF8841) {
3504b5c65b8SLaurent Vivier         /* |X| < 1/16 or |X| > -1/16 */
3514b5c65b8SLaurent Vivier         /* LP1CARE */
352e2326300SAlex Bennée         fSig = (aSig & UINT64_C(0xFE00000000000000)) | UINT64_C(0x0100000000000000);
3534b5c65b8SLaurent Vivier         f = packFloatx80(0, 0x3FFF, fSig); /* F */
3544b5c65b8SLaurent Vivier         j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
3554b5c65b8SLaurent Vivier 
3564b5c65b8SLaurent Vivier         if (compact >= 0x3FFF8000) { /* 1+Z >= 1 */
3574b5c65b8SLaurent Vivier             /* KISZERO */
3584b5c65b8SLaurent Vivier             fp0 = floatx80_sub(float32_to_floatx80(make_float32(0x3F800000),
3594b5c65b8SLaurent Vivier                                status), f, status); /* 1-F */
3604b5c65b8SLaurent Vivier             fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS Y-F = (1-F)+Z */
3614b5c65b8SLaurent Vivier             fp1 = packFloatx80(0, 0, 0); /* K = 0 */
3624b5c65b8SLaurent Vivier         } else {
3634b5c65b8SLaurent Vivier             /* KISNEG */
3644b5c65b8SLaurent Vivier             fp0 = floatx80_sub(float32_to_floatx80(make_float32(0x40000000),
3654b5c65b8SLaurent Vivier                                status), f, status); /* 2-F */
3664b5c65b8SLaurent Vivier             fp1 = floatx80_add(fp1, fp1, status); /* 2Z */
3674b5c65b8SLaurent Vivier             fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS Y-F = (2-F)+2Z */
3684b5c65b8SLaurent Vivier             fp1 = packFloatx80(1, one_exp, one_sig); /* K = -1 */
3694b5c65b8SLaurent Vivier         }
3704b5c65b8SLaurent Vivier         goto lp1cont1;
3714b5c65b8SLaurent Vivier     } else {
3724b5c65b8SLaurent Vivier         /* LP1ONE16 */
3734b5c65b8SLaurent Vivier         fp1 = floatx80_add(fp1, fp1, status); /* FP1 IS 2Z */
3744b5c65b8SLaurent Vivier         fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
3754b5c65b8SLaurent Vivier                            status), status); /* FP0 IS 1+X */
3764b5c65b8SLaurent Vivier 
3774b5c65b8SLaurent Vivier         /* LP1CONT2 */
3784b5c65b8SLaurent Vivier         fp1 = floatx80_div(fp1, fp0, status); /* U */
3794b5c65b8SLaurent Vivier         saveu = fp1;
3804b5c65b8SLaurent Vivier         fp0 = floatx80_mul(fp1, fp1, status); /* FP0 IS V = U*U */
3814b5c65b8SLaurent Vivier         fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS W = V*V */
3824b5c65b8SLaurent Vivier 
3834b5c65b8SLaurent Vivier         fp3 = float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
3844b5c65b8SLaurent Vivier                                   status); /* B5 */
3854b5c65b8SLaurent Vivier         fp2 = float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
3864b5c65b8SLaurent Vivier                                   status); /* B4 */
3874b5c65b8SLaurent Vivier         fp3 = floatx80_mul(fp3, fp1, status); /* W*B5 */
3884b5c65b8SLaurent Vivier         fp2 = floatx80_mul(fp2, fp1, status); /* W*B4 */
3894b5c65b8SLaurent Vivier         fp3 = floatx80_add(fp3, float64_to_floatx80(
3904b5c65b8SLaurent Vivier                            make_float64(0x3F624924928BCCFF), status),
3914b5c65b8SLaurent Vivier                            status); /* B3+W*B5 */
3924b5c65b8SLaurent Vivier         fp2 = floatx80_add(fp2, float64_to_floatx80(
3934b5c65b8SLaurent Vivier                            make_float64(0x3F899999999995EC), status),
3944b5c65b8SLaurent Vivier                            status); /* B2+W*B4 */
3954b5c65b8SLaurent Vivier         fp1 = floatx80_mul(fp1, fp3, status); /* W*(B3+W*B5) */
3964b5c65b8SLaurent Vivier         fp2 = floatx80_mul(fp2, fp0, status); /* V*(B2+W*B4) */
3974b5c65b8SLaurent Vivier         fp1 = floatx80_add(fp1, float64_to_floatx80(
3984b5c65b8SLaurent Vivier                            make_float64(0x3FB5555555555555), status),
3994b5c65b8SLaurent Vivier                            status); /* B1+W*(B3+W*B5) */
4004b5c65b8SLaurent Vivier 
4014b5c65b8SLaurent Vivier         fp0 = floatx80_mul(fp0, saveu, status); /* FP0 IS U*V */
4024b5c65b8SLaurent Vivier         fp1 = floatx80_add(fp1, fp2,
4034b5c65b8SLaurent Vivier                            status); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
4044b5c65b8SLaurent Vivier         fp0 = floatx80_mul(fp0, fp1,
4054b5c65b8SLaurent Vivier                            status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
4064b5c65b8SLaurent Vivier 
4074b5c65b8SLaurent Vivier         status->float_rounding_mode = user_rnd_mode;
4084b5c65b8SLaurent Vivier         status->floatx80_rounding_precision = user_rnd_prec;
4094b5c65b8SLaurent Vivier 
4104b5c65b8SLaurent Vivier         a = floatx80_add(fp0, saveu, status);
4114b5c65b8SLaurent Vivier 
4124b5c65b8SLaurent Vivier         /*if (!floatx80_is_zero(a)) { */
4134b5c65b8SLaurent Vivier             float_raise(float_flag_inexact, status);
4144b5c65b8SLaurent Vivier         /*} */
4154b5c65b8SLaurent Vivier 
4164b5c65b8SLaurent Vivier         return a;
4174b5c65b8SLaurent Vivier     }
4184b5c65b8SLaurent Vivier }
41950067bd1SLaurent Vivier 
420808d77bcSLucien Murray-Pitts /*
421808d77bcSLucien Murray-Pitts  * Log base e
422808d77bcSLucien Murray-Pitts  */
42350067bd1SLaurent Vivier 
floatx80_logn(floatx80 a,float_status * status)42450067bd1SLaurent Vivier floatx80 floatx80_logn(floatx80 a, float_status *status)
42550067bd1SLaurent Vivier {
426c120391cSRichard Henderson     bool aSign;
42750067bd1SLaurent Vivier     int32_t aExp;
42850067bd1SLaurent Vivier     uint64_t aSig, fSig;
42950067bd1SLaurent Vivier 
430*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
431*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
43250067bd1SLaurent Vivier 
43350067bd1SLaurent Vivier     int32_t compact, j, k, adjk;
43450067bd1SLaurent Vivier     floatx80 fp0, fp1, fp2, fp3, f, logof2, klog2, saveu;
43550067bd1SLaurent Vivier 
43650067bd1SLaurent Vivier     aSig = extractFloatx80Frac(a);
43750067bd1SLaurent Vivier     aExp = extractFloatx80Exp(a);
43850067bd1SLaurent Vivier     aSign = extractFloatx80Sign(a);
43950067bd1SLaurent Vivier 
44050067bd1SLaurent Vivier     if (aExp == 0x7FFF) {
44150067bd1SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
44250067bd1SLaurent Vivier             propagateFloatx80NaNOneArg(a, status);
44350067bd1SLaurent Vivier         }
44450067bd1SLaurent Vivier         if (aSign == 0) {
44550067bd1SLaurent Vivier             return packFloatx80(0, floatx80_infinity.high,
44650067bd1SLaurent Vivier                                 floatx80_infinity.low);
44750067bd1SLaurent Vivier         }
44850067bd1SLaurent Vivier     }
44950067bd1SLaurent Vivier 
45050067bd1SLaurent Vivier     adjk = 0;
45150067bd1SLaurent Vivier 
45250067bd1SLaurent Vivier     if (aExp == 0) {
45350067bd1SLaurent Vivier         if (aSig == 0) { /* zero */
45450067bd1SLaurent Vivier             float_raise(float_flag_divbyzero, status);
45550067bd1SLaurent Vivier             return packFloatx80(1, floatx80_infinity.high,
45650067bd1SLaurent Vivier                                 floatx80_infinity.low);
45750067bd1SLaurent Vivier         }
45850067bd1SLaurent Vivier         if ((aSig & one_sig) == 0) { /* denormal */
45950067bd1SLaurent Vivier             normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
46050067bd1SLaurent Vivier             adjk = -100;
46150067bd1SLaurent Vivier             aExp += 100;
46250067bd1SLaurent Vivier             a = packFloatx80(aSign, aExp, aSig);
46350067bd1SLaurent Vivier         }
46450067bd1SLaurent Vivier     }
46550067bd1SLaurent Vivier 
46650067bd1SLaurent Vivier     if (aSign) {
46750067bd1SLaurent Vivier         float_raise(float_flag_invalid, status);
46850067bd1SLaurent Vivier         return floatx80_default_nan(status);
46950067bd1SLaurent Vivier     }
47050067bd1SLaurent Vivier 
47150067bd1SLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
47250067bd1SLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
47350067bd1SLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
474*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
47550067bd1SLaurent Vivier 
47650067bd1SLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
47750067bd1SLaurent Vivier 
47850067bd1SLaurent Vivier     if (compact < 0x3FFEF07D || compact > 0x3FFF8841) {
47950067bd1SLaurent Vivier         /* |X| < 15/16 or |X| > 17/16 */
48050067bd1SLaurent Vivier         k = aExp - 0x3FFF;
48150067bd1SLaurent Vivier         k += adjk;
48250067bd1SLaurent Vivier         fp1 = int32_to_floatx80(k, status);
48350067bd1SLaurent Vivier 
484e2326300SAlex Bennée         fSig = (aSig & UINT64_C(0xFE00000000000000)) | UINT64_C(0x0100000000000000);
48550067bd1SLaurent Vivier         j = (fSig >> 56) & 0x7E; /* DISPLACEMENT FOR 1/F */
48650067bd1SLaurent Vivier 
48750067bd1SLaurent Vivier         f = packFloatx80(0, 0x3FFF, fSig); /* F */
48850067bd1SLaurent Vivier         fp0 = packFloatx80(0, 0x3FFF, aSig); /* Y */
48950067bd1SLaurent Vivier 
49050067bd1SLaurent Vivier         fp0 = floatx80_sub(fp0, f, status); /* Y-F */
49150067bd1SLaurent Vivier 
49250067bd1SLaurent Vivier         /* LP1CONT1 */
49350067bd1SLaurent Vivier         fp0 = floatx80_mul(fp0, log_tbl[j], status); /* FP0 IS U = (Y-F)/F */
494e2326300SAlex Bennée         logof2 = packFloatx80(0, 0x3FFE, UINT64_C(0xB17217F7D1CF79AC));
49550067bd1SLaurent Vivier         klog2 = floatx80_mul(fp1, logof2, status); /* FP1 IS K*LOG2 */
49650067bd1SLaurent Vivier         fp2 = floatx80_mul(fp0, fp0, status); /* FP2 IS V=U*U */
49750067bd1SLaurent Vivier 
49850067bd1SLaurent Vivier         fp3 = fp2;
49950067bd1SLaurent Vivier         fp1 = fp2;
50050067bd1SLaurent Vivier 
50150067bd1SLaurent Vivier         fp1 = floatx80_mul(fp1, float64_to_floatx80(
50250067bd1SLaurent Vivier                            make_float64(0x3FC2499AB5E4040B), status),
50350067bd1SLaurent Vivier                            status); /* V*A6 */
50450067bd1SLaurent Vivier         fp2 = floatx80_mul(fp2, float64_to_floatx80(
50550067bd1SLaurent Vivier                            make_float64(0xBFC555B5848CB7DB), status),
50650067bd1SLaurent Vivier                            status); /* V*A5 */
50750067bd1SLaurent Vivier         fp1 = floatx80_add(fp1, float64_to_floatx80(
50850067bd1SLaurent Vivier                            make_float64(0x3FC99999987D8730), status),
50950067bd1SLaurent Vivier                            status); /* A4+V*A6 */
51050067bd1SLaurent Vivier         fp2 = floatx80_add(fp2, float64_to_floatx80(
51150067bd1SLaurent Vivier                            make_float64(0xBFCFFFFFFF6F7E97), status),
51250067bd1SLaurent Vivier                            status); /* A3+V*A5 */
51350067bd1SLaurent Vivier         fp1 = floatx80_mul(fp1, fp3, status); /* V*(A4+V*A6) */
51450067bd1SLaurent Vivier         fp2 = floatx80_mul(fp2, fp3, status); /* V*(A3+V*A5) */
51550067bd1SLaurent Vivier         fp1 = floatx80_add(fp1, float64_to_floatx80(
51650067bd1SLaurent Vivier                            make_float64(0x3FD55555555555A4), status),
51750067bd1SLaurent Vivier                            status); /* A2+V*(A4+V*A6) */
51850067bd1SLaurent Vivier         fp2 = floatx80_add(fp2, float64_to_floatx80(
51950067bd1SLaurent Vivier                            make_float64(0xBFE0000000000008), status),
52050067bd1SLaurent Vivier                            status); /* A1+V*(A3+V*A5) */
52150067bd1SLaurent Vivier         fp1 = floatx80_mul(fp1, fp3, status); /* V*(A2+V*(A4+V*A6)) */
52250067bd1SLaurent Vivier         fp2 = floatx80_mul(fp2, fp3, status); /* V*(A1+V*(A3+V*A5)) */
52350067bd1SLaurent Vivier         fp1 = floatx80_mul(fp1, fp0, status); /* U*V*(A2+V*(A4+V*A6)) */
52450067bd1SLaurent Vivier         fp0 = floatx80_add(fp0, fp2, status); /* U+V*(A1+V*(A3+V*A5)) */
52550067bd1SLaurent Vivier 
52650067bd1SLaurent Vivier         fp1 = floatx80_add(fp1, log_tbl[j + 1],
52750067bd1SLaurent Vivier                            status); /* LOG(F)+U*V*(A2+V*(A4+V*A6)) */
52850067bd1SLaurent Vivier         fp0 = floatx80_add(fp0, fp1, status); /* FP0 IS LOG(F) + LOG(1+U) */
52950067bd1SLaurent Vivier 
53050067bd1SLaurent Vivier         status->float_rounding_mode = user_rnd_mode;
53150067bd1SLaurent Vivier         status->floatx80_rounding_precision = user_rnd_prec;
53250067bd1SLaurent Vivier 
53350067bd1SLaurent Vivier         a = floatx80_add(fp0, klog2, status);
53450067bd1SLaurent Vivier 
53550067bd1SLaurent Vivier         float_raise(float_flag_inexact, status);
53650067bd1SLaurent Vivier 
53750067bd1SLaurent Vivier         return a;
53850067bd1SLaurent Vivier     } else { /* |X-1| >= 1/16 */
53950067bd1SLaurent Vivier         fp0 = a;
54050067bd1SLaurent Vivier         fp1 = a;
54150067bd1SLaurent Vivier         fp1 = floatx80_sub(fp1, float32_to_floatx80(make_float32(0x3F800000),
54250067bd1SLaurent Vivier                            status), status); /* FP1 IS X-1 */
54350067bd1SLaurent Vivier         fp0 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
54450067bd1SLaurent Vivier                            status), status); /* FP0 IS X+1 */
54550067bd1SLaurent Vivier         fp1 = floatx80_add(fp1, fp1, status); /* FP1 IS 2(X-1) */
54650067bd1SLaurent Vivier 
54750067bd1SLaurent Vivier         /* LP1CONT2 */
54850067bd1SLaurent Vivier         fp1 = floatx80_div(fp1, fp0, status); /* U */
54950067bd1SLaurent Vivier         saveu = fp1;
55050067bd1SLaurent Vivier         fp0 = floatx80_mul(fp1, fp1, status); /* FP0 IS V = U*U */
55150067bd1SLaurent Vivier         fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS W = V*V */
55250067bd1SLaurent Vivier 
55350067bd1SLaurent Vivier         fp3 = float64_to_floatx80(make_float64(0x3F175496ADD7DAD6),
55450067bd1SLaurent Vivier                                   status); /* B5 */
55550067bd1SLaurent Vivier         fp2 = float64_to_floatx80(make_float64(0x3F3C71C2FE80C7E0),
55650067bd1SLaurent Vivier                                   status); /* B4 */
55750067bd1SLaurent Vivier         fp3 = floatx80_mul(fp3, fp1, status); /* W*B5 */
55850067bd1SLaurent Vivier         fp2 = floatx80_mul(fp2, fp1, status); /* W*B4 */
55950067bd1SLaurent Vivier         fp3 = floatx80_add(fp3, float64_to_floatx80(
56050067bd1SLaurent Vivier                            make_float64(0x3F624924928BCCFF), status),
56150067bd1SLaurent Vivier                            status); /* B3+W*B5 */
56250067bd1SLaurent Vivier         fp2 = floatx80_add(fp2, float64_to_floatx80(
56350067bd1SLaurent Vivier                            make_float64(0x3F899999999995EC), status),
56450067bd1SLaurent Vivier                            status); /* B2+W*B4 */
56550067bd1SLaurent Vivier         fp1 = floatx80_mul(fp1, fp3, status); /* W*(B3+W*B5) */
56650067bd1SLaurent Vivier         fp2 = floatx80_mul(fp2, fp0, status); /* V*(B2+W*B4) */
56750067bd1SLaurent Vivier         fp1 = floatx80_add(fp1, float64_to_floatx80(
56850067bd1SLaurent Vivier                            make_float64(0x3FB5555555555555), status),
56950067bd1SLaurent Vivier                            status); /* B1+W*(B3+W*B5) */
57050067bd1SLaurent Vivier 
57150067bd1SLaurent Vivier         fp0 = floatx80_mul(fp0, saveu, status); /* FP0 IS U*V */
57250067bd1SLaurent Vivier         fp1 = floatx80_add(fp1, fp2, status); /* B1+W*(B3+W*B5) + V*(B2+W*B4) */
57350067bd1SLaurent Vivier         fp0 = floatx80_mul(fp0, fp1,
57450067bd1SLaurent Vivier                            status); /* U*V*([B1+W*(B3+W*B5)] + [V*(B2+W*B4)]) */
57550067bd1SLaurent Vivier 
57650067bd1SLaurent Vivier         status->float_rounding_mode = user_rnd_mode;
57750067bd1SLaurent Vivier         status->floatx80_rounding_precision = user_rnd_prec;
57850067bd1SLaurent Vivier 
57950067bd1SLaurent Vivier         a = floatx80_add(fp0, saveu, status);
58050067bd1SLaurent Vivier 
58150067bd1SLaurent Vivier         /*if (!floatx80_is_zero(a)) { */
58250067bd1SLaurent Vivier             float_raise(float_flag_inexact, status);
58350067bd1SLaurent Vivier         /*} */
58450067bd1SLaurent Vivier 
58550067bd1SLaurent Vivier         return a;
58650067bd1SLaurent Vivier     }
58750067bd1SLaurent Vivier }
588248efb66SLaurent Vivier 
589808d77bcSLucien Murray-Pitts /*
590808d77bcSLucien Murray-Pitts  * Log base 10
591808d77bcSLucien Murray-Pitts  */
592248efb66SLaurent Vivier 
floatx80_log10(floatx80 a,float_status * status)593248efb66SLaurent Vivier floatx80 floatx80_log10(floatx80 a, float_status *status)
594248efb66SLaurent Vivier {
595c120391cSRichard Henderson     bool aSign;
596248efb66SLaurent Vivier     int32_t aExp;
597248efb66SLaurent Vivier     uint64_t aSig;
598248efb66SLaurent Vivier 
599*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
600*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
601248efb66SLaurent Vivier 
602248efb66SLaurent Vivier     floatx80 fp0, fp1;
603248efb66SLaurent Vivier 
604248efb66SLaurent Vivier     aSig = extractFloatx80Frac(a);
605248efb66SLaurent Vivier     aExp = extractFloatx80Exp(a);
606248efb66SLaurent Vivier     aSign = extractFloatx80Sign(a);
607248efb66SLaurent Vivier 
608248efb66SLaurent Vivier     if (aExp == 0x7FFF) {
609248efb66SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
610248efb66SLaurent Vivier             propagateFloatx80NaNOneArg(a, status);
611248efb66SLaurent Vivier         }
612248efb66SLaurent Vivier         if (aSign == 0) {
613248efb66SLaurent Vivier             return packFloatx80(0, floatx80_infinity.high,
614248efb66SLaurent Vivier                                 floatx80_infinity.low);
615248efb66SLaurent Vivier         }
616248efb66SLaurent Vivier     }
617248efb66SLaurent Vivier 
618248efb66SLaurent Vivier     if (aExp == 0 && aSig == 0) {
619248efb66SLaurent Vivier         float_raise(float_flag_divbyzero, status);
620248efb66SLaurent Vivier         return packFloatx80(1, floatx80_infinity.high,
621248efb66SLaurent Vivier                             floatx80_infinity.low);
622248efb66SLaurent Vivier     }
623248efb66SLaurent Vivier 
624248efb66SLaurent Vivier     if (aSign) {
625248efb66SLaurent Vivier         float_raise(float_flag_invalid, status);
626248efb66SLaurent Vivier         return floatx80_default_nan(status);
627248efb66SLaurent Vivier     }
628248efb66SLaurent Vivier 
629248efb66SLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
630248efb66SLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
631248efb66SLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
632*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
633248efb66SLaurent Vivier 
634248efb66SLaurent Vivier     fp0 = floatx80_logn(a, status);
635e2326300SAlex Bennée     fp1 = packFloatx80(0, 0x3FFD, UINT64_C(0xDE5BD8A937287195)); /* INV_L10 */
636248efb66SLaurent Vivier 
637248efb66SLaurent Vivier     status->float_rounding_mode = user_rnd_mode;
638248efb66SLaurent Vivier     status->floatx80_rounding_precision = user_rnd_prec;
639248efb66SLaurent Vivier 
640248efb66SLaurent Vivier     a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L10 */
641248efb66SLaurent Vivier 
642248efb66SLaurent Vivier     float_raise(float_flag_inexact, status);
643248efb66SLaurent Vivier 
644248efb66SLaurent Vivier     return a;
645248efb66SLaurent Vivier }
64667b453edSLaurent Vivier 
647808d77bcSLucien Murray-Pitts /*
648808d77bcSLucien Murray-Pitts  * Log base 2
649808d77bcSLucien Murray-Pitts  */
65067b453edSLaurent Vivier 
floatx80_log2(floatx80 a,float_status * status)65167b453edSLaurent Vivier floatx80 floatx80_log2(floatx80 a, float_status *status)
65267b453edSLaurent Vivier {
653c120391cSRichard Henderson     bool aSign;
65467b453edSLaurent Vivier     int32_t aExp;
65567b453edSLaurent Vivier     uint64_t aSig;
65667b453edSLaurent Vivier 
657*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
658*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
65967b453edSLaurent Vivier 
66067b453edSLaurent Vivier     floatx80 fp0, fp1;
66167b453edSLaurent Vivier 
66267b453edSLaurent Vivier     aSig = extractFloatx80Frac(a);
66367b453edSLaurent Vivier     aExp = extractFloatx80Exp(a);
66467b453edSLaurent Vivier     aSign = extractFloatx80Sign(a);
66567b453edSLaurent Vivier 
66667b453edSLaurent Vivier     if (aExp == 0x7FFF) {
66767b453edSLaurent Vivier         if ((uint64_t) (aSig << 1)) {
66867b453edSLaurent Vivier             propagateFloatx80NaNOneArg(a, status);
66967b453edSLaurent Vivier         }
67067b453edSLaurent Vivier         if (aSign == 0) {
67167b453edSLaurent Vivier             return packFloatx80(0, floatx80_infinity.high,
67267b453edSLaurent Vivier                                 floatx80_infinity.low);
67367b453edSLaurent Vivier         }
67467b453edSLaurent Vivier     }
67567b453edSLaurent Vivier 
67667b453edSLaurent Vivier     if (aExp == 0) {
67767b453edSLaurent Vivier         if (aSig == 0) {
67867b453edSLaurent Vivier             float_raise(float_flag_divbyzero, status);
67967b453edSLaurent Vivier             return packFloatx80(1, floatx80_infinity.high,
68067b453edSLaurent Vivier                                 floatx80_infinity.low);
68167b453edSLaurent Vivier         }
68267b453edSLaurent Vivier         normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
68367b453edSLaurent Vivier     }
68467b453edSLaurent Vivier 
68567b453edSLaurent Vivier     if (aSign) {
68667b453edSLaurent Vivier         float_raise(float_flag_invalid, status);
68767b453edSLaurent Vivier         return floatx80_default_nan(status);
68867b453edSLaurent Vivier     }
68967b453edSLaurent Vivier 
69067b453edSLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
69167b453edSLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
69267b453edSLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
693*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
69467b453edSLaurent Vivier 
69567b453edSLaurent Vivier     if (aSig == one_sig) { /* X is 2^k */
69667b453edSLaurent Vivier         status->float_rounding_mode = user_rnd_mode;
69767b453edSLaurent Vivier         status->floatx80_rounding_precision = user_rnd_prec;
69867b453edSLaurent Vivier 
69967b453edSLaurent Vivier         a = int32_to_floatx80(aExp - 0x3FFF, status);
70067b453edSLaurent Vivier     } else {
70167b453edSLaurent Vivier         fp0 = floatx80_logn(a, status);
702e2326300SAlex Bennée         fp1 = packFloatx80(0, 0x3FFF, UINT64_C(0xB8AA3B295C17F0BC)); /* INV_L2 */
70367b453edSLaurent Vivier 
70467b453edSLaurent Vivier         status->float_rounding_mode = user_rnd_mode;
70567b453edSLaurent Vivier         status->floatx80_rounding_precision = user_rnd_prec;
70667b453edSLaurent Vivier 
70767b453edSLaurent Vivier         a = floatx80_mul(fp0, fp1, status); /* LOGN(X)*INV_L2 */
70867b453edSLaurent Vivier     }
70967b453edSLaurent Vivier 
71067b453edSLaurent Vivier     float_raise(float_flag_inexact, status);
71167b453edSLaurent Vivier 
71267b453edSLaurent Vivier     return a;
71367b453edSLaurent Vivier }
71440ad0873SLaurent Vivier 
715808d77bcSLucien Murray-Pitts /*
716808d77bcSLucien Murray-Pitts  * e to x
717808d77bcSLucien Murray-Pitts  */
71840ad0873SLaurent Vivier 
floatx80_etox(floatx80 a,float_status * status)71940ad0873SLaurent Vivier floatx80 floatx80_etox(floatx80 a, float_status *status)
72040ad0873SLaurent Vivier {
721c120391cSRichard Henderson     bool aSign;
72240ad0873SLaurent Vivier     int32_t aExp;
72340ad0873SLaurent Vivier     uint64_t aSig;
72440ad0873SLaurent Vivier 
725*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
726*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
72740ad0873SLaurent Vivier 
72840ad0873SLaurent Vivier     int32_t compact, n, j, k, m, m1;
72940ad0873SLaurent Vivier     floatx80 fp0, fp1, fp2, fp3, l2, scale, adjscale;
730c120391cSRichard Henderson     bool adjflag;
73140ad0873SLaurent Vivier 
73240ad0873SLaurent Vivier     aSig = extractFloatx80Frac(a);
73340ad0873SLaurent Vivier     aExp = extractFloatx80Exp(a);
73440ad0873SLaurent Vivier     aSign = extractFloatx80Sign(a);
73540ad0873SLaurent Vivier 
73640ad0873SLaurent Vivier     if (aExp == 0x7FFF) {
73740ad0873SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
73840ad0873SLaurent Vivier             return propagateFloatx80NaNOneArg(a, status);
73940ad0873SLaurent Vivier         }
74040ad0873SLaurent Vivier         if (aSign) {
74140ad0873SLaurent Vivier             return packFloatx80(0, 0, 0);
74240ad0873SLaurent Vivier         }
74340ad0873SLaurent Vivier         return packFloatx80(0, floatx80_infinity.high,
74440ad0873SLaurent Vivier                             floatx80_infinity.low);
74540ad0873SLaurent Vivier     }
74640ad0873SLaurent Vivier 
74740ad0873SLaurent Vivier     if (aExp == 0 && aSig == 0) {
74840ad0873SLaurent Vivier         return packFloatx80(0, one_exp, one_sig);
74940ad0873SLaurent Vivier     }
75040ad0873SLaurent Vivier 
75140ad0873SLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
75240ad0873SLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
75340ad0873SLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
754*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
75540ad0873SLaurent Vivier 
75640ad0873SLaurent Vivier     adjflag = 0;
75740ad0873SLaurent Vivier 
75840ad0873SLaurent Vivier     if (aExp >= 0x3FBE) { /* |X| >= 2^(-65) */
75940ad0873SLaurent Vivier         compact = floatx80_make_compact(aExp, aSig);
76040ad0873SLaurent Vivier 
76140ad0873SLaurent Vivier         if (compact < 0x400CB167) { /* |X| < 16380 log2 */
76240ad0873SLaurent Vivier             fp0 = a;
76340ad0873SLaurent Vivier             fp1 = a;
76440ad0873SLaurent Vivier             fp0 = floatx80_mul(fp0, float32_to_floatx80(
76540ad0873SLaurent Vivier                                make_float32(0x42B8AA3B), status),
76640ad0873SLaurent Vivier                                status); /* 64/log2 * X */
76740ad0873SLaurent Vivier             adjflag = 0;
76840ad0873SLaurent Vivier             n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
76940ad0873SLaurent Vivier             fp0 = int32_to_floatx80(n, status);
77040ad0873SLaurent Vivier 
77140ad0873SLaurent Vivier             j = n & 0x3F; /* J = N mod 64 */
77240ad0873SLaurent Vivier             m = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
77340ad0873SLaurent Vivier             if (n < 0 && j) {
774808d77bcSLucien Murray-Pitts                 /*
775808d77bcSLucien Murray-Pitts                  * arithmetic right shift is division and
77640ad0873SLaurent Vivier                  * round towards minus infinity
77740ad0873SLaurent Vivier                  */
77840ad0873SLaurent Vivier                 m--;
77940ad0873SLaurent Vivier             }
78040ad0873SLaurent Vivier             m += 0x3FFF; /* biased exponent of 2^(M) */
78140ad0873SLaurent Vivier 
78240ad0873SLaurent Vivier         expcont1:
78340ad0873SLaurent Vivier             fp2 = fp0; /* N */
78440ad0873SLaurent Vivier             fp0 = floatx80_mul(fp0, float32_to_floatx80(
78540ad0873SLaurent Vivier                                make_float32(0xBC317218), status),
78640ad0873SLaurent Vivier                                status); /* N * L1, L1 = lead(-log2/64) */
787e2326300SAlex Bennée             l2 = packFloatx80(0, 0x3FDC, UINT64_C(0x82E308654361C4C6));
78840ad0873SLaurent Vivier             fp2 = floatx80_mul(fp2, l2, status); /* N * L2, L1+L2 = -log2/64 */
78940ad0873SLaurent Vivier             fp0 = floatx80_add(fp0, fp1, status); /* X + N*L1 */
79040ad0873SLaurent Vivier             fp0 = floatx80_add(fp0, fp2, status); /* R */
79140ad0873SLaurent Vivier 
79240ad0873SLaurent Vivier             fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
79340ad0873SLaurent Vivier             fp2 = float32_to_floatx80(make_float32(0x3AB60B70),
79440ad0873SLaurent Vivier                                       status); /* A5 */
79540ad0873SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*A5 */
79640ad0873SLaurent Vivier             fp3 = floatx80_mul(float32_to_floatx80(make_float32(0x3C088895),
79740ad0873SLaurent Vivier                                status), fp1,
79840ad0873SLaurent Vivier                                status); /* fp3 is S*A4 */
79940ad0873SLaurent Vivier             fp2 = floatx80_add(fp2, float64_to_floatx80(make_float64(
80040ad0873SLaurent Vivier                                0x3FA5555555554431), status),
80140ad0873SLaurent Vivier                                status); /* fp2 is A3+S*A5 */
80240ad0873SLaurent Vivier             fp3 = floatx80_add(fp3, float64_to_floatx80(make_float64(
80340ad0873SLaurent Vivier                                0x3FC5555555554018), status),
80440ad0873SLaurent Vivier                                status); /* fp3 is A2+S*A4 */
80540ad0873SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*(A3+S*A5) */
80640ad0873SLaurent Vivier             fp3 = floatx80_mul(fp3, fp1, status); /* fp3 is S*(A2+S*A4) */
80740ad0873SLaurent Vivier             fp2 = floatx80_add(fp2, float32_to_floatx80(
80840ad0873SLaurent Vivier                                make_float32(0x3F000000), status),
80940ad0873SLaurent Vivier                                status); /* fp2 is A1+S*(A3+S*A5) */
81040ad0873SLaurent Vivier             fp3 = floatx80_mul(fp3, fp0, status); /* fp3 IS R*S*(A2+S*A4) */
81140ad0873SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1,
81240ad0873SLaurent Vivier                                status); /* fp2 IS S*(A1+S*(A3+S*A5)) */
81340ad0873SLaurent Vivier             fp0 = floatx80_add(fp0, fp3, status); /* fp0 IS R+R*S*(A2+S*A4) */
81440ad0873SLaurent Vivier             fp0 = floatx80_add(fp0, fp2, status); /* fp0 IS EXP(R) - 1 */
81540ad0873SLaurent Vivier 
81640ad0873SLaurent Vivier             fp1 = exp_tbl[j];
81740ad0873SLaurent Vivier             fp0 = floatx80_mul(fp0, fp1, status); /* 2^(J/64)*(Exp(R)-1) */
81840ad0873SLaurent Vivier             fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j], status),
81940ad0873SLaurent Vivier                                status); /* accurate 2^(J/64) */
82040ad0873SLaurent Vivier             fp0 = floatx80_add(fp0, fp1,
82140ad0873SLaurent Vivier                                status); /* 2^(J/64) + 2^(J/64)*(Exp(R)-1) */
82240ad0873SLaurent Vivier 
82340ad0873SLaurent Vivier             scale = packFloatx80(0, m, one_sig);
82440ad0873SLaurent Vivier             if (adjflag) {
82540ad0873SLaurent Vivier                 adjscale = packFloatx80(0, m1, one_sig);
82640ad0873SLaurent Vivier                 fp0 = floatx80_mul(fp0, adjscale, status);
82740ad0873SLaurent Vivier             }
82840ad0873SLaurent Vivier 
82940ad0873SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
83040ad0873SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
83140ad0873SLaurent Vivier 
83240ad0873SLaurent Vivier             a = floatx80_mul(fp0, scale, status);
83340ad0873SLaurent Vivier 
83440ad0873SLaurent Vivier             float_raise(float_flag_inexact, status);
83540ad0873SLaurent Vivier 
83640ad0873SLaurent Vivier             return a;
83740ad0873SLaurent Vivier         } else { /* |X| >= 16380 log2 */
83840ad0873SLaurent Vivier             if (compact > 0x400CB27C) { /* |X| >= 16480 log2 */
83940ad0873SLaurent Vivier                 status->float_rounding_mode = user_rnd_mode;
84040ad0873SLaurent Vivier                 status->floatx80_rounding_precision = user_rnd_prec;
84140ad0873SLaurent Vivier                 if (aSign) {
84240ad0873SLaurent Vivier                     a = roundAndPackFloatx80(
84340ad0873SLaurent Vivier                                            status->floatx80_rounding_precision,
84440ad0873SLaurent Vivier                                            0, -0x1000, aSig, 0, status);
84540ad0873SLaurent Vivier                 } else {
84640ad0873SLaurent Vivier                     a = roundAndPackFloatx80(
84740ad0873SLaurent Vivier                                            status->floatx80_rounding_precision,
84840ad0873SLaurent Vivier                                            0, 0x8000, aSig, 0, status);
84940ad0873SLaurent Vivier                 }
85040ad0873SLaurent Vivier                 float_raise(float_flag_inexact, status);
85140ad0873SLaurent Vivier 
85240ad0873SLaurent Vivier                 return a;
85340ad0873SLaurent Vivier             } else {
85440ad0873SLaurent Vivier                 fp0 = a;
85540ad0873SLaurent Vivier                 fp1 = a;
85640ad0873SLaurent Vivier                 fp0 = floatx80_mul(fp0, float32_to_floatx80(
85740ad0873SLaurent Vivier                                    make_float32(0x42B8AA3B), status),
85840ad0873SLaurent Vivier                                    status); /* 64/log2 * X */
85940ad0873SLaurent Vivier                 adjflag = 1;
86040ad0873SLaurent Vivier                 n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
86140ad0873SLaurent Vivier                 fp0 = int32_to_floatx80(n, status);
86240ad0873SLaurent Vivier 
86340ad0873SLaurent Vivier                 j = n & 0x3F; /* J = N mod 64 */
86440ad0873SLaurent Vivier                 /* NOTE: this is really arithmetic right shift by 6 */
86540ad0873SLaurent Vivier                 k = n / 64;
86640ad0873SLaurent Vivier                 if (n < 0 && j) {
86740ad0873SLaurent Vivier                     /* arithmetic right shift is division and
86840ad0873SLaurent Vivier                      * round towards minus infinity
86940ad0873SLaurent Vivier                      */
87040ad0873SLaurent Vivier                     k--;
87140ad0873SLaurent Vivier                 }
87240ad0873SLaurent Vivier                 /* NOTE: this is really arithmetic right shift by 1 */
87340ad0873SLaurent Vivier                 m1 = k / 2;
87440ad0873SLaurent Vivier                 if (k < 0 && (k & 1)) {
87540ad0873SLaurent Vivier                     /* arithmetic right shift is division and
87640ad0873SLaurent Vivier                      * round towards minus infinity
87740ad0873SLaurent Vivier                      */
87840ad0873SLaurent Vivier                     m1--;
87940ad0873SLaurent Vivier                 }
88040ad0873SLaurent Vivier                 m = k - m1;
88140ad0873SLaurent Vivier                 m1 += 0x3FFF; /* biased exponent of 2^(M1) */
88240ad0873SLaurent Vivier                 m += 0x3FFF; /* biased exponent of 2^(M) */
88340ad0873SLaurent Vivier 
88440ad0873SLaurent Vivier                 goto expcont1;
88540ad0873SLaurent Vivier             }
88640ad0873SLaurent Vivier         }
88740ad0873SLaurent Vivier     } else { /* |X| < 2^(-65) */
88840ad0873SLaurent Vivier         status->float_rounding_mode = user_rnd_mode;
88940ad0873SLaurent Vivier         status->floatx80_rounding_precision = user_rnd_prec;
89040ad0873SLaurent Vivier 
89140ad0873SLaurent Vivier         a = floatx80_add(a, float32_to_floatx80(make_float32(0x3F800000),
89240ad0873SLaurent Vivier                          status), status); /* 1 + X */
89340ad0873SLaurent Vivier 
89440ad0873SLaurent Vivier         float_raise(float_flag_inexact, status);
89540ad0873SLaurent Vivier 
89640ad0873SLaurent Vivier         return a;
89740ad0873SLaurent Vivier     }
89840ad0873SLaurent Vivier }
899068f1615SLaurent Vivier 
900808d77bcSLucien Murray-Pitts /*
901808d77bcSLucien Murray-Pitts  * 2 to x
902808d77bcSLucien Murray-Pitts  */
903068f1615SLaurent Vivier 
floatx80_twotox(floatx80 a,float_status * status)904068f1615SLaurent Vivier floatx80 floatx80_twotox(floatx80 a, float_status *status)
905068f1615SLaurent Vivier {
906c120391cSRichard Henderson     bool aSign;
907068f1615SLaurent Vivier     int32_t aExp;
908068f1615SLaurent Vivier     uint64_t aSig;
909068f1615SLaurent Vivier 
910*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
911*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
912068f1615SLaurent Vivier 
913068f1615SLaurent Vivier     int32_t compact, n, j, l, m, m1;
914068f1615SLaurent Vivier     floatx80 fp0, fp1, fp2, fp3, adjfact, fact1, fact2;
915068f1615SLaurent Vivier 
916068f1615SLaurent Vivier     aSig = extractFloatx80Frac(a);
917068f1615SLaurent Vivier     aExp = extractFloatx80Exp(a);
918068f1615SLaurent Vivier     aSign = extractFloatx80Sign(a);
919068f1615SLaurent Vivier 
920068f1615SLaurent Vivier     if (aExp == 0x7FFF) {
921068f1615SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
922068f1615SLaurent Vivier             return propagateFloatx80NaNOneArg(a, status);
923068f1615SLaurent Vivier         }
924068f1615SLaurent Vivier         if (aSign) {
925068f1615SLaurent Vivier             return packFloatx80(0, 0, 0);
926068f1615SLaurent Vivier         }
927068f1615SLaurent Vivier         return packFloatx80(0, floatx80_infinity.high,
928068f1615SLaurent Vivier                             floatx80_infinity.low);
929068f1615SLaurent Vivier     }
930068f1615SLaurent Vivier 
931068f1615SLaurent Vivier     if (aExp == 0 && aSig == 0) {
932068f1615SLaurent Vivier         return packFloatx80(0, one_exp, one_sig);
933068f1615SLaurent Vivier     }
934068f1615SLaurent Vivier 
935068f1615SLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
936068f1615SLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
937068f1615SLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
938*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
939068f1615SLaurent Vivier 
940068f1615SLaurent Vivier     fp0 = a;
941068f1615SLaurent Vivier 
942068f1615SLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
943068f1615SLaurent Vivier 
944068f1615SLaurent Vivier     if (compact < 0x3FB98000 || compact > 0x400D80C0) {
945068f1615SLaurent Vivier         /* |X| > 16480 or |X| < 2^(-70) */
946068f1615SLaurent Vivier         if (compact > 0x3FFF8000) { /* |X| > 16480 */
947068f1615SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
948068f1615SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
949068f1615SLaurent Vivier 
950068f1615SLaurent Vivier             if (aSign) {
951068f1615SLaurent Vivier                 return roundAndPackFloatx80(status->floatx80_rounding_precision,
952068f1615SLaurent Vivier                                             0, -0x1000, aSig, 0, status);
953068f1615SLaurent Vivier             } else {
954068f1615SLaurent Vivier                 return roundAndPackFloatx80(status->floatx80_rounding_precision,
955068f1615SLaurent Vivier                                             0, 0x8000, aSig, 0, status);
956068f1615SLaurent Vivier             }
957068f1615SLaurent Vivier         } else { /* |X| < 2^(-70) */
958068f1615SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
959068f1615SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
960068f1615SLaurent Vivier 
961068f1615SLaurent Vivier             a = floatx80_add(fp0, float32_to_floatx80(
962068f1615SLaurent Vivier                              make_float32(0x3F800000), status),
963068f1615SLaurent Vivier                              status); /* 1 + X */
964068f1615SLaurent Vivier 
965068f1615SLaurent Vivier             float_raise(float_flag_inexact, status);
966068f1615SLaurent Vivier 
967068f1615SLaurent Vivier             return a;
968068f1615SLaurent Vivier         }
969068f1615SLaurent Vivier     } else { /* 2^(-70) <= |X| <= 16480 */
970068f1615SLaurent Vivier         fp1 = fp0; /* X */
971068f1615SLaurent Vivier         fp1 = floatx80_mul(fp1, float32_to_floatx80(
972068f1615SLaurent Vivier                            make_float32(0x42800000), status),
973068f1615SLaurent Vivier                            status); /* X * 64 */
974068f1615SLaurent Vivier         n = floatx80_to_int32(fp1, status);
975068f1615SLaurent Vivier         fp1 = int32_to_floatx80(n, status);
976068f1615SLaurent Vivier         j = n & 0x3F;
977068f1615SLaurent Vivier         l = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
978068f1615SLaurent Vivier         if (n < 0 && j) {
979808d77bcSLucien Murray-Pitts             /*
980808d77bcSLucien Murray-Pitts              * arithmetic right shift is division and
981068f1615SLaurent Vivier              * round towards minus infinity
982068f1615SLaurent Vivier              */
983068f1615SLaurent Vivier             l--;
984068f1615SLaurent Vivier         }
985068f1615SLaurent Vivier         m = l / 2; /* NOTE: this is really arithmetic right shift by 1 */
986068f1615SLaurent Vivier         if (l < 0 && (l & 1)) {
987808d77bcSLucien Murray-Pitts             /*
988808d77bcSLucien Murray-Pitts              * arithmetic right shift is division and
989068f1615SLaurent Vivier              * round towards minus infinity
990068f1615SLaurent Vivier              */
991068f1615SLaurent Vivier             m--;
992068f1615SLaurent Vivier         }
993068f1615SLaurent Vivier         m1 = l - m;
994068f1615SLaurent Vivier         m1 += 0x3FFF; /* ADJFACT IS 2^(M') */
995068f1615SLaurent Vivier 
996068f1615SLaurent Vivier         adjfact = packFloatx80(0, m1, one_sig);
997068f1615SLaurent Vivier         fact1 = exp2_tbl[j];
998068f1615SLaurent Vivier         fact1.high += m;
999068f1615SLaurent Vivier         fact2.high = exp2_tbl2[j] >> 16;
1000068f1615SLaurent Vivier         fact2.high += m;
1001068f1615SLaurent Vivier         fact2.low = (uint64_t)(exp2_tbl2[j] & 0xFFFF);
1002068f1615SLaurent Vivier         fact2.low <<= 48;
1003068f1615SLaurent Vivier 
1004068f1615SLaurent Vivier         fp1 = floatx80_mul(fp1, float32_to_floatx80(
1005068f1615SLaurent Vivier                            make_float32(0x3C800000), status),
1006068f1615SLaurent Vivier                            status); /* (1/64)*N */
1007068f1615SLaurent Vivier         fp0 = floatx80_sub(fp0, fp1, status); /* X - (1/64)*INT(64 X) */
1008e2326300SAlex Bennée         fp2 = packFloatx80(0, 0x3FFE, UINT64_C(0xB17217F7D1CF79AC)); /* LOG2 */
1009068f1615SLaurent Vivier         fp0 = floatx80_mul(fp0, fp2, status); /* R */
1010068f1615SLaurent Vivier 
1011068f1615SLaurent Vivier         /* EXPR */
1012068f1615SLaurent Vivier         fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
1013068f1615SLaurent Vivier         fp2 = float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
1014068f1615SLaurent Vivier                                   status); /* A5 */
1015068f1615SLaurent Vivier         fp3 = float64_to_floatx80(make_float64(0x3F811112302C712C),
1016068f1615SLaurent Vivier                                   status); /* A4 */
1017068f1615SLaurent Vivier         fp2 = floatx80_mul(fp2, fp1, status); /* S*A5 */
1018068f1615SLaurent Vivier         fp3 = floatx80_mul(fp3, fp1, status); /* S*A4 */
1019068f1615SLaurent Vivier         fp2 = floatx80_add(fp2, float64_to_floatx80(
1020068f1615SLaurent Vivier                            make_float64(0x3FA5555555554CC1), status),
1021068f1615SLaurent Vivier                            status); /* A3+S*A5 */
1022068f1615SLaurent Vivier         fp3 = floatx80_add(fp3, float64_to_floatx80(
1023068f1615SLaurent Vivier                            make_float64(0x3FC5555555554A54), status),
1024068f1615SLaurent Vivier                            status); /* A2+S*A4 */
1025068f1615SLaurent Vivier         fp2 = floatx80_mul(fp2, fp1, status); /* S*(A3+S*A5) */
1026068f1615SLaurent Vivier         fp3 = floatx80_mul(fp3, fp1, status); /* S*(A2+S*A4) */
1027068f1615SLaurent Vivier         fp2 = floatx80_add(fp2, float64_to_floatx80(
1028068f1615SLaurent Vivier                            make_float64(0x3FE0000000000000), status),
1029068f1615SLaurent Vivier                            status); /* A1+S*(A3+S*A5) */
1030068f1615SLaurent Vivier         fp3 = floatx80_mul(fp3, fp0, status); /* R*S*(A2+S*A4) */
1031068f1615SLaurent Vivier 
1032068f1615SLaurent Vivier         fp2 = floatx80_mul(fp2, fp1, status); /* S*(A1+S*(A3+S*A5)) */
1033068f1615SLaurent Vivier         fp0 = floatx80_add(fp0, fp3, status); /* R+R*S*(A2+S*A4) */
1034068f1615SLaurent Vivier         fp0 = floatx80_add(fp0, fp2, status); /* EXP(R) - 1 */
1035068f1615SLaurent Vivier 
1036068f1615SLaurent Vivier         fp0 = floatx80_mul(fp0, fact1, status);
1037068f1615SLaurent Vivier         fp0 = floatx80_add(fp0, fact2, status);
1038068f1615SLaurent Vivier         fp0 = floatx80_add(fp0, fact1, status);
1039068f1615SLaurent Vivier 
1040068f1615SLaurent Vivier         status->float_rounding_mode = user_rnd_mode;
1041068f1615SLaurent Vivier         status->floatx80_rounding_precision = user_rnd_prec;
1042068f1615SLaurent Vivier 
1043068f1615SLaurent Vivier         a = floatx80_mul(fp0, adjfact, status);
1044068f1615SLaurent Vivier 
1045068f1615SLaurent Vivier         float_raise(float_flag_inexact, status);
1046068f1615SLaurent Vivier 
1047068f1615SLaurent Vivier         return a;
1048068f1615SLaurent Vivier     }
1049068f1615SLaurent Vivier }
10506c25be6eSLaurent Vivier 
1051808d77bcSLucien Murray-Pitts /*
1052808d77bcSLucien Murray-Pitts  * 10 to x
1053808d77bcSLucien Murray-Pitts  */
10546c25be6eSLaurent Vivier 
floatx80_tentox(floatx80 a,float_status * status)10556c25be6eSLaurent Vivier floatx80 floatx80_tentox(floatx80 a, float_status *status)
10566c25be6eSLaurent Vivier {
1057c120391cSRichard Henderson     bool aSign;
10586c25be6eSLaurent Vivier     int32_t aExp;
10596c25be6eSLaurent Vivier     uint64_t aSig;
10606c25be6eSLaurent Vivier 
1061*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
1062*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
10636c25be6eSLaurent Vivier 
10646c25be6eSLaurent Vivier     int32_t compact, n, j, l, m, m1;
10656c25be6eSLaurent Vivier     floatx80 fp0, fp1, fp2, fp3, adjfact, fact1, fact2;
10666c25be6eSLaurent Vivier 
10676c25be6eSLaurent Vivier     aSig = extractFloatx80Frac(a);
10686c25be6eSLaurent Vivier     aExp = extractFloatx80Exp(a);
10696c25be6eSLaurent Vivier     aSign = extractFloatx80Sign(a);
10706c25be6eSLaurent Vivier 
10716c25be6eSLaurent Vivier     if (aExp == 0x7FFF) {
10726c25be6eSLaurent Vivier         if ((uint64_t) (aSig << 1)) {
10736c25be6eSLaurent Vivier             return propagateFloatx80NaNOneArg(a, status);
10746c25be6eSLaurent Vivier         }
10756c25be6eSLaurent Vivier         if (aSign) {
10766c25be6eSLaurent Vivier             return packFloatx80(0, 0, 0);
10776c25be6eSLaurent Vivier         }
10786c25be6eSLaurent Vivier         return packFloatx80(0, floatx80_infinity.high,
10796c25be6eSLaurent Vivier                             floatx80_infinity.low);
10806c25be6eSLaurent Vivier     }
10816c25be6eSLaurent Vivier 
10826c25be6eSLaurent Vivier     if (aExp == 0 && aSig == 0) {
10836c25be6eSLaurent Vivier         return packFloatx80(0, one_exp, one_sig);
10846c25be6eSLaurent Vivier     }
10856c25be6eSLaurent Vivier 
10866c25be6eSLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
10876c25be6eSLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
10886c25be6eSLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
1089*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
10906c25be6eSLaurent Vivier 
10916c25be6eSLaurent Vivier     fp0 = a;
10926c25be6eSLaurent Vivier 
10936c25be6eSLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
10946c25be6eSLaurent Vivier 
10956c25be6eSLaurent Vivier     if (compact < 0x3FB98000 || compact > 0x400B9B07) {
10966c25be6eSLaurent Vivier         /* |X| > 16480 LOG2/LOG10 or |X| < 2^(-70) */
10976c25be6eSLaurent Vivier         if (compact > 0x3FFF8000) { /* |X| > 16480 */
10986c25be6eSLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
10996c25be6eSLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
11006c25be6eSLaurent Vivier 
11016c25be6eSLaurent Vivier             if (aSign) {
11026c25be6eSLaurent Vivier                 return roundAndPackFloatx80(status->floatx80_rounding_precision,
11036c25be6eSLaurent Vivier                                             0, -0x1000, aSig, 0, status);
11046c25be6eSLaurent Vivier             } else {
11056c25be6eSLaurent Vivier                 return roundAndPackFloatx80(status->floatx80_rounding_precision,
11066c25be6eSLaurent Vivier                                             0, 0x8000, aSig, 0, status);
11076c25be6eSLaurent Vivier             }
11086c25be6eSLaurent Vivier         } else { /* |X| < 2^(-70) */
11096c25be6eSLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
11106c25be6eSLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
11116c25be6eSLaurent Vivier 
11126c25be6eSLaurent Vivier             a = floatx80_add(fp0, float32_to_floatx80(
11136c25be6eSLaurent Vivier                              make_float32(0x3F800000), status),
11146c25be6eSLaurent Vivier                              status); /* 1 + X */
11156c25be6eSLaurent Vivier 
11166c25be6eSLaurent Vivier             float_raise(float_flag_inexact, status);
11176c25be6eSLaurent Vivier 
11186c25be6eSLaurent Vivier             return a;
11196c25be6eSLaurent Vivier         }
11206c25be6eSLaurent Vivier     } else { /* 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10 */
11216c25be6eSLaurent Vivier         fp1 = fp0; /* X */
11226c25be6eSLaurent Vivier         fp1 = floatx80_mul(fp1, float64_to_floatx80(
11236c25be6eSLaurent Vivier                            make_float64(0x406A934F0979A371),
11246c25be6eSLaurent Vivier                            status), status); /* X*64*LOG10/LOG2 */
11256c25be6eSLaurent Vivier         n = floatx80_to_int32(fp1, status); /* N=INT(X*64*LOG10/LOG2) */
11266c25be6eSLaurent Vivier         fp1 = int32_to_floatx80(n, status);
11276c25be6eSLaurent Vivier 
11286c25be6eSLaurent Vivier         j = n & 0x3F;
11296c25be6eSLaurent Vivier         l = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
11306c25be6eSLaurent Vivier         if (n < 0 && j) {
1131808d77bcSLucien Murray-Pitts             /*
1132808d77bcSLucien Murray-Pitts              * arithmetic right shift is division and
11336c25be6eSLaurent Vivier              * round towards minus infinity
11346c25be6eSLaurent Vivier              */
11356c25be6eSLaurent Vivier             l--;
11366c25be6eSLaurent Vivier         }
11376c25be6eSLaurent Vivier         m = l / 2; /* NOTE: this is really arithmetic right shift by 1 */
11386c25be6eSLaurent Vivier         if (l < 0 && (l & 1)) {
1139808d77bcSLucien Murray-Pitts             /*
1140808d77bcSLucien Murray-Pitts              * arithmetic right shift is division and
11416c25be6eSLaurent Vivier              * round towards minus infinity
11426c25be6eSLaurent Vivier              */
11436c25be6eSLaurent Vivier             m--;
11446c25be6eSLaurent Vivier         }
11456c25be6eSLaurent Vivier         m1 = l - m;
11466c25be6eSLaurent Vivier         m1 += 0x3FFF; /* ADJFACT IS 2^(M') */
11476c25be6eSLaurent Vivier 
11486c25be6eSLaurent Vivier         adjfact = packFloatx80(0, m1, one_sig);
11496c25be6eSLaurent Vivier         fact1 = exp2_tbl[j];
11506c25be6eSLaurent Vivier         fact1.high += m;
11516c25be6eSLaurent Vivier         fact2.high = exp2_tbl2[j] >> 16;
11526c25be6eSLaurent Vivier         fact2.high += m;
11536c25be6eSLaurent Vivier         fact2.low = (uint64_t)(exp2_tbl2[j] & 0xFFFF);
11546c25be6eSLaurent Vivier         fact2.low <<= 48;
11556c25be6eSLaurent Vivier 
11566c25be6eSLaurent Vivier         fp2 = fp1; /* N */
11576c25be6eSLaurent Vivier         fp1 = floatx80_mul(fp1, float64_to_floatx80(
11586c25be6eSLaurent Vivier                            make_float64(0x3F734413509F8000), status),
11596c25be6eSLaurent Vivier                            status); /* N*(LOG2/64LOG10)_LEAD */
1160e2326300SAlex Bennée         fp3 = packFloatx80(1, 0x3FCD, UINT64_C(0xC0219DC1DA994FD2));
11616c25be6eSLaurent Vivier         fp2 = floatx80_mul(fp2, fp3, status); /* N*(LOG2/64LOG10)_TRAIL */
11626c25be6eSLaurent Vivier         fp0 = floatx80_sub(fp0, fp1, status); /* X - N L_LEAD */
11636c25be6eSLaurent Vivier         fp0 = floatx80_sub(fp0, fp2, status); /* X - N L_TRAIL */
1164e2326300SAlex Bennée         fp2 = packFloatx80(0, 0x4000, UINT64_C(0x935D8DDDAAA8AC17)); /* LOG10 */
11656c25be6eSLaurent Vivier         fp0 = floatx80_mul(fp0, fp2, status); /* R */
11666c25be6eSLaurent Vivier 
11676c25be6eSLaurent Vivier         /* EXPR */
11686c25be6eSLaurent Vivier         fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
11696c25be6eSLaurent Vivier         fp2 = float64_to_floatx80(make_float64(0x3F56C16D6F7BD0B2),
11706c25be6eSLaurent Vivier                                   status); /* A5 */
11716c25be6eSLaurent Vivier         fp3 = float64_to_floatx80(make_float64(0x3F811112302C712C),
11726c25be6eSLaurent Vivier                                   status); /* A4 */
11736c25be6eSLaurent Vivier         fp2 = floatx80_mul(fp2, fp1, status); /* S*A5 */
11746c25be6eSLaurent Vivier         fp3 = floatx80_mul(fp3, fp1, status); /* S*A4 */
11756c25be6eSLaurent Vivier         fp2 = floatx80_add(fp2, float64_to_floatx80(
11766c25be6eSLaurent Vivier                            make_float64(0x3FA5555555554CC1), status),
11776c25be6eSLaurent Vivier                            status); /* A3+S*A5 */
11786c25be6eSLaurent Vivier         fp3 = floatx80_add(fp3, float64_to_floatx80(
11796c25be6eSLaurent Vivier                            make_float64(0x3FC5555555554A54), status),
11806c25be6eSLaurent Vivier                            status); /* A2+S*A4 */
11816c25be6eSLaurent Vivier         fp2 = floatx80_mul(fp2, fp1, status); /* S*(A3+S*A5) */
11826c25be6eSLaurent Vivier         fp3 = floatx80_mul(fp3, fp1, status); /* S*(A2+S*A4) */
11836c25be6eSLaurent Vivier         fp2 = floatx80_add(fp2, float64_to_floatx80(
11846c25be6eSLaurent Vivier                            make_float64(0x3FE0000000000000), status),
11856c25be6eSLaurent Vivier                            status); /* A1+S*(A3+S*A5) */
11866c25be6eSLaurent Vivier         fp3 = floatx80_mul(fp3, fp0, status); /* R*S*(A2+S*A4) */
11876c25be6eSLaurent Vivier 
11886c25be6eSLaurent Vivier         fp2 = floatx80_mul(fp2, fp1, status); /* S*(A1+S*(A3+S*A5)) */
11896c25be6eSLaurent Vivier         fp0 = floatx80_add(fp0, fp3, status); /* R+R*S*(A2+S*A4) */
11906c25be6eSLaurent Vivier         fp0 = floatx80_add(fp0, fp2, status); /* EXP(R) - 1 */
11916c25be6eSLaurent Vivier 
11926c25be6eSLaurent Vivier         fp0 = floatx80_mul(fp0, fact1, status);
11936c25be6eSLaurent Vivier         fp0 = floatx80_add(fp0, fact2, status);
11946c25be6eSLaurent Vivier         fp0 = floatx80_add(fp0, fact1, status);
11956c25be6eSLaurent Vivier 
11966c25be6eSLaurent Vivier         status->float_rounding_mode = user_rnd_mode;
11976c25be6eSLaurent Vivier         status->floatx80_rounding_precision = user_rnd_prec;
11986c25be6eSLaurent Vivier 
11996c25be6eSLaurent Vivier         a = floatx80_mul(fp0, adjfact, status);
12006c25be6eSLaurent Vivier 
12016c25be6eSLaurent Vivier         float_raise(float_flag_inexact, status);
12026c25be6eSLaurent Vivier 
12036c25be6eSLaurent Vivier         return a;
12046c25be6eSLaurent Vivier     }
12056c25be6eSLaurent Vivier }
120627340180SLaurent Vivier 
1207808d77bcSLucien Murray-Pitts /*
1208808d77bcSLucien Murray-Pitts  * Tangent
1209808d77bcSLucien Murray-Pitts  */
121027340180SLaurent Vivier 
floatx80_tan(floatx80 a,float_status * status)121127340180SLaurent Vivier floatx80 floatx80_tan(floatx80 a, float_status *status)
121227340180SLaurent Vivier {
1213c120391cSRichard Henderson     bool aSign, xSign;
121427340180SLaurent Vivier     int32_t aExp, xExp;
121527340180SLaurent Vivier     uint64_t aSig, xSig;
121627340180SLaurent Vivier 
1217*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
1218*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
121927340180SLaurent Vivier 
122027340180SLaurent Vivier     int32_t compact, l, n, j;
122127340180SLaurent Vivier     floatx80 fp0, fp1, fp2, fp3, fp4, fp5, invtwopi, twopi1, twopi2;
122227340180SLaurent Vivier     float32 twoto63;
1223c120391cSRichard Henderson     bool endflag;
122427340180SLaurent Vivier 
122527340180SLaurent Vivier     aSig = extractFloatx80Frac(a);
122627340180SLaurent Vivier     aExp = extractFloatx80Exp(a);
122727340180SLaurent Vivier     aSign = extractFloatx80Sign(a);
122827340180SLaurent Vivier 
122927340180SLaurent Vivier     if (aExp == 0x7FFF) {
123027340180SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
123127340180SLaurent Vivier             return propagateFloatx80NaNOneArg(a, status);
123227340180SLaurent Vivier         }
123327340180SLaurent Vivier         float_raise(float_flag_invalid, status);
123427340180SLaurent Vivier         return floatx80_default_nan(status);
123527340180SLaurent Vivier     }
123627340180SLaurent Vivier 
123727340180SLaurent Vivier     if (aExp == 0 && aSig == 0) {
123827340180SLaurent Vivier         return packFloatx80(aSign, 0, 0);
123927340180SLaurent Vivier     }
124027340180SLaurent Vivier 
124127340180SLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
124227340180SLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
124327340180SLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
1244*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
124527340180SLaurent Vivier 
124627340180SLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
124727340180SLaurent Vivier 
124827340180SLaurent Vivier     fp0 = a;
124927340180SLaurent Vivier 
125027340180SLaurent Vivier     if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
125127340180SLaurent Vivier         /* 2^(-40) > |X| > 15 PI */
125227340180SLaurent Vivier         if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
125327340180SLaurent Vivier             /* REDUCEX */
125427340180SLaurent Vivier             fp1 = packFloatx80(0, 0, 0);
125527340180SLaurent Vivier             if (compact == 0x7FFEFFFF) {
125627340180SLaurent Vivier                 twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
1257e2326300SAlex Bennée                                       UINT64_C(0xC90FDAA200000000));
125827340180SLaurent Vivier                 twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
1259e2326300SAlex Bennée                                       UINT64_C(0x85A308D300000000));
126027340180SLaurent Vivier                 fp0 = floatx80_add(fp0, twopi1, status);
126127340180SLaurent Vivier                 fp1 = fp0;
126227340180SLaurent Vivier                 fp0 = floatx80_add(fp0, twopi2, status);
126327340180SLaurent Vivier                 fp1 = floatx80_sub(fp1, fp0, status);
126427340180SLaurent Vivier                 fp1 = floatx80_add(fp1, twopi2, status);
126527340180SLaurent Vivier             }
126627340180SLaurent Vivier         loop:
126727340180SLaurent Vivier             xSign = extractFloatx80Sign(fp0);
126827340180SLaurent Vivier             xExp = extractFloatx80Exp(fp0);
126927340180SLaurent Vivier             xExp -= 0x3FFF;
127027340180SLaurent Vivier             if (xExp <= 28) {
127127340180SLaurent Vivier                 l = 0;
1272c120391cSRichard Henderson                 endflag = true;
127327340180SLaurent Vivier             } else {
127427340180SLaurent Vivier                 l = xExp - 27;
1275c120391cSRichard Henderson                 endflag = false;
127627340180SLaurent Vivier             }
127727340180SLaurent Vivier             invtwopi = packFloatx80(0, 0x3FFE - l,
1278e2326300SAlex Bennée                                     UINT64_C(0xA2F9836E4E44152A)); /* INVTWOPI */
1279e2326300SAlex Bennée             twopi1 = packFloatx80(0, 0x3FFF + l, UINT64_C(0xC90FDAA200000000));
1280e2326300SAlex Bennée             twopi2 = packFloatx80(0, 0x3FDD + l, UINT64_C(0x85A308D300000000));
128127340180SLaurent Vivier 
128227340180SLaurent Vivier             /* SIGN(INARG)*2^63 IN SGL */
128327340180SLaurent Vivier             twoto63 = packFloat32(xSign, 0xBE, 0);
128427340180SLaurent Vivier 
128527340180SLaurent Vivier             fp2 = floatx80_mul(fp0, invtwopi, status);
128627340180SLaurent Vivier             fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
128727340180SLaurent Vivier                                status); /* THE FRACT PART OF FP2 IS ROUNDED */
128827340180SLaurent Vivier             fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
128927340180SLaurent Vivier                                status); /* FP2 is N */
129027340180SLaurent Vivier             fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
129127340180SLaurent Vivier             fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
129227340180SLaurent Vivier             fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
129327340180SLaurent Vivier             fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
129427340180SLaurent Vivier             fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
129527340180SLaurent Vivier             fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
129627340180SLaurent Vivier             fp3 = fp0; /* FP3 is A */
129727340180SLaurent Vivier             fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
129827340180SLaurent Vivier             fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
129927340180SLaurent Vivier 
1300c120391cSRichard Henderson             if (endflag) {
130127340180SLaurent Vivier                 n = floatx80_to_int32(fp2, status);
130227340180SLaurent Vivier                 goto tancont;
130327340180SLaurent Vivier             }
130427340180SLaurent Vivier             fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
130527340180SLaurent Vivier             fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
130627340180SLaurent Vivier             goto loop;
130727340180SLaurent Vivier         } else {
130827340180SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
130927340180SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
131027340180SLaurent Vivier 
131127340180SLaurent Vivier             a = floatx80_move(a, status);
131227340180SLaurent Vivier 
131327340180SLaurent Vivier             float_raise(float_flag_inexact, status);
131427340180SLaurent Vivier 
131527340180SLaurent Vivier             return a;
131627340180SLaurent Vivier         }
131727340180SLaurent Vivier     } else {
131827340180SLaurent Vivier         fp1 = floatx80_mul(fp0, float64_to_floatx80(
131927340180SLaurent Vivier                            make_float64(0x3FE45F306DC9C883), status),
132027340180SLaurent Vivier                            status); /* X*2/PI */
132127340180SLaurent Vivier 
132227340180SLaurent Vivier         n = floatx80_to_int32(fp1, status);
132327340180SLaurent Vivier         j = 32 + n;
132427340180SLaurent Vivier 
132527340180SLaurent Vivier         fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
132627340180SLaurent Vivier         fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
132727340180SLaurent Vivier                            status); /* FP0 IS R = (X-Y1)-Y2 */
132827340180SLaurent Vivier 
132927340180SLaurent Vivier     tancont:
133027340180SLaurent Vivier         if (n & 1) {
133127340180SLaurent Vivier             /* NODD */
133227340180SLaurent Vivier             fp1 = fp0; /* R */
133327340180SLaurent Vivier             fp0 = floatx80_mul(fp0, fp0, status); /* S = R*R */
133427340180SLaurent Vivier             fp3 = float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
133527340180SLaurent Vivier                                       status); /* Q4 */
133627340180SLaurent Vivier             fp2 = float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
133727340180SLaurent Vivier                                       status); /* P3 */
133827340180SLaurent Vivier             fp3 = floatx80_mul(fp3, fp0, status); /* SQ4 */
133927340180SLaurent Vivier             fp2 = floatx80_mul(fp2, fp0, status); /* SP3 */
134027340180SLaurent Vivier             fp3 = floatx80_add(fp3, float64_to_floatx80(
134127340180SLaurent Vivier                                make_float64(0xBF346F59B39BA65F), status),
134227340180SLaurent Vivier                                status); /* Q3+SQ4 */
1343e2326300SAlex Bennée             fp4 = packFloatx80(0, 0x3FF6, UINT64_C(0xE073D3FC199C4A00));
134427340180SLaurent Vivier             fp2 = floatx80_add(fp2, fp4, status); /* P2+SP3 */
134527340180SLaurent Vivier             fp3 = floatx80_mul(fp3, fp0, status); /* S(Q3+SQ4) */
134627340180SLaurent Vivier             fp2 = floatx80_mul(fp2, fp0, status); /* S(P2+SP3) */
1347e2326300SAlex Bennée             fp4 = packFloatx80(0, 0x3FF9, UINT64_C(0xD23CD68415D95FA1));
134827340180SLaurent Vivier             fp3 = floatx80_add(fp3, fp4, status); /* Q2+S(Q3+SQ4) */
1349e2326300SAlex Bennée             fp4 = packFloatx80(1, 0x3FFC, UINT64_C(0x8895A6C5FB423BCA));
135027340180SLaurent Vivier             fp2 = floatx80_add(fp2, fp4, status); /* P1+S(P2+SP3) */
135127340180SLaurent Vivier             fp3 = floatx80_mul(fp3, fp0, status); /* S(Q2+S(Q3+SQ4)) */
135227340180SLaurent Vivier             fp2 = floatx80_mul(fp2, fp0, status); /* S(P1+S(P2+SP3)) */
1353e2326300SAlex Bennée             fp4 = packFloatx80(1, 0x3FFD, UINT64_C(0xEEF57E0DA84BC8CE));
135427340180SLaurent Vivier             fp3 = floatx80_add(fp3, fp4, status); /* Q1+S(Q2+S(Q3+SQ4)) */
135527340180SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* RS(P1+S(P2+SP3)) */
135627340180SLaurent Vivier             fp0 = floatx80_mul(fp0, fp3, status); /* S(Q1+S(Q2+S(Q3+SQ4))) */
135727340180SLaurent Vivier             fp1 = floatx80_add(fp1, fp2, status); /* R+RS(P1+S(P2+SP3)) */
135827340180SLaurent Vivier             fp0 = floatx80_add(fp0, float32_to_floatx80(
135927340180SLaurent Vivier                                make_float32(0x3F800000), status),
136027340180SLaurent Vivier                                status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
136127340180SLaurent Vivier 
136227340180SLaurent Vivier             xSign = extractFloatx80Sign(fp1);
136327340180SLaurent Vivier             xExp = extractFloatx80Exp(fp1);
136427340180SLaurent Vivier             xSig = extractFloatx80Frac(fp1);
136527340180SLaurent Vivier             xSign ^= 1;
136627340180SLaurent Vivier             fp1 = packFloatx80(xSign, xExp, xSig);
136727340180SLaurent Vivier 
136827340180SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
136927340180SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
137027340180SLaurent Vivier 
137127340180SLaurent Vivier             a = floatx80_div(fp0, fp1, status);
137227340180SLaurent Vivier 
137327340180SLaurent Vivier             float_raise(float_flag_inexact, status);
137427340180SLaurent Vivier 
137527340180SLaurent Vivier             return a;
137627340180SLaurent Vivier         } else {
137727340180SLaurent Vivier             fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
137827340180SLaurent Vivier             fp3 = float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
137927340180SLaurent Vivier                                       status); /* Q4 */
138027340180SLaurent Vivier             fp2 = float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
138127340180SLaurent Vivier                                       status); /* P3 */
138227340180SLaurent Vivier             fp3 = floatx80_mul(fp3, fp1, status); /* SQ4 */
138327340180SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* SP3 */
138427340180SLaurent Vivier             fp3 = floatx80_add(fp3, float64_to_floatx80(
138527340180SLaurent Vivier                                make_float64(0xBF346F59B39BA65F), status),
138627340180SLaurent Vivier                                status); /* Q3+SQ4 */
1387e2326300SAlex Bennée             fp4 = packFloatx80(0, 0x3FF6, UINT64_C(0xE073D3FC199C4A00));
138827340180SLaurent Vivier             fp2 = floatx80_add(fp2, fp4, status); /* P2+SP3 */
138927340180SLaurent Vivier             fp3 = floatx80_mul(fp3, fp1, status); /* S(Q3+SQ4) */
139027340180SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* S(P2+SP3) */
1391e2326300SAlex Bennée             fp4 = packFloatx80(0, 0x3FF9, UINT64_C(0xD23CD68415D95FA1));
139227340180SLaurent Vivier             fp3 = floatx80_add(fp3, fp4, status); /* Q2+S(Q3+SQ4) */
1393e2326300SAlex Bennée             fp4 = packFloatx80(1, 0x3FFC, UINT64_C(0x8895A6C5FB423BCA));
139427340180SLaurent Vivier             fp2 = floatx80_add(fp2, fp4, status); /* P1+S(P2+SP3) */
139527340180SLaurent Vivier             fp3 = floatx80_mul(fp3, fp1, status); /* S(Q2+S(Q3+SQ4)) */
139627340180SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* S(P1+S(P2+SP3)) */
1397e2326300SAlex Bennée             fp4 = packFloatx80(1, 0x3FFD, UINT64_C(0xEEF57E0DA84BC8CE));
139827340180SLaurent Vivier             fp3 = floatx80_add(fp3, fp4, status); /* Q1+S(Q2+S(Q3+SQ4)) */
139927340180SLaurent Vivier             fp2 = floatx80_mul(fp2, fp0, status); /* RS(P1+S(P2+SP3)) */
140027340180SLaurent Vivier             fp1 = floatx80_mul(fp1, fp3, status); /* S(Q1+S(Q2+S(Q3+SQ4))) */
140127340180SLaurent Vivier             fp0 = floatx80_add(fp0, fp2, status); /* R+RS(P1+S(P2+SP3)) */
140227340180SLaurent Vivier             fp1 = floatx80_add(fp1, float32_to_floatx80(
140327340180SLaurent Vivier                                make_float32(0x3F800000), status),
140427340180SLaurent Vivier                                status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
140527340180SLaurent Vivier 
140627340180SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
140727340180SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
140827340180SLaurent Vivier 
140927340180SLaurent Vivier             a = floatx80_div(fp0, fp1, status);
141027340180SLaurent Vivier 
141127340180SLaurent Vivier             float_raise(float_flag_inexact, status);
141227340180SLaurent Vivier 
141327340180SLaurent Vivier             return a;
141427340180SLaurent Vivier         }
141527340180SLaurent Vivier     }
141627340180SLaurent Vivier }
14175add1ac4SLaurent Vivier 
1418808d77bcSLucien Murray-Pitts /*
1419808d77bcSLucien Murray-Pitts  * Sine
1420808d77bcSLucien Murray-Pitts  */
14215add1ac4SLaurent Vivier 
floatx80_sin(floatx80 a,float_status * status)14225add1ac4SLaurent Vivier floatx80 floatx80_sin(floatx80 a, float_status *status)
14235add1ac4SLaurent Vivier {
1424c120391cSRichard Henderson     bool aSign, xSign;
14255add1ac4SLaurent Vivier     int32_t aExp, xExp;
14265add1ac4SLaurent Vivier     uint64_t aSig, xSig;
14275add1ac4SLaurent Vivier 
1428*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
1429*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
14305add1ac4SLaurent Vivier 
14315add1ac4SLaurent Vivier     int32_t compact, l, n, j;
14325add1ac4SLaurent Vivier     floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
14335add1ac4SLaurent Vivier     float32 posneg1, twoto63;
1434c120391cSRichard Henderson     bool endflag;
14355add1ac4SLaurent Vivier 
14365add1ac4SLaurent Vivier     aSig = extractFloatx80Frac(a);
14375add1ac4SLaurent Vivier     aExp = extractFloatx80Exp(a);
14385add1ac4SLaurent Vivier     aSign = extractFloatx80Sign(a);
14395add1ac4SLaurent Vivier 
14405add1ac4SLaurent Vivier     if (aExp == 0x7FFF) {
14415add1ac4SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
14425add1ac4SLaurent Vivier             return propagateFloatx80NaNOneArg(a, status);
14435add1ac4SLaurent Vivier         }
14445add1ac4SLaurent Vivier         float_raise(float_flag_invalid, status);
14455add1ac4SLaurent Vivier         return floatx80_default_nan(status);
14465add1ac4SLaurent Vivier     }
14475add1ac4SLaurent Vivier 
14485add1ac4SLaurent Vivier     if (aExp == 0 && aSig == 0) {
14495add1ac4SLaurent Vivier         return packFloatx80(aSign, 0, 0);
14505add1ac4SLaurent Vivier     }
14515add1ac4SLaurent Vivier 
14525add1ac4SLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
14535add1ac4SLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
14545add1ac4SLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
1455*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
14565add1ac4SLaurent Vivier 
14575add1ac4SLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
14585add1ac4SLaurent Vivier 
14595add1ac4SLaurent Vivier     fp0 = a;
14605add1ac4SLaurent Vivier 
14615add1ac4SLaurent Vivier     if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
14625add1ac4SLaurent Vivier         /* 2^(-40) > |X| > 15 PI */
14635add1ac4SLaurent Vivier         if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
14645add1ac4SLaurent Vivier             /* REDUCEX */
14655add1ac4SLaurent Vivier             fp1 = packFloatx80(0, 0, 0);
14665add1ac4SLaurent Vivier             if (compact == 0x7FFEFFFF) {
14675add1ac4SLaurent Vivier                 twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
1468e2326300SAlex Bennée                                       UINT64_C(0xC90FDAA200000000));
14695add1ac4SLaurent Vivier                 twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
1470e2326300SAlex Bennée                                       UINT64_C(0x85A308D300000000));
14715add1ac4SLaurent Vivier                 fp0 = floatx80_add(fp0, twopi1, status);
14725add1ac4SLaurent Vivier                 fp1 = fp0;
14735add1ac4SLaurent Vivier                 fp0 = floatx80_add(fp0, twopi2, status);
14745add1ac4SLaurent Vivier                 fp1 = floatx80_sub(fp1, fp0, status);
14755add1ac4SLaurent Vivier                 fp1 = floatx80_add(fp1, twopi2, status);
14765add1ac4SLaurent Vivier             }
14775add1ac4SLaurent Vivier         loop:
14785add1ac4SLaurent Vivier             xSign = extractFloatx80Sign(fp0);
14795add1ac4SLaurent Vivier             xExp = extractFloatx80Exp(fp0);
14805add1ac4SLaurent Vivier             xExp -= 0x3FFF;
14815add1ac4SLaurent Vivier             if (xExp <= 28) {
14825add1ac4SLaurent Vivier                 l = 0;
1483c120391cSRichard Henderson                 endflag = true;
14845add1ac4SLaurent Vivier             } else {
14855add1ac4SLaurent Vivier                 l = xExp - 27;
1486c120391cSRichard Henderson                 endflag = false;
14875add1ac4SLaurent Vivier             }
14885add1ac4SLaurent Vivier             invtwopi = packFloatx80(0, 0x3FFE - l,
1489e2326300SAlex Bennée                                     UINT64_C(0xA2F9836E4E44152A)); /* INVTWOPI */
1490e2326300SAlex Bennée             twopi1 = packFloatx80(0, 0x3FFF + l, UINT64_C(0xC90FDAA200000000));
1491e2326300SAlex Bennée             twopi2 = packFloatx80(0, 0x3FDD + l, UINT64_C(0x85A308D300000000));
14925add1ac4SLaurent Vivier 
14935add1ac4SLaurent Vivier             /* SIGN(INARG)*2^63 IN SGL */
14945add1ac4SLaurent Vivier             twoto63 = packFloat32(xSign, 0xBE, 0);
14955add1ac4SLaurent Vivier 
14965add1ac4SLaurent Vivier             fp2 = floatx80_mul(fp0, invtwopi, status);
14975add1ac4SLaurent Vivier             fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
14985add1ac4SLaurent Vivier                                status); /* THE FRACT PART OF FP2 IS ROUNDED */
14995add1ac4SLaurent Vivier             fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
15005add1ac4SLaurent Vivier                                status); /* FP2 is N */
15015add1ac4SLaurent Vivier             fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
15025add1ac4SLaurent Vivier             fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
15035add1ac4SLaurent Vivier             fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
15045add1ac4SLaurent Vivier             fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
15055add1ac4SLaurent Vivier             fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
15065add1ac4SLaurent Vivier             fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
15075add1ac4SLaurent Vivier             fp3 = fp0; /* FP3 is A */
15085add1ac4SLaurent Vivier             fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
15095add1ac4SLaurent Vivier             fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
15105add1ac4SLaurent Vivier 
1511c120391cSRichard Henderson             if (endflag) {
15125add1ac4SLaurent Vivier                 n = floatx80_to_int32(fp2, status);
15135add1ac4SLaurent Vivier                 goto sincont;
15145add1ac4SLaurent Vivier             }
15155add1ac4SLaurent Vivier             fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
15165add1ac4SLaurent Vivier             fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
15175add1ac4SLaurent Vivier             goto loop;
15185add1ac4SLaurent Vivier         } else {
15195add1ac4SLaurent Vivier             /* SINSM */
15205add1ac4SLaurent Vivier             fp0 = float32_to_floatx80(make_float32(0x3F800000),
15215add1ac4SLaurent Vivier                                       status); /* 1 */
15225add1ac4SLaurent Vivier 
15235add1ac4SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
15245add1ac4SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
15255add1ac4SLaurent Vivier 
15265add1ac4SLaurent Vivier             /* SINTINY */
15275add1ac4SLaurent Vivier             a = floatx80_move(a, status);
15285add1ac4SLaurent Vivier             float_raise(float_flag_inexact, status);
15295add1ac4SLaurent Vivier 
15305add1ac4SLaurent Vivier             return a;
15315add1ac4SLaurent Vivier         }
15325add1ac4SLaurent Vivier     } else {
15335add1ac4SLaurent Vivier         fp1 = floatx80_mul(fp0, float64_to_floatx80(
15345add1ac4SLaurent Vivier                            make_float64(0x3FE45F306DC9C883), status),
15355add1ac4SLaurent Vivier                            status); /* X*2/PI */
15365add1ac4SLaurent Vivier 
15375add1ac4SLaurent Vivier         n = floatx80_to_int32(fp1, status);
15385add1ac4SLaurent Vivier         j = 32 + n;
15395add1ac4SLaurent Vivier 
15405add1ac4SLaurent Vivier         fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
15415add1ac4SLaurent Vivier         fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
15425add1ac4SLaurent Vivier                            status); /* FP0 IS R = (X-Y1)-Y2 */
15435add1ac4SLaurent Vivier 
15445add1ac4SLaurent Vivier     sincont:
15456361d298SLaurent Vivier         if (n & 1) {
15465add1ac4SLaurent Vivier             /* COSPOLY */
15475add1ac4SLaurent Vivier             fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
15485add1ac4SLaurent Vivier             fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
15495add1ac4SLaurent Vivier             fp2 = float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
15505add1ac4SLaurent Vivier                                       status); /* B8 */
15515add1ac4SLaurent Vivier             fp3 = float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
15525add1ac4SLaurent Vivier                                       status); /* B7 */
15535add1ac4SLaurent Vivier 
15545add1ac4SLaurent Vivier             xSign = extractFloatx80Sign(fp0); /* X IS S */
15555add1ac4SLaurent Vivier             xExp = extractFloatx80Exp(fp0);
15565add1ac4SLaurent Vivier             xSig = extractFloatx80Frac(fp0);
15575add1ac4SLaurent Vivier 
15586361d298SLaurent Vivier             if ((n >> 1) & 1) {
15595add1ac4SLaurent Vivier                 xSign ^= 1;
15605add1ac4SLaurent Vivier                 posneg1 = make_float32(0xBF800000); /* -1 */
15615add1ac4SLaurent Vivier             } else {
15625add1ac4SLaurent Vivier                 xSign ^= 0;
15635add1ac4SLaurent Vivier                 posneg1 = make_float32(0x3F800000); /* 1 */
15645add1ac4SLaurent Vivier             } /* X IS NOW R'= SGN*R */
15655add1ac4SLaurent Vivier 
15665add1ac4SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* TB8 */
15675add1ac4SLaurent Vivier             fp3 = floatx80_mul(fp3, fp1, status); /* TB7 */
15685add1ac4SLaurent Vivier             fp2 = floatx80_add(fp2, float64_to_floatx80(
15695add1ac4SLaurent Vivier                                make_float64(0x3E21EED90612C972), status),
15705add1ac4SLaurent Vivier                                status); /* B6+TB8 */
15715add1ac4SLaurent Vivier             fp3 = floatx80_add(fp3, float64_to_floatx80(
15725add1ac4SLaurent Vivier                                make_float64(0xBE927E4FB79D9FCF), status),
15735add1ac4SLaurent Vivier                                status); /* B5+TB7 */
15745add1ac4SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* T(B6+TB8) */
15755add1ac4SLaurent Vivier             fp3 = floatx80_mul(fp3, fp1, status); /* T(B5+TB7) */
15765add1ac4SLaurent Vivier             fp2 = floatx80_add(fp2, float64_to_floatx80(
15775add1ac4SLaurent Vivier                                make_float64(0x3EFA01A01A01D423), status),
15785add1ac4SLaurent Vivier                                status); /* B4+T(B6+TB8) */
1579e2326300SAlex Bennée             fp4 = packFloatx80(1, 0x3FF5, UINT64_C(0xB60B60B60B61D438));
15805add1ac4SLaurent Vivier             fp3 = floatx80_add(fp3, fp4, status); /* B3+T(B5+TB7) */
15815add1ac4SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* T(B4+T(B6+TB8)) */
15825add1ac4SLaurent Vivier             fp1 = floatx80_mul(fp1, fp3, status); /* T(B3+T(B5+TB7)) */
1583e2326300SAlex Bennée             fp4 = packFloatx80(0, 0x3FFA, UINT64_C(0xAAAAAAAAAAAAAB5E));
15845add1ac4SLaurent Vivier             fp2 = floatx80_add(fp2, fp4, status); /* B2+T(B4+T(B6+TB8)) */
15855add1ac4SLaurent Vivier             fp1 = floatx80_add(fp1, float32_to_floatx80(
15865add1ac4SLaurent Vivier                                make_float32(0xBF000000), status),
15875add1ac4SLaurent Vivier                                status); /* B1+T(B3+T(B5+TB7)) */
15885add1ac4SLaurent Vivier             fp0 = floatx80_mul(fp0, fp2, status); /* S(B2+T(B4+T(B6+TB8))) */
15895add1ac4SLaurent Vivier             fp0 = floatx80_add(fp0, fp1, status); /* [B1+T(B3+T(B5+TB7))]+
15905add1ac4SLaurent Vivier                                                    * [S(B2+T(B4+T(B6+TB8)))]
15915add1ac4SLaurent Vivier                                                    */
15925add1ac4SLaurent Vivier 
15935add1ac4SLaurent Vivier             x = packFloatx80(xSign, xExp, xSig);
15945add1ac4SLaurent Vivier             fp0 = floatx80_mul(fp0, x, status);
15955add1ac4SLaurent Vivier 
15965add1ac4SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
15975add1ac4SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
15985add1ac4SLaurent Vivier 
15995add1ac4SLaurent Vivier             a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status);
16005add1ac4SLaurent Vivier 
16015add1ac4SLaurent Vivier             float_raise(float_flag_inexact, status);
16025add1ac4SLaurent Vivier 
16035add1ac4SLaurent Vivier             return a;
16045add1ac4SLaurent Vivier         } else {
16055add1ac4SLaurent Vivier             /* SINPOLY */
16065add1ac4SLaurent Vivier             xSign = extractFloatx80Sign(fp0); /* X IS R */
16075add1ac4SLaurent Vivier             xExp = extractFloatx80Exp(fp0);
16085add1ac4SLaurent Vivier             xSig = extractFloatx80Frac(fp0);
16095add1ac4SLaurent Vivier 
16106361d298SLaurent Vivier             xSign ^= (n >> 1) & 1; /* X IS NOW R'= SGN*R */
16115add1ac4SLaurent Vivier 
16125add1ac4SLaurent Vivier             fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
16135add1ac4SLaurent Vivier             fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
16145add1ac4SLaurent Vivier             fp3 = float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
16155add1ac4SLaurent Vivier                                       status); /* A7 */
16165add1ac4SLaurent Vivier             fp2 = float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
16175add1ac4SLaurent Vivier                                       status); /* A6 */
16185add1ac4SLaurent Vivier             fp3 = floatx80_mul(fp3, fp1, status); /* T*A7 */
16195add1ac4SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* T*A6 */
16205add1ac4SLaurent Vivier             fp3 = floatx80_add(fp3, float64_to_floatx80(
16215add1ac4SLaurent Vivier                                make_float64(0xBE5AE6452A118AE4), status),
16225add1ac4SLaurent Vivier                                status); /* A5+T*A7 */
16235add1ac4SLaurent Vivier             fp2 = floatx80_add(fp2, float64_to_floatx80(
16245add1ac4SLaurent Vivier                                make_float64(0x3EC71DE3A5341531), status),
16255add1ac4SLaurent Vivier                                status); /* A4+T*A6 */
16265add1ac4SLaurent Vivier             fp3 = floatx80_mul(fp3, fp1, status); /* T(A5+TA7) */
16275add1ac4SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* T(A4+TA6) */
16285add1ac4SLaurent Vivier             fp3 = floatx80_add(fp3, float64_to_floatx80(
16295add1ac4SLaurent Vivier                                make_float64(0xBF2A01A01A018B59), status),
16305add1ac4SLaurent Vivier                                status); /* A3+T(A5+TA7) */
1631e2326300SAlex Bennée             fp4 = packFloatx80(0, 0x3FF8, UINT64_C(0x88888888888859AF));
16325add1ac4SLaurent Vivier             fp2 = floatx80_add(fp2, fp4, status); /* A2+T(A4+TA6) */
16335add1ac4SLaurent Vivier             fp1 = floatx80_mul(fp1, fp3, status); /* T(A3+T(A5+TA7)) */
16345add1ac4SLaurent Vivier             fp2 = floatx80_mul(fp2, fp0, status); /* S(A2+T(A4+TA6)) */
1635e2326300SAlex Bennée             fp4 = packFloatx80(1, 0x3FFC, UINT64_C(0xAAAAAAAAAAAAAA99));
16365add1ac4SLaurent Vivier             fp1 = floatx80_add(fp1, fp4, status); /* A1+T(A3+T(A5+TA7)) */
16375add1ac4SLaurent Vivier             fp1 = floatx80_add(fp1, fp2,
16385add1ac4SLaurent Vivier                                status); /* [A1+T(A3+T(A5+TA7))]+
16395add1ac4SLaurent Vivier                                          * [S(A2+T(A4+TA6))]
16405add1ac4SLaurent Vivier                                          */
16415add1ac4SLaurent Vivier 
16425add1ac4SLaurent Vivier             x = packFloatx80(xSign, xExp, xSig);
16435add1ac4SLaurent Vivier             fp0 = floatx80_mul(fp0, x, status); /* R'*S */
16445add1ac4SLaurent Vivier             fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */
16455add1ac4SLaurent Vivier 
16465add1ac4SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
16475add1ac4SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
16485add1ac4SLaurent Vivier 
16495add1ac4SLaurent Vivier             a = floatx80_add(fp0, x, status);
16505add1ac4SLaurent Vivier 
16515add1ac4SLaurent Vivier             float_raise(float_flag_inexact, status);
16525add1ac4SLaurent Vivier 
16535add1ac4SLaurent Vivier             return a;
16545add1ac4SLaurent Vivier         }
16555add1ac4SLaurent Vivier     }
16565add1ac4SLaurent Vivier }
165768d0ed37SLaurent Vivier 
1658808d77bcSLucien Murray-Pitts /*
1659808d77bcSLucien Murray-Pitts  * Cosine
1660808d77bcSLucien Murray-Pitts  */
166168d0ed37SLaurent Vivier 
floatx80_cos(floatx80 a,float_status * status)166268d0ed37SLaurent Vivier floatx80 floatx80_cos(floatx80 a, float_status *status)
166368d0ed37SLaurent Vivier {
1664c120391cSRichard Henderson     bool aSign, xSign;
166568d0ed37SLaurent Vivier     int32_t aExp, xExp;
166668d0ed37SLaurent Vivier     uint64_t aSig, xSig;
166768d0ed37SLaurent Vivier 
1668*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
1669*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
167068d0ed37SLaurent Vivier 
167168d0ed37SLaurent Vivier     int32_t compact, l, n, j;
167268d0ed37SLaurent Vivier     floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
167368d0ed37SLaurent Vivier     float32 posneg1, twoto63;
1674c120391cSRichard Henderson     bool endflag;
167568d0ed37SLaurent Vivier 
167668d0ed37SLaurent Vivier     aSig = extractFloatx80Frac(a);
167768d0ed37SLaurent Vivier     aExp = extractFloatx80Exp(a);
167868d0ed37SLaurent Vivier     aSign = extractFloatx80Sign(a);
167968d0ed37SLaurent Vivier 
168068d0ed37SLaurent Vivier     if (aExp == 0x7FFF) {
168168d0ed37SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
168268d0ed37SLaurent Vivier             return propagateFloatx80NaNOneArg(a, status);
168368d0ed37SLaurent Vivier         }
168468d0ed37SLaurent Vivier         float_raise(float_flag_invalid, status);
168568d0ed37SLaurent Vivier         return floatx80_default_nan(status);
168668d0ed37SLaurent Vivier     }
168768d0ed37SLaurent Vivier 
168868d0ed37SLaurent Vivier     if (aExp == 0 && aSig == 0) {
168968d0ed37SLaurent Vivier         return packFloatx80(0, one_exp, one_sig);
169068d0ed37SLaurent Vivier     }
169168d0ed37SLaurent Vivier 
169268d0ed37SLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
169368d0ed37SLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
169468d0ed37SLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
1695*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
169668d0ed37SLaurent Vivier 
169768d0ed37SLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
169868d0ed37SLaurent Vivier 
169968d0ed37SLaurent Vivier     fp0 = a;
170068d0ed37SLaurent Vivier 
170168d0ed37SLaurent Vivier     if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
170268d0ed37SLaurent Vivier         /* 2^(-40) > |X| > 15 PI */
170368d0ed37SLaurent Vivier         if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
170468d0ed37SLaurent Vivier             /* REDUCEX */
170568d0ed37SLaurent Vivier             fp1 = packFloatx80(0, 0, 0);
170668d0ed37SLaurent Vivier             if (compact == 0x7FFEFFFF) {
170768d0ed37SLaurent Vivier                 twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
1708e2326300SAlex Bennée                                       UINT64_C(0xC90FDAA200000000));
170968d0ed37SLaurent Vivier                 twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
1710e2326300SAlex Bennée                                       UINT64_C(0x85A308D300000000));
171168d0ed37SLaurent Vivier                 fp0 = floatx80_add(fp0, twopi1, status);
171268d0ed37SLaurent Vivier                 fp1 = fp0;
171368d0ed37SLaurent Vivier                 fp0 = floatx80_add(fp0, twopi2, status);
171468d0ed37SLaurent Vivier                 fp1 = floatx80_sub(fp1, fp0, status);
171568d0ed37SLaurent Vivier                 fp1 = floatx80_add(fp1, twopi2, status);
171668d0ed37SLaurent Vivier             }
171768d0ed37SLaurent Vivier         loop:
171868d0ed37SLaurent Vivier             xSign = extractFloatx80Sign(fp0);
171968d0ed37SLaurent Vivier             xExp = extractFloatx80Exp(fp0);
172068d0ed37SLaurent Vivier             xExp -= 0x3FFF;
172168d0ed37SLaurent Vivier             if (xExp <= 28) {
172268d0ed37SLaurent Vivier                 l = 0;
1723c120391cSRichard Henderson                 endflag = true;
172468d0ed37SLaurent Vivier             } else {
172568d0ed37SLaurent Vivier                 l = xExp - 27;
1726c120391cSRichard Henderson                 endflag = false;
172768d0ed37SLaurent Vivier             }
172868d0ed37SLaurent Vivier             invtwopi = packFloatx80(0, 0x3FFE - l,
1729e2326300SAlex Bennée                                     UINT64_C(0xA2F9836E4E44152A)); /* INVTWOPI */
1730e2326300SAlex Bennée             twopi1 = packFloatx80(0, 0x3FFF + l, UINT64_C(0xC90FDAA200000000));
1731e2326300SAlex Bennée             twopi2 = packFloatx80(0, 0x3FDD + l, UINT64_C(0x85A308D300000000));
173268d0ed37SLaurent Vivier 
173368d0ed37SLaurent Vivier             /* SIGN(INARG)*2^63 IN SGL */
173468d0ed37SLaurent Vivier             twoto63 = packFloat32(xSign, 0xBE, 0);
173568d0ed37SLaurent Vivier 
173668d0ed37SLaurent Vivier             fp2 = floatx80_mul(fp0, invtwopi, status);
173768d0ed37SLaurent Vivier             fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
173868d0ed37SLaurent Vivier                                status); /* THE FRACT PART OF FP2 IS ROUNDED */
173968d0ed37SLaurent Vivier             fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
174068d0ed37SLaurent Vivier                                status); /* FP2 is N */
174168d0ed37SLaurent Vivier             fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
174268d0ed37SLaurent Vivier             fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
174368d0ed37SLaurent Vivier             fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
174468d0ed37SLaurent Vivier             fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
174568d0ed37SLaurent Vivier             fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
174668d0ed37SLaurent Vivier             fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
174768d0ed37SLaurent Vivier             fp3 = fp0; /* FP3 is A */
174868d0ed37SLaurent Vivier             fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
174968d0ed37SLaurent Vivier             fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
175068d0ed37SLaurent Vivier 
1751c120391cSRichard Henderson             if (endflag) {
175268d0ed37SLaurent Vivier                 n = floatx80_to_int32(fp2, status);
175368d0ed37SLaurent Vivier                 goto sincont;
175468d0ed37SLaurent Vivier             }
175568d0ed37SLaurent Vivier             fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
175668d0ed37SLaurent Vivier             fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
175768d0ed37SLaurent Vivier             goto loop;
175868d0ed37SLaurent Vivier         } else {
175968d0ed37SLaurent Vivier             /* SINSM */
176068d0ed37SLaurent Vivier             fp0 = float32_to_floatx80(make_float32(0x3F800000), status); /* 1 */
176168d0ed37SLaurent Vivier 
176268d0ed37SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
176368d0ed37SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
176468d0ed37SLaurent Vivier 
176568d0ed37SLaurent Vivier             /* COSTINY */
176668d0ed37SLaurent Vivier             a = floatx80_sub(fp0, float32_to_floatx80(
176768d0ed37SLaurent Vivier                              make_float32(0x00800000), status),
176868d0ed37SLaurent Vivier                              status);
176968d0ed37SLaurent Vivier             float_raise(float_flag_inexact, status);
177068d0ed37SLaurent Vivier 
177168d0ed37SLaurent Vivier             return a;
177268d0ed37SLaurent Vivier         }
177368d0ed37SLaurent Vivier     } else {
177468d0ed37SLaurent Vivier         fp1 = floatx80_mul(fp0, float64_to_floatx80(
177568d0ed37SLaurent Vivier                            make_float64(0x3FE45F306DC9C883), status),
177668d0ed37SLaurent Vivier                            status); /* X*2/PI */
177768d0ed37SLaurent Vivier 
177868d0ed37SLaurent Vivier         n = floatx80_to_int32(fp1, status);
177968d0ed37SLaurent Vivier         j = 32 + n;
178068d0ed37SLaurent Vivier 
178168d0ed37SLaurent Vivier         fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
178268d0ed37SLaurent Vivier         fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
178368d0ed37SLaurent Vivier                            status); /* FP0 IS R = (X-Y1)-Y2 */
178468d0ed37SLaurent Vivier 
178568d0ed37SLaurent Vivier     sincont:
17866361d298SLaurent Vivier         if ((n + 1) & 1) {
178768d0ed37SLaurent Vivier             /* COSPOLY */
178868d0ed37SLaurent Vivier             fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
178968d0ed37SLaurent Vivier             fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
179068d0ed37SLaurent Vivier             fp2 = float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
179168d0ed37SLaurent Vivier                                       status); /* B8 */
179268d0ed37SLaurent Vivier             fp3 = float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
179368d0ed37SLaurent Vivier                                       status); /* B7 */
179468d0ed37SLaurent Vivier 
179568d0ed37SLaurent Vivier             xSign = extractFloatx80Sign(fp0); /* X IS S */
179668d0ed37SLaurent Vivier             xExp = extractFloatx80Exp(fp0);
179768d0ed37SLaurent Vivier             xSig = extractFloatx80Frac(fp0);
179868d0ed37SLaurent Vivier 
17996361d298SLaurent Vivier             if (((n + 1) >> 1) & 1) {
180068d0ed37SLaurent Vivier                 xSign ^= 1;
180168d0ed37SLaurent Vivier                 posneg1 = make_float32(0xBF800000); /* -1 */
180268d0ed37SLaurent Vivier             } else {
180368d0ed37SLaurent Vivier                 xSign ^= 0;
180468d0ed37SLaurent Vivier                 posneg1 = make_float32(0x3F800000); /* 1 */
180568d0ed37SLaurent Vivier             } /* X IS NOW R'= SGN*R */
180668d0ed37SLaurent Vivier 
180768d0ed37SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* TB8 */
180868d0ed37SLaurent Vivier             fp3 = floatx80_mul(fp3, fp1, status); /* TB7 */
180968d0ed37SLaurent Vivier             fp2 = floatx80_add(fp2, float64_to_floatx80(
181068d0ed37SLaurent Vivier                                make_float64(0x3E21EED90612C972), status),
181168d0ed37SLaurent Vivier                                status); /* B6+TB8 */
181268d0ed37SLaurent Vivier             fp3 = floatx80_add(fp3, float64_to_floatx80(
181368d0ed37SLaurent Vivier                                make_float64(0xBE927E4FB79D9FCF), status),
181468d0ed37SLaurent Vivier                                status); /* B5+TB7 */
181568d0ed37SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* T(B6+TB8) */
181668d0ed37SLaurent Vivier             fp3 = floatx80_mul(fp3, fp1, status); /* T(B5+TB7) */
181768d0ed37SLaurent Vivier             fp2 = floatx80_add(fp2, float64_to_floatx80(
181868d0ed37SLaurent Vivier                                make_float64(0x3EFA01A01A01D423), status),
181968d0ed37SLaurent Vivier                                status); /* B4+T(B6+TB8) */
1820e2326300SAlex Bennée             fp4 = packFloatx80(1, 0x3FF5, UINT64_C(0xB60B60B60B61D438));
182168d0ed37SLaurent Vivier             fp3 = floatx80_add(fp3, fp4, status); /* B3+T(B5+TB7) */
182268d0ed37SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* T(B4+T(B6+TB8)) */
182368d0ed37SLaurent Vivier             fp1 = floatx80_mul(fp1, fp3, status); /* T(B3+T(B5+TB7)) */
1824e2326300SAlex Bennée             fp4 = packFloatx80(0, 0x3FFA, UINT64_C(0xAAAAAAAAAAAAAB5E));
182568d0ed37SLaurent Vivier             fp2 = floatx80_add(fp2, fp4, status); /* B2+T(B4+T(B6+TB8)) */
182668d0ed37SLaurent Vivier             fp1 = floatx80_add(fp1, float32_to_floatx80(
182768d0ed37SLaurent Vivier                                make_float32(0xBF000000), status),
182868d0ed37SLaurent Vivier                                status); /* B1+T(B3+T(B5+TB7)) */
182968d0ed37SLaurent Vivier             fp0 = floatx80_mul(fp0, fp2, status); /* S(B2+T(B4+T(B6+TB8))) */
183068d0ed37SLaurent Vivier             fp0 = floatx80_add(fp0, fp1, status);
183168d0ed37SLaurent Vivier                               /* [B1+T(B3+T(B5+TB7))]+[S(B2+T(B4+T(B6+TB8)))] */
183268d0ed37SLaurent Vivier 
183368d0ed37SLaurent Vivier             x = packFloatx80(xSign, xExp, xSig);
183468d0ed37SLaurent Vivier             fp0 = floatx80_mul(fp0, x, status);
183568d0ed37SLaurent Vivier 
183668d0ed37SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
183768d0ed37SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
183868d0ed37SLaurent Vivier 
183968d0ed37SLaurent Vivier             a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status);
184068d0ed37SLaurent Vivier 
184168d0ed37SLaurent Vivier             float_raise(float_flag_inexact, status);
184268d0ed37SLaurent Vivier 
184368d0ed37SLaurent Vivier             return a;
184468d0ed37SLaurent Vivier         } else {
184568d0ed37SLaurent Vivier             /* SINPOLY */
184668d0ed37SLaurent Vivier             xSign = extractFloatx80Sign(fp0); /* X IS R */
184768d0ed37SLaurent Vivier             xExp = extractFloatx80Exp(fp0);
184868d0ed37SLaurent Vivier             xSig = extractFloatx80Frac(fp0);
184968d0ed37SLaurent Vivier 
18506361d298SLaurent Vivier             xSign ^= ((n + 1) >> 1) & 1; /* X IS NOW R'= SGN*R */
185168d0ed37SLaurent Vivier 
185268d0ed37SLaurent Vivier             fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
185368d0ed37SLaurent Vivier             fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
185468d0ed37SLaurent Vivier             fp3 = float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
185568d0ed37SLaurent Vivier                                       status); /* A7 */
185668d0ed37SLaurent Vivier             fp2 = float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
185768d0ed37SLaurent Vivier                                       status); /* A6 */
185868d0ed37SLaurent Vivier             fp3 = floatx80_mul(fp3, fp1, status); /* T*A7 */
185968d0ed37SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* T*A6 */
186068d0ed37SLaurent Vivier             fp3 = floatx80_add(fp3, float64_to_floatx80(
186168d0ed37SLaurent Vivier                                make_float64(0xBE5AE6452A118AE4), status),
186268d0ed37SLaurent Vivier                                status); /* A5+T*A7 */
186368d0ed37SLaurent Vivier             fp2 = floatx80_add(fp2, float64_to_floatx80(
186468d0ed37SLaurent Vivier                                make_float64(0x3EC71DE3A5341531), status),
186568d0ed37SLaurent Vivier                                status); /* A4+T*A6 */
186668d0ed37SLaurent Vivier             fp3 = floatx80_mul(fp3, fp1, status); /* T(A5+TA7) */
186768d0ed37SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* T(A4+TA6) */
186868d0ed37SLaurent Vivier             fp3 = floatx80_add(fp3, float64_to_floatx80(
186968d0ed37SLaurent Vivier                                make_float64(0xBF2A01A01A018B59), status),
187068d0ed37SLaurent Vivier                                status); /* A3+T(A5+TA7) */
1871e2326300SAlex Bennée             fp4 = packFloatx80(0, 0x3FF8, UINT64_C(0x88888888888859AF));
187268d0ed37SLaurent Vivier             fp2 = floatx80_add(fp2, fp4, status); /* A2+T(A4+TA6) */
187368d0ed37SLaurent Vivier             fp1 = floatx80_mul(fp1, fp3, status); /* T(A3+T(A5+TA7)) */
187468d0ed37SLaurent Vivier             fp2 = floatx80_mul(fp2, fp0, status); /* S(A2+T(A4+TA6)) */
1875e2326300SAlex Bennée             fp4 = packFloatx80(1, 0x3FFC, UINT64_C(0xAAAAAAAAAAAAAA99));
187668d0ed37SLaurent Vivier             fp1 = floatx80_add(fp1, fp4, status); /* A1+T(A3+T(A5+TA7)) */
187768d0ed37SLaurent Vivier             fp1 = floatx80_add(fp1, fp2, status);
187868d0ed37SLaurent Vivier                                     /* [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))] */
187968d0ed37SLaurent Vivier 
188068d0ed37SLaurent Vivier             x = packFloatx80(xSign, xExp, xSig);
188168d0ed37SLaurent Vivier             fp0 = floatx80_mul(fp0, x, status); /* R'*S */
188268d0ed37SLaurent Vivier             fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */
188368d0ed37SLaurent Vivier 
188468d0ed37SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
188568d0ed37SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
188668d0ed37SLaurent Vivier 
188768d0ed37SLaurent Vivier             a = floatx80_add(fp0, x, status);
188868d0ed37SLaurent Vivier 
188968d0ed37SLaurent Vivier             float_raise(float_flag_inexact, status);
189068d0ed37SLaurent Vivier 
189168d0ed37SLaurent Vivier             return a;
189268d0ed37SLaurent Vivier         }
189368d0ed37SLaurent Vivier     }
189468d0ed37SLaurent Vivier }
18958c992abcSLaurent Vivier 
1896808d77bcSLucien Murray-Pitts /*
1897808d77bcSLucien Murray-Pitts  * Arc tangent
1898808d77bcSLucien Murray-Pitts  */
18998c992abcSLaurent Vivier 
floatx80_atan(floatx80 a,float_status * status)19008c992abcSLaurent Vivier floatx80 floatx80_atan(floatx80 a, float_status *status)
19018c992abcSLaurent Vivier {
1902c120391cSRichard Henderson     bool aSign;
19038c992abcSLaurent Vivier     int32_t aExp;
19048c992abcSLaurent Vivier     uint64_t aSig;
19058c992abcSLaurent Vivier 
1906*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
1907*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
19088c992abcSLaurent Vivier 
19098c992abcSLaurent Vivier     int32_t compact, tbl_index;
19108c992abcSLaurent Vivier     floatx80 fp0, fp1, fp2, fp3, xsave;
19118c992abcSLaurent Vivier 
19128c992abcSLaurent Vivier     aSig = extractFloatx80Frac(a);
19138c992abcSLaurent Vivier     aExp = extractFloatx80Exp(a);
19148c992abcSLaurent Vivier     aSign = extractFloatx80Sign(a);
19158c992abcSLaurent Vivier 
19168c992abcSLaurent Vivier     if (aExp == 0x7FFF) {
19178c992abcSLaurent Vivier         if ((uint64_t) (aSig << 1)) {
19188c992abcSLaurent Vivier             return propagateFloatx80NaNOneArg(a, status);
19198c992abcSLaurent Vivier         }
19208c992abcSLaurent Vivier         a = packFloatx80(aSign, piby2_exp, pi_sig);
19218c992abcSLaurent Vivier         float_raise(float_flag_inexact, status);
19228c992abcSLaurent Vivier         return floatx80_move(a, status);
19238c992abcSLaurent Vivier     }
19248c992abcSLaurent Vivier 
19258c992abcSLaurent Vivier     if (aExp == 0 && aSig == 0) {
19268c992abcSLaurent Vivier         return packFloatx80(aSign, 0, 0);
19278c992abcSLaurent Vivier     }
19288c992abcSLaurent Vivier 
19298c992abcSLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
19308c992abcSLaurent Vivier 
19318c992abcSLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
19328c992abcSLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
19338c992abcSLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
1934*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
19358c992abcSLaurent Vivier 
19368c992abcSLaurent Vivier     if (compact < 0x3FFB8000 || compact > 0x4002FFFF) {
19378c992abcSLaurent Vivier         /* |X| >= 16 or |X| < 1/16 */
19388c992abcSLaurent Vivier         if (compact > 0x3FFF8000) { /* |X| >= 16 */
19398c992abcSLaurent Vivier             if (compact > 0x40638000) { /* |X| > 2^(100) */
19408c992abcSLaurent Vivier                 fp0 = packFloatx80(aSign, piby2_exp, pi_sig);
19418c992abcSLaurent Vivier                 fp1 = packFloatx80(aSign, 0x0001, one_sig);
19428c992abcSLaurent Vivier 
19438c992abcSLaurent Vivier                 status->float_rounding_mode = user_rnd_mode;
19448c992abcSLaurent Vivier                 status->floatx80_rounding_precision = user_rnd_prec;
19458c992abcSLaurent Vivier 
19468c992abcSLaurent Vivier                 a = floatx80_sub(fp0, fp1, status);
19478c992abcSLaurent Vivier 
19488c992abcSLaurent Vivier                 float_raise(float_flag_inexact, status);
19498c992abcSLaurent Vivier 
19508c992abcSLaurent Vivier                 return a;
19518c992abcSLaurent Vivier             } else {
19528c992abcSLaurent Vivier                 fp0 = a;
19538c992abcSLaurent Vivier                 fp1 = packFloatx80(1, one_exp, one_sig); /* -1 */
19548c992abcSLaurent Vivier                 fp1 = floatx80_div(fp1, fp0, status); /* X' = -1/X */
19558c992abcSLaurent Vivier                 xsave = fp1;
19568c992abcSLaurent Vivier                 fp0 = floatx80_mul(fp1, fp1, status); /* Y = X'*X' */
19578c992abcSLaurent Vivier                 fp1 = floatx80_mul(fp0, fp0, status); /* Z = Y*Y */
19588c992abcSLaurent Vivier                 fp3 = float64_to_floatx80(make_float64(0xBFB70BF398539E6A),
19598c992abcSLaurent Vivier                                           status); /* C5 */
19608c992abcSLaurent Vivier                 fp2 = float64_to_floatx80(make_float64(0x3FBC7187962D1D7D),
19618c992abcSLaurent Vivier                                           status); /* C4 */
19628c992abcSLaurent Vivier                 fp3 = floatx80_mul(fp3, fp1, status); /* Z*C5 */
19638c992abcSLaurent Vivier                 fp2 = floatx80_mul(fp2, fp1, status); /* Z*C4 */
19648c992abcSLaurent Vivier                 fp3 = floatx80_add(fp3, float64_to_floatx80(
19658c992abcSLaurent Vivier                                    make_float64(0xBFC24924827107B8), status),
19668c992abcSLaurent Vivier                                    status); /* C3+Z*C5 */
19678c992abcSLaurent Vivier                 fp2 = floatx80_add(fp2, float64_to_floatx80(
19688c992abcSLaurent Vivier                                    make_float64(0x3FC999999996263E), status),
19698c992abcSLaurent Vivier                                    status); /* C2+Z*C4 */
19708c992abcSLaurent Vivier                 fp1 = floatx80_mul(fp1, fp3, status); /* Z*(C3+Z*C5) */
19718c992abcSLaurent Vivier                 fp2 = floatx80_mul(fp2, fp0, status); /* Y*(C2+Z*C4) */
19728c992abcSLaurent Vivier                 fp1 = floatx80_add(fp1, float64_to_floatx80(
19738c992abcSLaurent Vivier                                    make_float64(0xBFD5555555555536), status),
19748c992abcSLaurent Vivier                                    status); /* C1+Z*(C3+Z*C5) */
19758c992abcSLaurent Vivier                 fp0 = floatx80_mul(fp0, xsave, status); /* X'*Y */
19768c992abcSLaurent Vivier                 /* [Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)] */
19778c992abcSLaurent Vivier                 fp1 = floatx80_add(fp1, fp2, status);
19788c992abcSLaurent Vivier                 /* X'*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) ?? */
19798c992abcSLaurent Vivier                 fp0 = floatx80_mul(fp0, fp1, status);
19808c992abcSLaurent Vivier                 fp0 = floatx80_add(fp0, xsave, status);
19818c992abcSLaurent Vivier                 fp1 = packFloatx80(aSign, piby2_exp, pi_sig);
19828c992abcSLaurent Vivier 
19838c992abcSLaurent Vivier                 status->float_rounding_mode = user_rnd_mode;
19848c992abcSLaurent Vivier                 status->floatx80_rounding_precision = user_rnd_prec;
19858c992abcSLaurent Vivier 
19868c992abcSLaurent Vivier                 a = floatx80_add(fp0, fp1, status);
19878c992abcSLaurent Vivier 
19888c992abcSLaurent Vivier                 float_raise(float_flag_inexact, status);
19898c992abcSLaurent Vivier 
19908c992abcSLaurent Vivier                 return a;
19918c992abcSLaurent Vivier             }
19928c992abcSLaurent Vivier         } else { /* |X| < 1/16 */
19938c992abcSLaurent Vivier             if (compact < 0x3FD78000) { /* |X| < 2^(-40) */
19948c992abcSLaurent Vivier                 status->float_rounding_mode = user_rnd_mode;
19958c992abcSLaurent Vivier                 status->floatx80_rounding_precision = user_rnd_prec;
19968c992abcSLaurent Vivier 
19978c992abcSLaurent Vivier                 a = floatx80_move(a, status);
19988c992abcSLaurent Vivier 
19998c992abcSLaurent Vivier                 float_raise(float_flag_inexact, status);
20008c992abcSLaurent Vivier 
20018c992abcSLaurent Vivier                 return a;
20028c992abcSLaurent Vivier             } else {
20038c992abcSLaurent Vivier                 fp0 = a;
20048c992abcSLaurent Vivier                 xsave = a;
20058c992abcSLaurent Vivier                 fp0 = floatx80_mul(fp0, fp0, status); /* Y = X*X */
20068c992abcSLaurent Vivier                 fp1 = floatx80_mul(fp0, fp0, status); /* Z = Y*Y */
20078c992abcSLaurent Vivier                 fp2 = float64_to_floatx80(make_float64(0x3FB344447F876989),
20088c992abcSLaurent Vivier                                           status); /* B6 */
20098c992abcSLaurent Vivier                 fp3 = float64_to_floatx80(make_float64(0xBFB744EE7FAF45DB),
20108c992abcSLaurent Vivier                                           status); /* B5 */
20118c992abcSLaurent Vivier                 fp2 = floatx80_mul(fp2, fp1, status); /* Z*B6 */
20128c992abcSLaurent Vivier                 fp3 = floatx80_mul(fp3, fp1, status); /* Z*B5 */
20138c992abcSLaurent Vivier                 fp2 = floatx80_add(fp2, float64_to_floatx80(
20148c992abcSLaurent Vivier                                    make_float64(0x3FBC71C646940220), status),
20158c992abcSLaurent Vivier                                    status); /* B4+Z*B6 */
20168c992abcSLaurent Vivier                 fp3 = floatx80_add(fp3, float64_to_floatx80(
20178c992abcSLaurent Vivier                                    make_float64(0xBFC24924921872F9),
20188c992abcSLaurent Vivier                                    status), status); /* B3+Z*B5 */
20198c992abcSLaurent Vivier                 fp2 = floatx80_mul(fp2, fp1, status); /* Z*(B4+Z*B6) */
20208c992abcSLaurent Vivier                 fp1 = floatx80_mul(fp1, fp3, status); /* Z*(B3+Z*B5) */
20218c992abcSLaurent Vivier                 fp2 = floatx80_add(fp2, float64_to_floatx80(
20228c992abcSLaurent Vivier                                    make_float64(0x3FC9999999998FA9), status),
20238c992abcSLaurent Vivier                                    status); /* B2+Z*(B4+Z*B6) */
20248c992abcSLaurent Vivier                 fp1 = floatx80_add(fp1, float64_to_floatx80(
20258c992abcSLaurent Vivier                                    make_float64(0xBFD5555555555555), status),
20268c992abcSLaurent Vivier                                    status); /* B1+Z*(B3+Z*B5) */
20278c992abcSLaurent Vivier                 fp2 = floatx80_mul(fp2, fp0, status); /* Y*(B2+Z*(B4+Z*B6)) */
20288c992abcSLaurent Vivier                 fp0 = floatx80_mul(fp0, xsave, status); /* X*Y */
20298c992abcSLaurent Vivier                 /* [B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))] */
20308c992abcSLaurent Vivier                 fp1 = floatx80_add(fp1, fp2, status);
20318c992abcSLaurent Vivier                 /* X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) */
20328c992abcSLaurent Vivier                 fp0 = floatx80_mul(fp0, fp1, status);
20338c992abcSLaurent Vivier 
20348c992abcSLaurent Vivier                 status->float_rounding_mode = user_rnd_mode;
20358c992abcSLaurent Vivier                 status->floatx80_rounding_precision = user_rnd_prec;
20368c992abcSLaurent Vivier 
20378c992abcSLaurent Vivier                 a = floatx80_add(fp0, xsave, status);
20388c992abcSLaurent Vivier 
20398c992abcSLaurent Vivier                 float_raise(float_flag_inexact, status);
20408c992abcSLaurent Vivier 
20418c992abcSLaurent Vivier                 return a;
20428c992abcSLaurent Vivier             }
20438c992abcSLaurent Vivier         }
20448c992abcSLaurent Vivier     } else {
2045e2326300SAlex Bennée         aSig &= UINT64_C(0xF800000000000000);
2046e2326300SAlex Bennée         aSig |= UINT64_C(0x0400000000000000);
20478c992abcSLaurent Vivier         xsave = packFloatx80(aSign, aExp, aSig); /* F */
20488c992abcSLaurent Vivier         fp0 = a;
20498c992abcSLaurent Vivier         fp1 = a; /* X */
20508c992abcSLaurent Vivier         fp2 = packFloatx80(0, one_exp, one_sig); /* 1 */
20518c992abcSLaurent Vivier         fp1 = floatx80_mul(fp1, xsave, status); /* X*F */
20528c992abcSLaurent Vivier         fp0 = floatx80_sub(fp0, xsave, status); /* X-F */
20538c992abcSLaurent Vivier         fp1 = floatx80_add(fp1, fp2, status); /* 1 + X*F */
20548c992abcSLaurent Vivier         fp0 = floatx80_div(fp0, fp1, status); /* U = (X-F)/(1+X*F) */
20558c992abcSLaurent Vivier 
20568c992abcSLaurent Vivier         tbl_index = compact;
20578c992abcSLaurent Vivier 
20588c992abcSLaurent Vivier         tbl_index &= 0x7FFF0000;
20598c992abcSLaurent Vivier         tbl_index -= 0x3FFB0000;
20608c992abcSLaurent Vivier         tbl_index >>= 1;
20618c992abcSLaurent Vivier         tbl_index += compact & 0x00007800;
20628c992abcSLaurent Vivier         tbl_index >>= 11;
20638c992abcSLaurent Vivier 
20648c992abcSLaurent Vivier         fp3 = atan_tbl[tbl_index];
20658c992abcSLaurent Vivier 
20668c992abcSLaurent Vivier         fp3.high |= aSign ? 0x8000 : 0; /* ATAN(F) */
20678c992abcSLaurent Vivier 
20688c992abcSLaurent Vivier         fp1 = floatx80_mul(fp0, fp0, status); /* V = U*U */
20698c992abcSLaurent Vivier         fp2 = float64_to_floatx80(make_float64(0xBFF6687E314987D8),
20708c992abcSLaurent Vivier                                   status); /* A3 */
20718c992abcSLaurent Vivier         fp2 = floatx80_add(fp2, fp1, status); /* A3+V */
20728c992abcSLaurent Vivier         fp2 = floatx80_mul(fp2, fp1, status); /* V*(A3+V) */
20738c992abcSLaurent Vivier         fp1 = floatx80_mul(fp1, fp0, status); /* U*V */
20748c992abcSLaurent Vivier         fp2 = floatx80_add(fp2, float64_to_floatx80(
20758c992abcSLaurent Vivier                            make_float64(0x4002AC6934A26DB3), status),
20768c992abcSLaurent Vivier                            status); /* A2+V*(A3+V) */
20778c992abcSLaurent Vivier         fp1 = floatx80_mul(fp1, float64_to_floatx80(
20788c992abcSLaurent Vivier                            make_float64(0xBFC2476F4E1DA28E), status),
20798c992abcSLaurent Vivier                            status); /* A1+U*V */
20808c992abcSLaurent Vivier         fp1 = floatx80_mul(fp1, fp2, status); /* A1*U*V*(A2+V*(A3+V)) */
20818c992abcSLaurent Vivier         fp0 = floatx80_add(fp0, fp1, status); /* ATAN(U) */
20828c992abcSLaurent Vivier 
20838c992abcSLaurent Vivier         status->float_rounding_mode = user_rnd_mode;
20848c992abcSLaurent Vivier         status->floatx80_rounding_precision = user_rnd_prec;
20858c992abcSLaurent Vivier 
20868c992abcSLaurent Vivier         a = floatx80_add(fp0, fp3, status); /* ATAN(X) */
20878c992abcSLaurent Vivier 
20888c992abcSLaurent Vivier         float_raise(float_flag_inexact, status);
20898c992abcSLaurent Vivier 
20908c992abcSLaurent Vivier         return a;
20918c992abcSLaurent Vivier     }
20928c992abcSLaurent Vivier }
2093bc20b34eSLaurent Vivier 
2094808d77bcSLucien Murray-Pitts /*
2095808d77bcSLucien Murray-Pitts  * Arc sine
2096808d77bcSLucien Murray-Pitts  */
2097bc20b34eSLaurent Vivier 
floatx80_asin(floatx80 a,float_status * status)2098bc20b34eSLaurent Vivier floatx80 floatx80_asin(floatx80 a, float_status *status)
2099bc20b34eSLaurent Vivier {
2100c120391cSRichard Henderson     bool aSign;
2101bc20b34eSLaurent Vivier     int32_t aExp;
2102bc20b34eSLaurent Vivier     uint64_t aSig;
2103bc20b34eSLaurent Vivier 
2104*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
2105*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
2106bc20b34eSLaurent Vivier 
2107bc20b34eSLaurent Vivier     int32_t compact;
2108bc20b34eSLaurent Vivier     floatx80 fp0, fp1, fp2, one;
2109bc20b34eSLaurent Vivier 
2110bc20b34eSLaurent Vivier     aSig = extractFloatx80Frac(a);
2111bc20b34eSLaurent Vivier     aExp = extractFloatx80Exp(a);
2112bc20b34eSLaurent Vivier     aSign = extractFloatx80Sign(a);
2113bc20b34eSLaurent Vivier 
2114bc20b34eSLaurent Vivier     if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
2115bc20b34eSLaurent Vivier         return propagateFloatx80NaNOneArg(a, status);
2116bc20b34eSLaurent Vivier     }
2117bc20b34eSLaurent Vivier 
2118bc20b34eSLaurent Vivier     if (aExp == 0 && aSig == 0) {
2119bc20b34eSLaurent Vivier         return packFloatx80(aSign, 0, 0);
2120bc20b34eSLaurent Vivier     }
2121bc20b34eSLaurent Vivier 
2122bc20b34eSLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
2123bc20b34eSLaurent Vivier 
2124bc20b34eSLaurent Vivier     if (compact >= 0x3FFF8000) { /* |X| >= 1 */
2125bc20b34eSLaurent Vivier         if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
2126bc20b34eSLaurent Vivier             float_raise(float_flag_inexact, status);
2127bc20b34eSLaurent Vivier             a = packFloatx80(aSign, piby2_exp, pi_sig);
2128bc20b34eSLaurent Vivier             return floatx80_move(a, status);
2129bc20b34eSLaurent Vivier         } else { /* |X| > 1 */
2130bc20b34eSLaurent Vivier             float_raise(float_flag_invalid, status);
2131bc20b34eSLaurent Vivier             return floatx80_default_nan(status);
2132bc20b34eSLaurent Vivier         }
2133bc20b34eSLaurent Vivier 
2134bc20b34eSLaurent Vivier     } /* |X| < 1 */
2135bc20b34eSLaurent Vivier 
2136bc20b34eSLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
2137bc20b34eSLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
2138bc20b34eSLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
2139*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
2140bc20b34eSLaurent Vivier 
2141bc20b34eSLaurent Vivier     one = packFloatx80(0, one_exp, one_sig);
2142bc20b34eSLaurent Vivier     fp0 = a;
2143bc20b34eSLaurent Vivier 
2144bc20b34eSLaurent Vivier     fp1 = floatx80_sub(one, fp0, status);   /* 1 - X */
2145bc20b34eSLaurent Vivier     fp2 = floatx80_add(one, fp0, status);   /* 1 + X */
2146bc20b34eSLaurent Vivier     fp1 = floatx80_mul(fp2, fp1, status);   /* (1+X)*(1-X) */
2147bc20b34eSLaurent Vivier     fp1 = floatx80_sqrt(fp1, status);       /* SQRT((1+X)*(1-X)) */
2148bc20b34eSLaurent Vivier     fp0 = floatx80_div(fp0, fp1, status);   /* X/SQRT((1+X)*(1-X)) */
2149bc20b34eSLaurent Vivier 
2150bc20b34eSLaurent Vivier     status->float_rounding_mode = user_rnd_mode;
2151bc20b34eSLaurent Vivier     status->floatx80_rounding_precision = user_rnd_prec;
2152bc20b34eSLaurent Vivier 
2153bc20b34eSLaurent Vivier     a = floatx80_atan(fp0, status);         /* ATAN(X/SQRT((1+X)*(1-X))) */
2154bc20b34eSLaurent Vivier 
2155bc20b34eSLaurent Vivier     float_raise(float_flag_inexact, status);
2156bc20b34eSLaurent Vivier 
2157bc20b34eSLaurent Vivier     return a;
2158bc20b34eSLaurent Vivier }
2159c84813b8SLaurent Vivier 
2160808d77bcSLucien Murray-Pitts /*
2161808d77bcSLucien Murray-Pitts  * Arc cosine
2162808d77bcSLucien Murray-Pitts  */
2163c84813b8SLaurent Vivier 
floatx80_acos(floatx80 a,float_status * status)2164c84813b8SLaurent Vivier floatx80 floatx80_acos(floatx80 a, float_status *status)
2165c84813b8SLaurent Vivier {
2166c120391cSRichard Henderson     bool aSign;
2167c84813b8SLaurent Vivier     int32_t aExp;
2168c84813b8SLaurent Vivier     uint64_t aSig;
2169c84813b8SLaurent Vivier 
2170*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
2171*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
2172c84813b8SLaurent Vivier 
2173c84813b8SLaurent Vivier     int32_t compact;
2174c84813b8SLaurent Vivier     floatx80 fp0, fp1, one;
2175c84813b8SLaurent Vivier 
2176c84813b8SLaurent Vivier     aSig = extractFloatx80Frac(a);
2177c84813b8SLaurent Vivier     aExp = extractFloatx80Exp(a);
2178c84813b8SLaurent Vivier     aSign = extractFloatx80Sign(a);
2179c84813b8SLaurent Vivier 
2180c84813b8SLaurent Vivier     if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
2181c84813b8SLaurent Vivier         return propagateFloatx80NaNOneArg(a, status);
2182c84813b8SLaurent Vivier     }
2183c84813b8SLaurent Vivier     if (aExp == 0 && aSig == 0) {
2184c84813b8SLaurent Vivier         float_raise(float_flag_inexact, status);
2185c84813b8SLaurent Vivier         return roundAndPackFloatx80(status->floatx80_rounding_precision, 0,
2186c84813b8SLaurent Vivier                                     piby2_exp, pi_sig, 0, status);
2187c84813b8SLaurent Vivier     }
2188c84813b8SLaurent Vivier 
2189c84813b8SLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
2190c84813b8SLaurent Vivier 
2191c84813b8SLaurent Vivier     if (compact >= 0x3FFF8000) { /* |X| >= 1 */
2192c84813b8SLaurent Vivier         if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
2193c84813b8SLaurent Vivier             if (aSign) { /* X == -1 */
2194c84813b8SLaurent Vivier                 a = packFloatx80(0, pi_exp, pi_sig);
2195c84813b8SLaurent Vivier                 float_raise(float_flag_inexact, status);
2196c84813b8SLaurent Vivier                 return floatx80_move(a, status);
2197c84813b8SLaurent Vivier             } else { /* X == +1 */
2198c84813b8SLaurent Vivier                 return packFloatx80(0, 0, 0);
2199c84813b8SLaurent Vivier             }
2200c84813b8SLaurent Vivier         } else { /* |X| > 1 */
2201c84813b8SLaurent Vivier             float_raise(float_flag_invalid, status);
2202c84813b8SLaurent Vivier             return floatx80_default_nan(status);
2203c84813b8SLaurent Vivier         }
2204c84813b8SLaurent Vivier     } /* |X| < 1 */
2205c84813b8SLaurent Vivier 
2206c84813b8SLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
2207c84813b8SLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
2208c84813b8SLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
2209*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
2210c84813b8SLaurent Vivier 
2211c84813b8SLaurent Vivier     one = packFloatx80(0, one_exp, one_sig);
2212c84813b8SLaurent Vivier     fp0 = a;
2213c84813b8SLaurent Vivier 
2214c84813b8SLaurent Vivier     fp1 = floatx80_add(one, fp0, status);   /* 1 + X */
2215c84813b8SLaurent Vivier     fp0 = floatx80_sub(one, fp0, status);   /* 1 - X */
2216c84813b8SLaurent Vivier     fp0 = floatx80_div(fp0, fp1, status);   /* (1-X)/(1+X) */
2217c84813b8SLaurent Vivier     fp0 = floatx80_sqrt(fp0, status);       /* SQRT((1-X)/(1+X)) */
2218c84813b8SLaurent Vivier     fp0 = floatx80_atan(fp0, status);       /* ATAN(SQRT((1-X)/(1+X))) */
2219c84813b8SLaurent Vivier 
2220c84813b8SLaurent Vivier     status->float_rounding_mode = user_rnd_mode;
2221c84813b8SLaurent Vivier     status->floatx80_rounding_precision = user_rnd_prec;
2222c84813b8SLaurent Vivier 
2223c84813b8SLaurent Vivier     a = floatx80_add(fp0, fp0, status);     /* 2 * ATAN(SQRT((1-X)/(1+X))) */
2224c84813b8SLaurent Vivier 
2225c84813b8SLaurent Vivier     float_raise(float_flag_inexact, status);
2226c84813b8SLaurent Vivier 
2227c84813b8SLaurent Vivier     return a;
2228c84813b8SLaurent Vivier }
2229e3655afaSLaurent Vivier 
2230808d77bcSLucien Murray-Pitts /*
2231808d77bcSLucien Murray-Pitts  * Hyperbolic arc tangent
2232808d77bcSLucien Murray-Pitts  */
2233e3655afaSLaurent Vivier 
floatx80_atanh(floatx80 a,float_status * status)2234e3655afaSLaurent Vivier floatx80 floatx80_atanh(floatx80 a, float_status *status)
2235e3655afaSLaurent Vivier {
2236c120391cSRichard Henderson     bool aSign;
2237e3655afaSLaurent Vivier     int32_t aExp;
2238e3655afaSLaurent Vivier     uint64_t aSig;
2239e3655afaSLaurent Vivier 
2240*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
2241*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
2242e3655afaSLaurent Vivier 
2243e3655afaSLaurent Vivier     int32_t compact;
2244e3655afaSLaurent Vivier     floatx80 fp0, fp1, fp2, one;
2245e3655afaSLaurent Vivier 
2246e3655afaSLaurent Vivier     aSig = extractFloatx80Frac(a);
2247e3655afaSLaurent Vivier     aExp = extractFloatx80Exp(a);
2248e3655afaSLaurent Vivier     aSign = extractFloatx80Sign(a);
2249e3655afaSLaurent Vivier 
2250e3655afaSLaurent Vivier     if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
2251e3655afaSLaurent Vivier         return propagateFloatx80NaNOneArg(a, status);
2252e3655afaSLaurent Vivier     }
2253e3655afaSLaurent Vivier 
2254e3655afaSLaurent Vivier     if (aExp == 0 && aSig == 0) {
2255e3655afaSLaurent Vivier         return packFloatx80(aSign, 0, 0);
2256e3655afaSLaurent Vivier     }
2257e3655afaSLaurent Vivier 
2258e3655afaSLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
2259e3655afaSLaurent Vivier 
2260e3655afaSLaurent Vivier     if (compact >= 0x3FFF8000) { /* |X| >= 1 */
2261e3655afaSLaurent Vivier         if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
2262e3655afaSLaurent Vivier             float_raise(float_flag_divbyzero, status);
2263e3655afaSLaurent Vivier             return packFloatx80(aSign, floatx80_infinity.high,
2264e3655afaSLaurent Vivier                                 floatx80_infinity.low);
2265e3655afaSLaurent Vivier         } else { /* |X| > 1 */
2266e3655afaSLaurent Vivier             float_raise(float_flag_invalid, status);
2267e3655afaSLaurent Vivier             return floatx80_default_nan(status);
2268e3655afaSLaurent Vivier         }
2269e3655afaSLaurent Vivier     } /* |X| < 1 */
2270e3655afaSLaurent Vivier 
2271e3655afaSLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
2272e3655afaSLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
2273e3655afaSLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
2274*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
2275e3655afaSLaurent Vivier 
2276e3655afaSLaurent Vivier     one = packFloatx80(0, one_exp, one_sig);
2277e3655afaSLaurent Vivier     fp2 = packFloatx80(aSign, 0x3FFE, one_sig); /* SIGN(X) * (1/2) */
2278e3655afaSLaurent Vivier     fp0 = packFloatx80(0, aExp, aSig); /* Y = |X| */
2279e3655afaSLaurent Vivier     fp1 = packFloatx80(1, aExp, aSig); /* -Y */
2280e3655afaSLaurent Vivier     fp0 = floatx80_add(fp0, fp0, status); /* 2Y */
2281e3655afaSLaurent Vivier     fp1 = floatx80_add(fp1, one, status); /* 1-Y */
2282e3655afaSLaurent Vivier     fp0 = floatx80_div(fp0, fp1, status); /* Z = 2Y/(1-Y) */
2283e3655afaSLaurent Vivier     fp0 = floatx80_lognp1(fp0, status); /* LOG1P(Z) */
2284e3655afaSLaurent Vivier 
2285e3655afaSLaurent Vivier     status->float_rounding_mode = user_rnd_mode;
2286e3655afaSLaurent Vivier     status->floatx80_rounding_precision = user_rnd_prec;
2287e3655afaSLaurent Vivier 
2288e3655afaSLaurent Vivier     a = floatx80_mul(fp0, fp2,
2289e3655afaSLaurent Vivier                      status); /* ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z) */
2290e3655afaSLaurent Vivier 
2291e3655afaSLaurent Vivier     float_raise(float_flag_inexact, status);
2292e3655afaSLaurent Vivier 
2293e3655afaSLaurent Vivier     return a;
2294e3655afaSLaurent Vivier }
22959937b029SLaurent Vivier 
2296808d77bcSLucien Murray-Pitts /*
2297808d77bcSLucien Murray-Pitts  * e to x minus 1
2298808d77bcSLucien Murray-Pitts  */
22999937b029SLaurent Vivier 
floatx80_etoxm1(floatx80 a,float_status * status)23009937b029SLaurent Vivier floatx80 floatx80_etoxm1(floatx80 a, float_status *status)
23019937b029SLaurent Vivier {
2302c120391cSRichard Henderson     bool aSign;
23039937b029SLaurent Vivier     int32_t aExp;
23049937b029SLaurent Vivier     uint64_t aSig;
23059937b029SLaurent Vivier 
2306*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
2307*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
23089937b029SLaurent Vivier 
23099937b029SLaurent Vivier     int32_t compact, n, j, m, m1;
23109937b029SLaurent Vivier     floatx80 fp0, fp1, fp2, fp3, l2, sc, onebysc;
23119937b029SLaurent Vivier 
23129937b029SLaurent Vivier     aSig = extractFloatx80Frac(a);
23139937b029SLaurent Vivier     aExp = extractFloatx80Exp(a);
23149937b029SLaurent Vivier     aSign = extractFloatx80Sign(a);
23159937b029SLaurent Vivier 
23169937b029SLaurent Vivier     if (aExp == 0x7FFF) {
23179937b029SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
23189937b029SLaurent Vivier             return propagateFloatx80NaNOneArg(a, status);
23199937b029SLaurent Vivier         }
23209937b029SLaurent Vivier         if (aSign) {
23219937b029SLaurent Vivier             return packFloatx80(aSign, one_exp, one_sig);
23229937b029SLaurent Vivier         }
23239937b029SLaurent Vivier         return packFloatx80(0, floatx80_infinity.high,
23249937b029SLaurent Vivier                             floatx80_infinity.low);
23259937b029SLaurent Vivier     }
23269937b029SLaurent Vivier 
23279937b029SLaurent Vivier     if (aExp == 0 && aSig == 0) {
23289937b029SLaurent Vivier         return packFloatx80(aSign, 0, 0);
23299937b029SLaurent Vivier     }
23309937b029SLaurent Vivier 
23319937b029SLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
23329937b029SLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
23339937b029SLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
2334*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
23359937b029SLaurent Vivier 
23369937b029SLaurent Vivier     if (aExp >= 0x3FFD) { /* |X| >= 1/4 */
23379937b029SLaurent Vivier         compact = floatx80_make_compact(aExp, aSig);
23389937b029SLaurent Vivier 
23399937b029SLaurent Vivier         if (compact <= 0x4004C215) { /* |X| <= 70 log2 */
23409937b029SLaurent Vivier             fp0 = a;
23419937b029SLaurent Vivier             fp1 = a;
23429937b029SLaurent Vivier             fp0 = floatx80_mul(fp0, float32_to_floatx80(
23439937b029SLaurent Vivier                                make_float32(0x42B8AA3B), status),
23449937b029SLaurent Vivier                                status); /* 64/log2 * X */
23459937b029SLaurent Vivier             n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
23469937b029SLaurent Vivier             fp0 = int32_to_floatx80(n, status);
23479937b029SLaurent Vivier 
23489937b029SLaurent Vivier             j = n & 0x3F; /* J = N mod 64 */
23499937b029SLaurent Vivier             m = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
23509937b029SLaurent Vivier             if (n < 0 && j) {
2351808d77bcSLucien Murray-Pitts                 /*
2352808d77bcSLucien Murray-Pitts                  * arithmetic right shift is division and
23539937b029SLaurent Vivier                  * round towards minus infinity
23549937b029SLaurent Vivier                  */
23559937b029SLaurent Vivier                 m--;
23569937b029SLaurent Vivier             }
23579937b029SLaurent Vivier             m1 = -m;
23589937b029SLaurent Vivier             /*m += 0x3FFF; // biased exponent of 2^(M) */
23599937b029SLaurent Vivier             /*m1 += 0x3FFF; // biased exponent of -2^(-M) */
23609937b029SLaurent Vivier 
23619937b029SLaurent Vivier             fp2 = fp0; /* N */
23629937b029SLaurent Vivier             fp0 = floatx80_mul(fp0, float32_to_floatx80(
23639937b029SLaurent Vivier                                make_float32(0xBC317218), status),
23649937b029SLaurent Vivier                                status); /* N * L1, L1 = lead(-log2/64) */
2365e2326300SAlex Bennée             l2 = packFloatx80(0, 0x3FDC, UINT64_C(0x82E308654361C4C6));
23669937b029SLaurent Vivier             fp2 = floatx80_mul(fp2, l2, status); /* N * L2, L1+L2 = -log2/64 */
23679937b029SLaurent Vivier             fp0 = floatx80_add(fp0, fp1, status); /* X + N*L1 */
23689937b029SLaurent Vivier             fp0 = floatx80_add(fp0, fp2, status); /* R */
23699937b029SLaurent Vivier 
23709937b029SLaurent Vivier             fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
23719937b029SLaurent Vivier             fp2 = float32_to_floatx80(make_float32(0x3950097B),
23729937b029SLaurent Vivier                                       status); /* A6 */
23739937b029SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*A6 */
23749937b029SLaurent Vivier             fp3 = floatx80_mul(float32_to_floatx80(make_float32(0x3AB60B6A),
23759937b029SLaurent Vivier                                status), fp1, status); /* fp3 is S*A5 */
23769937b029SLaurent Vivier             fp2 = floatx80_add(fp2, float64_to_floatx80(
23779937b029SLaurent Vivier                                make_float64(0x3F81111111174385), status),
23789937b029SLaurent Vivier                                status); /* fp2 IS A4+S*A6 */
23799937b029SLaurent Vivier             fp3 = floatx80_add(fp3, float64_to_floatx80(
23809937b029SLaurent Vivier                                make_float64(0x3FA5555555554F5A), status),
23819937b029SLaurent Vivier                                status); /* fp3 is A3+S*A5 */
23829937b029SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1, status); /* fp2 IS S*(A4+S*A6) */
23839937b029SLaurent Vivier             fp3 = floatx80_mul(fp3, fp1, status); /* fp3 IS S*(A3+S*A5) */
23849937b029SLaurent Vivier             fp2 = floatx80_add(fp2, float64_to_floatx80(
23859937b029SLaurent Vivier                                make_float64(0x3FC5555555555555), status),
23869937b029SLaurent Vivier                                status); /* fp2 IS A2+S*(A4+S*A6) */
23879937b029SLaurent Vivier             fp3 = floatx80_add(fp3, float32_to_floatx80(
23889937b029SLaurent Vivier                                make_float32(0x3F000000), status),
23899937b029SLaurent Vivier                                status); /* fp3 IS A1+S*(A3+S*A5) */
23909937b029SLaurent Vivier             fp2 = floatx80_mul(fp2, fp1,
23919937b029SLaurent Vivier                                status); /* fp2 IS S*(A2+S*(A4+S*A6)) */
23929937b029SLaurent Vivier             fp1 = floatx80_mul(fp1, fp3,
23939937b029SLaurent Vivier                                status); /* fp1 IS S*(A1+S*(A3+S*A5)) */
23949937b029SLaurent Vivier             fp2 = floatx80_mul(fp2, fp0,
23959937b029SLaurent Vivier                                status); /* fp2 IS R*S*(A2+S*(A4+S*A6)) */
23969937b029SLaurent Vivier             fp0 = floatx80_add(fp0, fp1,
23979937b029SLaurent Vivier                                status); /* fp0 IS R+S*(A1+S*(A3+S*A5)) */
23989937b029SLaurent Vivier             fp0 = floatx80_add(fp0, fp2, status); /* fp0 IS EXP(R) - 1 */
23999937b029SLaurent Vivier 
24009937b029SLaurent Vivier             fp0 = floatx80_mul(fp0, exp_tbl[j],
24019937b029SLaurent Vivier                                status); /* 2^(J/64)*(Exp(R)-1) */
24029937b029SLaurent Vivier 
24039937b029SLaurent Vivier             if (m >= 64) {
24049937b029SLaurent Vivier                 fp1 = float32_to_floatx80(exp_tbl2[j], status);
24059937b029SLaurent Vivier                 onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
24069937b029SLaurent Vivier                 fp1 = floatx80_add(fp1, onebysc, status);
24079937b029SLaurent Vivier                 fp0 = floatx80_add(fp0, fp1, status);
24089937b029SLaurent Vivier                 fp0 = floatx80_add(fp0, exp_tbl[j], status);
24099937b029SLaurent Vivier             } else if (m < -3) {
24109937b029SLaurent Vivier                 fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j],
24119937b029SLaurent Vivier                                    status), status);
24129937b029SLaurent Vivier                 fp0 = floatx80_add(fp0, exp_tbl[j], status);
24139937b029SLaurent Vivier                 onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
24149937b029SLaurent Vivier                 fp0 = floatx80_add(fp0, onebysc, status);
24159937b029SLaurent Vivier             } else { /* -3 <= m <= 63 */
24169937b029SLaurent Vivier                 fp1 = exp_tbl[j];
24179937b029SLaurent Vivier                 fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j],
24189937b029SLaurent Vivier                                    status), status);
24199937b029SLaurent Vivier                 onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
24209937b029SLaurent Vivier                 fp1 = floatx80_add(fp1, onebysc, status);
24219937b029SLaurent Vivier                 fp0 = floatx80_add(fp0, fp1, status);
24229937b029SLaurent Vivier             }
24239937b029SLaurent Vivier 
24249937b029SLaurent Vivier             sc = packFloatx80(0, m + 0x3FFF, one_sig);
24259937b029SLaurent Vivier 
24269937b029SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
24279937b029SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
24289937b029SLaurent Vivier 
24299937b029SLaurent Vivier             a = floatx80_mul(fp0, sc, status);
24309937b029SLaurent Vivier 
24319937b029SLaurent Vivier             float_raise(float_flag_inexact, status);
24329937b029SLaurent Vivier 
24339937b029SLaurent Vivier             return a;
24349937b029SLaurent Vivier         } else { /* |X| > 70 log2 */
24359937b029SLaurent Vivier             if (aSign) {
24369937b029SLaurent Vivier                 fp0 = float32_to_floatx80(make_float32(0xBF800000),
24379937b029SLaurent Vivier                       status); /* -1 */
24389937b029SLaurent Vivier 
24399937b029SLaurent Vivier                 status->float_rounding_mode = user_rnd_mode;
24409937b029SLaurent Vivier                 status->floatx80_rounding_precision = user_rnd_prec;
24419937b029SLaurent Vivier 
24429937b029SLaurent Vivier                 a = floatx80_add(fp0, float32_to_floatx80(
24439937b029SLaurent Vivier                                  make_float32(0x00800000), status),
24449937b029SLaurent Vivier                                  status); /* -1 + 2^(-126) */
24459937b029SLaurent Vivier 
24469937b029SLaurent Vivier                 float_raise(float_flag_inexact, status);
24479937b029SLaurent Vivier 
24489937b029SLaurent Vivier                 return a;
24499937b029SLaurent Vivier             } else {
24509937b029SLaurent Vivier                 status->float_rounding_mode = user_rnd_mode;
24519937b029SLaurent Vivier                 status->floatx80_rounding_precision = user_rnd_prec;
24529937b029SLaurent Vivier 
24539937b029SLaurent Vivier                 return floatx80_etox(a, status);
24549937b029SLaurent Vivier             }
24559937b029SLaurent Vivier         }
24569937b029SLaurent Vivier     } else { /* |X| < 1/4 */
24579937b029SLaurent Vivier         if (aExp >= 0x3FBE) {
24589937b029SLaurent Vivier             fp0 = a;
24599937b029SLaurent Vivier             fp0 = floatx80_mul(fp0, fp0, status); /* S = X*X */
24609937b029SLaurent Vivier             fp1 = float32_to_floatx80(make_float32(0x2F30CAA8),
24619937b029SLaurent Vivier                                       status); /* B12 */
24629937b029SLaurent Vivier             fp1 = floatx80_mul(fp1, fp0, status); /* S * B12 */
24639937b029SLaurent Vivier             fp2 = float32_to_floatx80(make_float32(0x310F8290),
24649937b029SLaurent Vivier                                       status); /* B11 */
24659937b029SLaurent Vivier             fp1 = floatx80_add(fp1, float32_to_floatx80(
24669937b029SLaurent Vivier                                make_float32(0x32D73220), status),
24679937b029SLaurent Vivier                                status); /* B10 */
24689937b029SLaurent Vivier             fp2 = floatx80_mul(fp2, fp0, status);
24699937b029SLaurent Vivier             fp1 = floatx80_mul(fp1, fp0, status);
24709937b029SLaurent Vivier             fp2 = floatx80_add(fp2, float32_to_floatx80(
24719937b029SLaurent Vivier                                make_float32(0x3493F281), status),
24729937b029SLaurent Vivier                                status); /* B9 */
24739937b029SLaurent Vivier             fp1 = floatx80_add(fp1, float64_to_floatx80(
24749937b029SLaurent Vivier                                make_float64(0x3EC71DE3A5774682), status),
24759937b029SLaurent Vivier                                status); /* B8 */
24769937b029SLaurent Vivier             fp2 = floatx80_mul(fp2, fp0, status);
24779937b029SLaurent Vivier             fp1 = floatx80_mul(fp1, fp0, status);
24789937b029SLaurent Vivier             fp2 = floatx80_add(fp2, float64_to_floatx80(
24799937b029SLaurent Vivier                                make_float64(0x3EFA01A019D7CB68), status),
24809937b029SLaurent Vivier                                status); /* B7 */
24819937b029SLaurent Vivier             fp1 = floatx80_add(fp1, float64_to_floatx80(
24829937b029SLaurent Vivier                                make_float64(0x3F2A01A01A019DF3), status),
24839937b029SLaurent Vivier                                status); /* B6 */
24849937b029SLaurent Vivier             fp2 = floatx80_mul(fp2, fp0, status);
24859937b029SLaurent Vivier             fp1 = floatx80_mul(fp1, fp0, status);
24869937b029SLaurent Vivier             fp2 = floatx80_add(fp2, float64_to_floatx80(
24879937b029SLaurent Vivier                                make_float64(0x3F56C16C16C170E2), status),
24889937b029SLaurent Vivier                                status); /* B5 */
24899937b029SLaurent Vivier             fp1 = floatx80_add(fp1, float64_to_floatx80(
24909937b029SLaurent Vivier                                make_float64(0x3F81111111111111), status),
24919937b029SLaurent Vivier                                status); /* B4 */
24929937b029SLaurent Vivier             fp2 = floatx80_mul(fp2, fp0, status);
24939937b029SLaurent Vivier             fp1 = floatx80_mul(fp1, fp0, status);
24949937b029SLaurent Vivier             fp2 = floatx80_add(fp2, float64_to_floatx80(
24959937b029SLaurent Vivier                                make_float64(0x3FA5555555555555), status),
24969937b029SLaurent Vivier                                status); /* B3 */
2497e2326300SAlex Bennée             fp3 = packFloatx80(0, 0x3FFC, UINT64_C(0xAAAAAAAAAAAAAAAB));
24989937b029SLaurent Vivier             fp1 = floatx80_add(fp1, fp3, status); /* B2 */
24999937b029SLaurent Vivier             fp2 = floatx80_mul(fp2, fp0, status);
25009937b029SLaurent Vivier             fp1 = floatx80_mul(fp1, fp0, status);
25019937b029SLaurent Vivier 
25029937b029SLaurent Vivier             fp2 = floatx80_mul(fp2, fp0, status);
25039937b029SLaurent Vivier             fp1 = floatx80_mul(fp1, a, status);
25049937b029SLaurent Vivier 
25059937b029SLaurent Vivier             fp0 = floatx80_mul(fp0, float32_to_floatx80(
25069937b029SLaurent Vivier                                make_float32(0x3F000000), status),
25079937b029SLaurent Vivier                                status); /* S*B1 */
25089937b029SLaurent Vivier             fp1 = floatx80_add(fp1, fp2, status); /* Q */
25099937b029SLaurent Vivier             fp0 = floatx80_add(fp0, fp1, status); /* S*B1+Q */
25109937b029SLaurent Vivier 
25119937b029SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
25129937b029SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
25139937b029SLaurent Vivier 
25149937b029SLaurent Vivier             a = floatx80_add(fp0, a, status);
25159937b029SLaurent Vivier 
25169937b029SLaurent Vivier             float_raise(float_flag_inexact, status);
25179937b029SLaurent Vivier 
25189937b029SLaurent Vivier             return a;
25199937b029SLaurent Vivier         } else { /* |X| < 2^(-65) */
25209937b029SLaurent Vivier             sc = packFloatx80(1, 1, one_sig);
25219937b029SLaurent Vivier             fp0 = a;
25229937b029SLaurent Vivier 
25239937b029SLaurent Vivier             if (aExp < 0x0033) { /* |X| < 2^(-16382) */
25249937b029SLaurent Vivier                 fp0 = floatx80_mul(fp0, float64_to_floatx80(
25259937b029SLaurent Vivier                                    make_float64(0x48B0000000000000), status),
25269937b029SLaurent Vivier                                    status);
25279937b029SLaurent Vivier                 fp0 = floatx80_add(fp0, sc, status);
25289937b029SLaurent Vivier 
25299937b029SLaurent Vivier                 status->float_rounding_mode = user_rnd_mode;
25309937b029SLaurent Vivier                 status->floatx80_rounding_precision = user_rnd_prec;
25319937b029SLaurent Vivier 
25329937b029SLaurent Vivier                 a = floatx80_mul(fp0, float64_to_floatx80(
25339937b029SLaurent Vivier                                  make_float64(0x3730000000000000), status),
25349937b029SLaurent Vivier                                  status);
25359937b029SLaurent Vivier             } else {
25369937b029SLaurent Vivier                 status->float_rounding_mode = user_rnd_mode;
25379937b029SLaurent Vivier                 status->floatx80_rounding_precision = user_rnd_prec;
25389937b029SLaurent Vivier 
25399937b029SLaurent Vivier                 a = floatx80_add(fp0, sc, status);
25409937b029SLaurent Vivier             }
25419937b029SLaurent Vivier 
25429937b029SLaurent Vivier             float_raise(float_flag_inexact, status);
25439937b029SLaurent Vivier 
25449937b029SLaurent Vivier             return a;
25459937b029SLaurent Vivier         }
25469937b029SLaurent Vivier     }
25479937b029SLaurent Vivier }
25489937b029SLaurent Vivier 
2549808d77bcSLucien Murray-Pitts /*
2550808d77bcSLucien Murray-Pitts  * Hyperbolic tangent
2551808d77bcSLucien Murray-Pitts  */
25529937b029SLaurent Vivier 
floatx80_tanh(floatx80 a,float_status * status)25539937b029SLaurent Vivier floatx80 floatx80_tanh(floatx80 a, float_status *status)
25549937b029SLaurent Vivier {
2555c120391cSRichard Henderson     bool aSign, vSign;
25569937b029SLaurent Vivier     int32_t aExp, vExp;
25579937b029SLaurent Vivier     uint64_t aSig, vSig;
25589937b029SLaurent Vivier 
2559*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
2560*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
25619937b029SLaurent Vivier 
25629937b029SLaurent Vivier     int32_t compact;
25639937b029SLaurent Vivier     floatx80 fp0, fp1;
25649937b029SLaurent Vivier     uint32_t sign;
25659937b029SLaurent Vivier 
25669937b029SLaurent Vivier     aSig = extractFloatx80Frac(a);
25679937b029SLaurent Vivier     aExp = extractFloatx80Exp(a);
25689937b029SLaurent Vivier     aSign = extractFloatx80Sign(a);
25699937b029SLaurent Vivier 
25709937b029SLaurent Vivier     if (aExp == 0x7FFF) {
25719937b029SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
25729937b029SLaurent Vivier             return propagateFloatx80NaNOneArg(a, status);
25739937b029SLaurent Vivier         }
25749937b029SLaurent Vivier         return packFloatx80(aSign, one_exp, one_sig);
25759937b029SLaurent Vivier     }
25769937b029SLaurent Vivier 
25779937b029SLaurent Vivier     if (aExp == 0 && aSig == 0) {
25789937b029SLaurent Vivier         return packFloatx80(aSign, 0, 0);
25799937b029SLaurent Vivier     }
25809937b029SLaurent Vivier 
25819937b029SLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
25829937b029SLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
25839937b029SLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
2584*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
25859937b029SLaurent Vivier 
25869937b029SLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
25879937b029SLaurent Vivier 
25889937b029SLaurent Vivier     if (compact < 0x3FD78000 || compact > 0x3FFFDDCE) {
25899937b029SLaurent Vivier         /* TANHBORS */
25909937b029SLaurent Vivier         if (compact < 0x3FFF8000) {
25919937b029SLaurent Vivier             /* TANHSM */
25929937b029SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
25939937b029SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
25949937b029SLaurent Vivier 
25959937b029SLaurent Vivier             a = floatx80_move(a, status);
25969937b029SLaurent Vivier 
25979937b029SLaurent Vivier             float_raise(float_flag_inexact, status);
25989937b029SLaurent Vivier 
25999937b029SLaurent Vivier             return a;
26009937b029SLaurent Vivier         } else {
26019937b029SLaurent Vivier             if (compact > 0x40048AA1) {
26029937b029SLaurent Vivier                 /* TANHHUGE */
26039937b029SLaurent Vivier                 sign = 0x3F800000;
26049937b029SLaurent Vivier                 sign |= aSign ? 0x80000000 : 0x00000000;
26059937b029SLaurent Vivier                 fp0 = float32_to_floatx80(make_float32(sign), status);
26069937b029SLaurent Vivier                 sign &= 0x80000000;
26079937b029SLaurent Vivier                 sign ^= 0x80800000; /* -SIGN(X)*EPS */
26089937b029SLaurent Vivier 
26099937b029SLaurent Vivier                 status->float_rounding_mode = user_rnd_mode;
26109937b029SLaurent Vivier                 status->floatx80_rounding_precision = user_rnd_prec;
26119937b029SLaurent Vivier 
26129937b029SLaurent Vivier                 a = floatx80_add(fp0, float32_to_floatx80(make_float32(sign),
26139937b029SLaurent Vivier                                  status), status);
26149937b029SLaurent Vivier 
26159937b029SLaurent Vivier                 float_raise(float_flag_inexact, status);
26169937b029SLaurent Vivier 
26179937b029SLaurent Vivier                 return a;
26189937b029SLaurent Vivier             } else {
26199937b029SLaurent Vivier                 fp0 = packFloatx80(0, aExp + 1, aSig); /* Y = 2|X| */
26209937b029SLaurent Vivier                 fp0 = floatx80_etox(fp0, status); /* FP0 IS EXP(Y) */
26219937b029SLaurent Vivier                 fp0 = floatx80_add(fp0, float32_to_floatx80(
26229937b029SLaurent Vivier                                    make_float32(0x3F800000),
26239937b029SLaurent Vivier                                    status), status); /* EXP(Y)+1 */
26249937b029SLaurent Vivier                 sign = aSign ? 0x80000000 : 0x00000000;
26259937b029SLaurent Vivier                 fp1 = floatx80_div(float32_to_floatx80(make_float32(
26269937b029SLaurent Vivier                                    sign ^ 0xC0000000), status), fp0,
26279937b029SLaurent Vivier                                    status); /* -SIGN(X)*2 / [EXP(Y)+1] */
26289937b029SLaurent Vivier                 fp0 = float32_to_floatx80(make_float32(sign | 0x3F800000),
26299937b029SLaurent Vivier                                           status); /* SIGN */
26309937b029SLaurent Vivier 
26319937b029SLaurent Vivier                 status->float_rounding_mode = user_rnd_mode;
26329937b029SLaurent Vivier                 status->floatx80_rounding_precision = user_rnd_prec;
26339937b029SLaurent Vivier 
26349937b029SLaurent Vivier                 a = floatx80_add(fp1, fp0, status);
26359937b029SLaurent Vivier 
26369937b029SLaurent Vivier                 float_raise(float_flag_inexact, status);
26379937b029SLaurent Vivier 
26389937b029SLaurent Vivier                 return a;
26399937b029SLaurent Vivier             }
26409937b029SLaurent Vivier         }
26419937b029SLaurent Vivier     } else { /* 2**(-40) < |X| < (5/2)LOG2 */
26429937b029SLaurent Vivier         fp0 = packFloatx80(0, aExp + 1, aSig); /* Y = 2|X| */
26439937b029SLaurent Vivier         fp0 = floatx80_etoxm1(fp0, status); /* FP0 IS Z = EXPM1(Y) */
26449937b029SLaurent Vivier         fp1 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x40000000),
26459937b029SLaurent Vivier                            status),
26469937b029SLaurent Vivier                            status); /* Z+2 */
26479937b029SLaurent Vivier 
26489937b029SLaurent Vivier         vSign = extractFloatx80Sign(fp1);
26499937b029SLaurent Vivier         vExp = extractFloatx80Exp(fp1);
26509937b029SLaurent Vivier         vSig = extractFloatx80Frac(fp1);
26519937b029SLaurent Vivier 
26529937b029SLaurent Vivier         fp1 = packFloatx80(vSign ^ aSign, vExp, vSig);
26539937b029SLaurent Vivier 
26549937b029SLaurent Vivier         status->float_rounding_mode = user_rnd_mode;
26559937b029SLaurent Vivier         status->floatx80_rounding_precision = user_rnd_prec;
26569937b029SLaurent Vivier 
26579937b029SLaurent Vivier         a = floatx80_div(fp0, fp1, status);
26589937b029SLaurent Vivier 
26599937b029SLaurent Vivier         float_raise(float_flag_inexact, status);
26609937b029SLaurent Vivier 
26619937b029SLaurent Vivier         return a;
26629937b029SLaurent Vivier     }
26639937b029SLaurent Vivier }
2664eee6b892SLaurent Vivier 
2665808d77bcSLucien Murray-Pitts /*
2666808d77bcSLucien Murray-Pitts  * Hyperbolic sine
2667808d77bcSLucien Murray-Pitts  */
2668eee6b892SLaurent Vivier 
floatx80_sinh(floatx80 a,float_status * status)2669eee6b892SLaurent Vivier floatx80 floatx80_sinh(floatx80 a, float_status *status)
2670eee6b892SLaurent Vivier {
2671c120391cSRichard Henderson     bool aSign;
2672eee6b892SLaurent Vivier     int32_t aExp;
2673eee6b892SLaurent Vivier     uint64_t aSig;
2674eee6b892SLaurent Vivier 
2675*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
2676*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
2677eee6b892SLaurent Vivier 
2678eee6b892SLaurent Vivier     int32_t compact;
2679eee6b892SLaurent Vivier     floatx80 fp0, fp1, fp2;
2680eee6b892SLaurent Vivier     float32 fact;
2681eee6b892SLaurent Vivier 
2682eee6b892SLaurent Vivier     aSig = extractFloatx80Frac(a);
2683eee6b892SLaurent Vivier     aExp = extractFloatx80Exp(a);
2684eee6b892SLaurent Vivier     aSign = extractFloatx80Sign(a);
2685eee6b892SLaurent Vivier 
2686eee6b892SLaurent Vivier     if (aExp == 0x7FFF) {
2687eee6b892SLaurent Vivier         if ((uint64_t) (aSig << 1)) {
2688eee6b892SLaurent Vivier             return propagateFloatx80NaNOneArg(a, status);
2689eee6b892SLaurent Vivier         }
2690eee6b892SLaurent Vivier         return packFloatx80(aSign, floatx80_infinity.high,
2691eee6b892SLaurent Vivier                             floatx80_infinity.low);
2692eee6b892SLaurent Vivier     }
2693eee6b892SLaurent Vivier 
2694eee6b892SLaurent Vivier     if (aExp == 0 && aSig == 0) {
2695eee6b892SLaurent Vivier         return packFloatx80(aSign, 0, 0);
2696eee6b892SLaurent Vivier     }
2697eee6b892SLaurent Vivier 
2698eee6b892SLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
2699eee6b892SLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
2700eee6b892SLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
2701*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
2702eee6b892SLaurent Vivier 
2703eee6b892SLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
2704eee6b892SLaurent Vivier 
2705eee6b892SLaurent Vivier     if (compact > 0x400CB167) {
2706eee6b892SLaurent Vivier         /* SINHBIG */
2707eee6b892SLaurent Vivier         if (compact > 0x400CB2B3) {
2708eee6b892SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
2709eee6b892SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
2710eee6b892SLaurent Vivier 
2711eee6b892SLaurent Vivier             return roundAndPackFloatx80(status->floatx80_rounding_precision,
2712eee6b892SLaurent Vivier                                         aSign, 0x8000, aSig, 0, status);
2713eee6b892SLaurent Vivier         } else {
2714eee6b892SLaurent Vivier             fp0 = floatx80_abs(a); /* Y = |X| */
2715eee6b892SLaurent Vivier             fp0 = floatx80_sub(fp0, float64_to_floatx80(
2716eee6b892SLaurent Vivier                                make_float64(0x40C62D38D3D64634), status),
2717eee6b892SLaurent Vivier                                status); /* (|X|-16381LOG2_LEAD) */
2718eee6b892SLaurent Vivier             fp0 = floatx80_sub(fp0, float64_to_floatx80(
2719eee6b892SLaurent Vivier                                make_float64(0x3D6F90AEB1E75CC7), status),
2720eee6b892SLaurent Vivier                                status); /* |X| - 16381 LOG2, ACCURATE */
2721eee6b892SLaurent Vivier             fp0 = floatx80_etox(fp0, status);
2722eee6b892SLaurent Vivier             fp2 = packFloatx80(aSign, 0x7FFB, one_sig);
2723eee6b892SLaurent Vivier 
2724eee6b892SLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
2725eee6b892SLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
2726eee6b892SLaurent Vivier 
2727eee6b892SLaurent Vivier             a = floatx80_mul(fp0, fp2, status);
2728eee6b892SLaurent Vivier 
2729eee6b892SLaurent Vivier             float_raise(float_flag_inexact, status);
2730eee6b892SLaurent Vivier 
2731eee6b892SLaurent Vivier             return a;
2732eee6b892SLaurent Vivier         }
2733eee6b892SLaurent Vivier     } else { /* |X| < 16380 LOG2 */
2734eee6b892SLaurent Vivier         fp0 = floatx80_abs(a); /* Y = |X| */
2735eee6b892SLaurent Vivier         fp0 = floatx80_etoxm1(fp0, status); /* FP0 IS Z = EXPM1(Y) */
2736eee6b892SLaurent Vivier         fp1 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
2737eee6b892SLaurent Vivier                            status), status); /* 1+Z */
2738eee6b892SLaurent Vivier         fp2 = fp0;
2739eee6b892SLaurent Vivier         fp0 = floatx80_div(fp0, fp1, status); /* Z/(1+Z) */
2740eee6b892SLaurent Vivier         fp0 = floatx80_add(fp0, fp2, status);
2741eee6b892SLaurent Vivier 
2742eee6b892SLaurent Vivier         fact = packFloat32(aSign, 0x7E, 0);
2743eee6b892SLaurent Vivier 
2744eee6b892SLaurent Vivier         status->float_rounding_mode = user_rnd_mode;
2745eee6b892SLaurent Vivier         status->floatx80_rounding_precision = user_rnd_prec;
2746eee6b892SLaurent Vivier 
2747eee6b892SLaurent Vivier         a = floatx80_mul(fp0, float32_to_floatx80(fact, status), status);
2748eee6b892SLaurent Vivier 
2749eee6b892SLaurent Vivier         float_raise(float_flag_inexact, status);
2750eee6b892SLaurent Vivier 
2751eee6b892SLaurent Vivier         return a;
2752eee6b892SLaurent Vivier     }
2753eee6b892SLaurent Vivier }
275402f9124eSLaurent Vivier 
2755808d77bcSLucien Murray-Pitts /*
2756808d77bcSLucien Murray-Pitts  * Hyperbolic cosine
2757808d77bcSLucien Murray-Pitts  */
275802f9124eSLaurent Vivier 
floatx80_cosh(floatx80 a,float_status * status)275902f9124eSLaurent Vivier floatx80 floatx80_cosh(floatx80 a, float_status *status)
276002f9124eSLaurent Vivier {
276102f9124eSLaurent Vivier     int32_t aExp;
276202f9124eSLaurent Vivier     uint64_t aSig;
276302f9124eSLaurent Vivier 
2764*8da5f1dbSRichard Henderson     FloatRoundMode user_rnd_mode;
2765*8da5f1dbSRichard Henderson     FloatX80RoundPrec user_rnd_prec;
276602f9124eSLaurent Vivier 
276702f9124eSLaurent Vivier     int32_t compact;
276802f9124eSLaurent Vivier     floatx80 fp0, fp1;
276902f9124eSLaurent Vivier 
277002f9124eSLaurent Vivier     aSig = extractFloatx80Frac(a);
277102f9124eSLaurent Vivier     aExp = extractFloatx80Exp(a);
277202f9124eSLaurent Vivier 
277302f9124eSLaurent Vivier     if (aExp == 0x7FFF) {
277402f9124eSLaurent Vivier         if ((uint64_t) (aSig << 1)) {
277502f9124eSLaurent Vivier             return propagateFloatx80NaNOneArg(a, status);
277602f9124eSLaurent Vivier         }
277702f9124eSLaurent Vivier         return packFloatx80(0, floatx80_infinity.high,
277802f9124eSLaurent Vivier                             floatx80_infinity.low);
277902f9124eSLaurent Vivier     }
278002f9124eSLaurent Vivier 
278102f9124eSLaurent Vivier     if (aExp == 0 && aSig == 0) {
278202f9124eSLaurent Vivier         return packFloatx80(0, one_exp, one_sig);
278302f9124eSLaurent Vivier     }
278402f9124eSLaurent Vivier 
278502f9124eSLaurent Vivier     user_rnd_mode = status->float_rounding_mode;
278602f9124eSLaurent Vivier     user_rnd_prec = status->floatx80_rounding_precision;
278702f9124eSLaurent Vivier     status->float_rounding_mode = float_round_nearest_even;
2788*8da5f1dbSRichard Henderson     status->floatx80_rounding_precision = floatx80_precision_x;
278902f9124eSLaurent Vivier 
279002f9124eSLaurent Vivier     compact = floatx80_make_compact(aExp, aSig);
279102f9124eSLaurent Vivier 
279202f9124eSLaurent Vivier     if (compact > 0x400CB167) {
279302f9124eSLaurent Vivier         if (compact > 0x400CB2B3) {
279402f9124eSLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
279502f9124eSLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
279602f9124eSLaurent Vivier             return roundAndPackFloatx80(status->floatx80_rounding_precision, 0,
279702f9124eSLaurent Vivier                                         0x8000, one_sig, 0, status);
279802f9124eSLaurent Vivier         } else {
279902f9124eSLaurent Vivier             fp0 = packFloatx80(0, aExp, aSig);
280002f9124eSLaurent Vivier             fp0 = floatx80_sub(fp0, float64_to_floatx80(
280102f9124eSLaurent Vivier                                make_float64(0x40C62D38D3D64634), status),
280202f9124eSLaurent Vivier                                status);
280302f9124eSLaurent Vivier             fp0 = floatx80_sub(fp0, float64_to_floatx80(
280402f9124eSLaurent Vivier                                make_float64(0x3D6F90AEB1E75CC7), status),
280502f9124eSLaurent Vivier                                status);
280602f9124eSLaurent Vivier             fp0 = floatx80_etox(fp0, status);
280702f9124eSLaurent Vivier             fp1 = packFloatx80(0, 0x7FFB, one_sig);
280802f9124eSLaurent Vivier 
280902f9124eSLaurent Vivier             status->float_rounding_mode = user_rnd_mode;
281002f9124eSLaurent Vivier             status->floatx80_rounding_precision = user_rnd_prec;
281102f9124eSLaurent Vivier 
281202f9124eSLaurent Vivier             a = floatx80_mul(fp0, fp1, status);
281302f9124eSLaurent Vivier 
281402f9124eSLaurent Vivier             float_raise(float_flag_inexact, status);
281502f9124eSLaurent Vivier 
281602f9124eSLaurent Vivier             return a;
281702f9124eSLaurent Vivier         }
281802f9124eSLaurent Vivier     }
281902f9124eSLaurent Vivier 
282002f9124eSLaurent Vivier     fp0 = packFloatx80(0, aExp, aSig); /* |X| */
282102f9124eSLaurent Vivier     fp0 = floatx80_etox(fp0, status); /* EXP(|X|) */
282202f9124eSLaurent Vivier     fp0 = floatx80_mul(fp0, float32_to_floatx80(make_float32(0x3F000000),
282302f9124eSLaurent Vivier                        status), status); /* (1/2)*EXP(|X|) */
282402f9124eSLaurent Vivier     fp1 = float32_to_floatx80(make_float32(0x3E800000), status); /* 1/4 */
282502f9124eSLaurent Vivier     fp1 = floatx80_div(fp1, fp0, status); /* 1/(2*EXP(|X|)) */
282602f9124eSLaurent Vivier 
282702f9124eSLaurent Vivier     status->float_rounding_mode = user_rnd_mode;
282802f9124eSLaurent Vivier     status->floatx80_rounding_precision = user_rnd_prec;
282902f9124eSLaurent Vivier 
283002f9124eSLaurent Vivier     a = floatx80_add(fp0, fp1, status);
283102f9124eSLaurent Vivier 
283202f9124eSLaurent Vivier     float_raise(float_flag_inexact, status);
283302f9124eSLaurent Vivier 
283402f9124eSLaurent Vivier     return a;
283502f9124eSLaurent Vivier }
2836