xref: /openbsd-src/gnu/llvm/compiler-rt/lib/builtins/fp_lib.h (revision d89ec533011f513df1010f142a111086a0785f09)
13cab2bb3Spatrick //===-- lib/fp_lib.h - Floating-point utilities -------------------*- C -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a configuration header for soft-float routines in compiler-rt.
103cab2bb3Spatrick // This file does not provide any part of the compiler-rt interface, but defines
113cab2bb3Spatrick // many useful constants and utility routines that are used in the
123cab2bb3Spatrick // implementation of the soft-float routines in compiler-rt.
133cab2bb3Spatrick //
143cab2bb3Spatrick // Assumes that float, double and long double correspond to the IEEE-754
153cab2bb3Spatrick // binary32, binary64 and binary 128 types, respectively, and that integer
163cab2bb3Spatrick // endianness matches floating point endianness on the target platform.
173cab2bb3Spatrick //
183cab2bb3Spatrick //===----------------------------------------------------------------------===//
193cab2bb3Spatrick 
203cab2bb3Spatrick #ifndef FP_LIB_HEADER
213cab2bb3Spatrick #define FP_LIB_HEADER
223cab2bb3Spatrick 
233cab2bb3Spatrick #include "int_lib.h"
243cab2bb3Spatrick #include "int_math.h"
253cab2bb3Spatrick #include <limits.h>
263cab2bb3Spatrick #include <stdbool.h>
273cab2bb3Spatrick #include <stdint.h>
283cab2bb3Spatrick 
293cab2bb3Spatrick // x86_64 FreeBSD prior v9.3 define fixed-width types incorrectly in
303cab2bb3Spatrick // 32-bit mode.
313cab2bb3Spatrick #if defined(__FreeBSD__) && defined(__i386__)
323cab2bb3Spatrick #include <sys/param.h>
333cab2bb3Spatrick #if __FreeBSD_version < 903000 // v9.3
343cab2bb3Spatrick #define uint64_t unsigned long long
353cab2bb3Spatrick #define int64_t long long
363cab2bb3Spatrick #undef UINT64_C
373cab2bb3Spatrick #define UINT64_C(c) (c##ULL)
383cab2bb3Spatrick #endif
393cab2bb3Spatrick #endif
403cab2bb3Spatrick 
413cab2bb3Spatrick #if defined SINGLE_PRECISION
423cab2bb3Spatrick 
43*d89ec533Spatrick typedef uint16_t half_rep_t;
443cab2bb3Spatrick typedef uint32_t rep_t;
45*d89ec533Spatrick typedef uint64_t twice_rep_t;
463cab2bb3Spatrick typedef int32_t srep_t;
473cab2bb3Spatrick typedef float fp_t;
48*d89ec533Spatrick #define HALF_REP_C UINT16_C
493cab2bb3Spatrick #define REP_C UINT32_C
503cab2bb3Spatrick #define significandBits 23
513cab2bb3Spatrick 
rep_clz(rep_t a)521f9cb04fSpatrick static __inline int rep_clz(rep_t a) { return clzsi(a); }
533cab2bb3Spatrick 
543cab2bb3Spatrick // 32x32 --> 64 bit multiply
wideMultiply(rep_t a,rep_t b,rep_t * hi,rep_t * lo)553cab2bb3Spatrick static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
563cab2bb3Spatrick   const uint64_t product = (uint64_t)a * b;
573cab2bb3Spatrick   *hi = product >> 32;
583cab2bb3Spatrick   *lo = product;
593cab2bb3Spatrick }
603cab2bb3Spatrick COMPILER_RT_ABI fp_t __addsf3(fp_t a, fp_t b);
613cab2bb3Spatrick 
623cab2bb3Spatrick #elif defined DOUBLE_PRECISION
633cab2bb3Spatrick 
64*d89ec533Spatrick typedef uint32_t half_rep_t;
653cab2bb3Spatrick typedef uint64_t rep_t;
663cab2bb3Spatrick typedef int64_t srep_t;
673cab2bb3Spatrick typedef double fp_t;
68*d89ec533Spatrick #define HALF_REP_C UINT32_C
693cab2bb3Spatrick #define REP_C UINT64_C
703cab2bb3Spatrick #define significandBits 52
713cab2bb3Spatrick 
rep_clz(rep_t a)723cab2bb3Spatrick static __inline int rep_clz(rep_t a) {
733cab2bb3Spatrick #if defined __LP64__
743cab2bb3Spatrick   return __builtin_clzl(a);
753cab2bb3Spatrick #else
763cab2bb3Spatrick   if (a & REP_C(0xffffffff00000000))
771f9cb04fSpatrick     return clzsi(a >> 32);
783cab2bb3Spatrick   else
791f9cb04fSpatrick     return 32 + clzsi(a & REP_C(0xffffffff));
803cab2bb3Spatrick #endif
813cab2bb3Spatrick }
823cab2bb3Spatrick 
833cab2bb3Spatrick #define loWord(a) (a & 0xffffffffU)
843cab2bb3Spatrick #define hiWord(a) (a >> 32)
853cab2bb3Spatrick 
863cab2bb3Spatrick // 64x64 -> 128 wide multiply for platforms that don't have such an operation;
873cab2bb3Spatrick // many 64-bit platforms have this operation, but they tend to have hardware
883cab2bb3Spatrick // floating-point, so we don't bother with a special case for them here.
wideMultiply(rep_t a,rep_t b,rep_t * hi,rep_t * lo)893cab2bb3Spatrick static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
903cab2bb3Spatrick   // Each of the component 32x32 -> 64 products
913cab2bb3Spatrick   const uint64_t plolo = loWord(a) * loWord(b);
923cab2bb3Spatrick   const uint64_t plohi = loWord(a) * hiWord(b);
933cab2bb3Spatrick   const uint64_t philo = hiWord(a) * loWord(b);
943cab2bb3Spatrick   const uint64_t phihi = hiWord(a) * hiWord(b);
953cab2bb3Spatrick   // Sum terms that contribute to lo in a way that allows us to get the carry
963cab2bb3Spatrick   const uint64_t r0 = loWord(plolo);
973cab2bb3Spatrick   const uint64_t r1 = hiWord(plolo) + loWord(plohi) + loWord(philo);
983cab2bb3Spatrick   *lo = r0 + (r1 << 32);
993cab2bb3Spatrick   // Sum terms contributing to hi with the carry from lo
1003cab2bb3Spatrick   *hi = hiWord(plohi) + hiWord(philo) + hiWord(r1) + phihi;
1013cab2bb3Spatrick }
1023cab2bb3Spatrick #undef loWord
1033cab2bb3Spatrick #undef hiWord
1043cab2bb3Spatrick 
1053cab2bb3Spatrick COMPILER_RT_ABI fp_t __adddf3(fp_t a, fp_t b);
1063cab2bb3Spatrick 
1073cab2bb3Spatrick #elif defined QUAD_PRECISION
1083cab2bb3Spatrick #if __LDBL_MANT_DIG__ == 113 && defined(__SIZEOF_INT128__)
1093cab2bb3Spatrick #define CRT_LDBL_128BIT
110*d89ec533Spatrick typedef uint64_t half_rep_t;
1113cab2bb3Spatrick typedef __uint128_t rep_t;
1123cab2bb3Spatrick typedef __int128_t srep_t;
1133cab2bb3Spatrick typedef long double fp_t;
114*d89ec533Spatrick #define HALF_REP_C UINT64_C
1153cab2bb3Spatrick #define REP_C (__uint128_t)
1163cab2bb3Spatrick // Note: Since there is no explicit way to tell compiler the constant is a
1173cab2bb3Spatrick // 128-bit integer, we let the constant be casted to 128-bit integer
1183cab2bb3Spatrick #define significandBits 112
1193cab2bb3Spatrick 
rep_clz(rep_t a)1203cab2bb3Spatrick static __inline int rep_clz(rep_t a) {
1213cab2bb3Spatrick   const union {
1223cab2bb3Spatrick     __uint128_t ll;
1233cab2bb3Spatrick #if _YUGA_BIG_ENDIAN
1243cab2bb3Spatrick     struct {
1253cab2bb3Spatrick       uint64_t high, low;
1263cab2bb3Spatrick     } s;
1273cab2bb3Spatrick #else
1283cab2bb3Spatrick     struct {
1293cab2bb3Spatrick       uint64_t low, high;
1303cab2bb3Spatrick     } s;
1313cab2bb3Spatrick #endif
1323cab2bb3Spatrick   } uu = {.ll = a};
1333cab2bb3Spatrick 
1343cab2bb3Spatrick   uint64_t word;
1353cab2bb3Spatrick   uint64_t add;
1363cab2bb3Spatrick 
1373cab2bb3Spatrick   if (uu.s.high) {
1383cab2bb3Spatrick     word = uu.s.high;
1393cab2bb3Spatrick     add = 0;
1403cab2bb3Spatrick   } else {
1413cab2bb3Spatrick     word = uu.s.low;
1423cab2bb3Spatrick     add = 64;
1433cab2bb3Spatrick   }
1443cab2bb3Spatrick   return __builtin_clzll(word) + add;
1453cab2bb3Spatrick }
1463cab2bb3Spatrick 
1473cab2bb3Spatrick #define Word_LoMask UINT64_C(0x00000000ffffffff)
1483cab2bb3Spatrick #define Word_HiMask UINT64_C(0xffffffff00000000)
1493cab2bb3Spatrick #define Word_FullMask UINT64_C(0xffffffffffffffff)
1503cab2bb3Spatrick #define Word_1(a) (uint64_t)((a >> 96) & Word_LoMask)
1513cab2bb3Spatrick #define Word_2(a) (uint64_t)((a >> 64) & Word_LoMask)
1523cab2bb3Spatrick #define Word_3(a) (uint64_t)((a >> 32) & Word_LoMask)
1533cab2bb3Spatrick #define Word_4(a) (uint64_t)(a & Word_LoMask)
1543cab2bb3Spatrick 
1553cab2bb3Spatrick // 128x128 -> 256 wide multiply for platforms that don't have such an operation;
1563cab2bb3Spatrick // many 64-bit platforms have this operation, but they tend to have hardware
1573cab2bb3Spatrick // floating-point, so we don't bother with a special case for them here.
wideMultiply(rep_t a,rep_t b,rep_t * hi,rep_t * lo)1583cab2bb3Spatrick static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
1593cab2bb3Spatrick 
1603cab2bb3Spatrick   const uint64_t product11 = Word_1(a) * Word_1(b);
1613cab2bb3Spatrick   const uint64_t product12 = Word_1(a) * Word_2(b);
1623cab2bb3Spatrick   const uint64_t product13 = Word_1(a) * Word_3(b);
1633cab2bb3Spatrick   const uint64_t product14 = Word_1(a) * Word_4(b);
1643cab2bb3Spatrick   const uint64_t product21 = Word_2(a) * Word_1(b);
1653cab2bb3Spatrick   const uint64_t product22 = Word_2(a) * Word_2(b);
1663cab2bb3Spatrick   const uint64_t product23 = Word_2(a) * Word_3(b);
1673cab2bb3Spatrick   const uint64_t product24 = Word_2(a) * Word_4(b);
1683cab2bb3Spatrick   const uint64_t product31 = Word_3(a) * Word_1(b);
1693cab2bb3Spatrick   const uint64_t product32 = Word_3(a) * Word_2(b);
1703cab2bb3Spatrick   const uint64_t product33 = Word_3(a) * Word_3(b);
1713cab2bb3Spatrick   const uint64_t product34 = Word_3(a) * Word_4(b);
1723cab2bb3Spatrick   const uint64_t product41 = Word_4(a) * Word_1(b);
1733cab2bb3Spatrick   const uint64_t product42 = Word_4(a) * Word_2(b);
1743cab2bb3Spatrick   const uint64_t product43 = Word_4(a) * Word_3(b);
1753cab2bb3Spatrick   const uint64_t product44 = Word_4(a) * Word_4(b);
1763cab2bb3Spatrick 
1773cab2bb3Spatrick   const __uint128_t sum0 = (__uint128_t)product44;
1783cab2bb3Spatrick   const __uint128_t sum1 = (__uint128_t)product34 + (__uint128_t)product43;
1793cab2bb3Spatrick   const __uint128_t sum2 =
1803cab2bb3Spatrick       (__uint128_t)product24 + (__uint128_t)product33 + (__uint128_t)product42;
1813cab2bb3Spatrick   const __uint128_t sum3 = (__uint128_t)product14 + (__uint128_t)product23 +
1823cab2bb3Spatrick                            (__uint128_t)product32 + (__uint128_t)product41;
1833cab2bb3Spatrick   const __uint128_t sum4 =
1843cab2bb3Spatrick       (__uint128_t)product13 + (__uint128_t)product22 + (__uint128_t)product31;
1853cab2bb3Spatrick   const __uint128_t sum5 = (__uint128_t)product12 + (__uint128_t)product21;
1863cab2bb3Spatrick   const __uint128_t sum6 = (__uint128_t)product11;
1873cab2bb3Spatrick 
1883cab2bb3Spatrick   const __uint128_t r0 = (sum0 & Word_FullMask) + ((sum1 & Word_LoMask) << 32);
1893cab2bb3Spatrick   const __uint128_t r1 = (sum0 >> 64) + ((sum1 >> 32) & Word_FullMask) +
1903cab2bb3Spatrick                          (sum2 & Word_FullMask) + ((sum3 << 32) & Word_HiMask);
1913cab2bb3Spatrick 
1923cab2bb3Spatrick   *lo = r0 + (r1 << 64);
1933cab2bb3Spatrick   *hi = (r1 >> 64) + (sum1 >> 96) + (sum2 >> 64) + (sum3 >> 32) + sum4 +
1943cab2bb3Spatrick         (sum5 << 32) + (sum6 << 64);
1953cab2bb3Spatrick }
1963cab2bb3Spatrick #undef Word_1
1973cab2bb3Spatrick #undef Word_2
1983cab2bb3Spatrick #undef Word_3
1993cab2bb3Spatrick #undef Word_4
2003cab2bb3Spatrick #undef Word_HiMask
2013cab2bb3Spatrick #undef Word_LoMask
2023cab2bb3Spatrick #undef Word_FullMask
2033cab2bb3Spatrick #endif // __LDBL_MANT_DIG__ == 113 && __SIZEOF_INT128__
2043cab2bb3Spatrick #else
2053cab2bb3Spatrick #error SINGLE_PRECISION, DOUBLE_PRECISION or QUAD_PRECISION must be defined.
2063cab2bb3Spatrick #endif
2073cab2bb3Spatrick 
2083cab2bb3Spatrick #if defined(SINGLE_PRECISION) || defined(DOUBLE_PRECISION) ||                  \
2093cab2bb3Spatrick     defined(CRT_LDBL_128BIT)
2103cab2bb3Spatrick #define typeWidth (sizeof(rep_t) * CHAR_BIT)
2113cab2bb3Spatrick #define exponentBits (typeWidth - significandBits - 1)
2123cab2bb3Spatrick #define maxExponent ((1 << exponentBits) - 1)
2133cab2bb3Spatrick #define exponentBias (maxExponent >> 1)
2143cab2bb3Spatrick 
2153cab2bb3Spatrick #define implicitBit (REP_C(1) << significandBits)
2163cab2bb3Spatrick #define significandMask (implicitBit - 1U)
2173cab2bb3Spatrick #define signBit (REP_C(1) << (significandBits + exponentBits))
2183cab2bb3Spatrick #define absMask (signBit - 1U)
2193cab2bb3Spatrick #define exponentMask (absMask ^ significandMask)
2203cab2bb3Spatrick #define oneRep ((rep_t)exponentBias << significandBits)
2213cab2bb3Spatrick #define infRep exponentMask
2223cab2bb3Spatrick #define quietBit (implicitBit >> 1)
2233cab2bb3Spatrick #define qnanRep (exponentMask | quietBit)
2243cab2bb3Spatrick 
toRep(fp_t x)2253cab2bb3Spatrick static __inline rep_t toRep(fp_t x) {
2263cab2bb3Spatrick   const union {
2273cab2bb3Spatrick     fp_t f;
2283cab2bb3Spatrick     rep_t i;
2293cab2bb3Spatrick   } rep = {.f = x};
2303cab2bb3Spatrick   return rep.i;
2313cab2bb3Spatrick }
2323cab2bb3Spatrick 
fromRep(rep_t x)2333cab2bb3Spatrick static __inline fp_t fromRep(rep_t x) {
2343cab2bb3Spatrick   const union {
2353cab2bb3Spatrick     fp_t f;
2363cab2bb3Spatrick     rep_t i;
2373cab2bb3Spatrick   } rep = {.i = x};
2383cab2bb3Spatrick   return rep.f;
2393cab2bb3Spatrick }
2403cab2bb3Spatrick 
normalize(rep_t * significand)2413cab2bb3Spatrick static __inline int normalize(rep_t *significand) {
2423cab2bb3Spatrick   const int shift = rep_clz(*significand) - rep_clz(implicitBit);
2433cab2bb3Spatrick   *significand <<= shift;
2443cab2bb3Spatrick   return 1 - shift;
2453cab2bb3Spatrick }
2463cab2bb3Spatrick 
wideLeftShift(rep_t * hi,rep_t * lo,int count)2473cab2bb3Spatrick static __inline void wideLeftShift(rep_t *hi, rep_t *lo, int count) {
2483cab2bb3Spatrick   *hi = *hi << count | *lo >> (typeWidth - count);
2493cab2bb3Spatrick   *lo = *lo << count;
2503cab2bb3Spatrick }
2513cab2bb3Spatrick 
wideRightShiftWithSticky(rep_t * hi,rep_t * lo,unsigned int count)2523cab2bb3Spatrick static __inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo,
2533cab2bb3Spatrick                                               unsigned int count) {
2543cab2bb3Spatrick   if (count < typeWidth) {
2553cab2bb3Spatrick     const bool sticky = (*lo << (typeWidth - count)) != 0;
2563cab2bb3Spatrick     *lo = *hi << (typeWidth - count) | *lo >> count | sticky;
2573cab2bb3Spatrick     *hi = *hi >> count;
2583cab2bb3Spatrick   } else if (count < 2 * typeWidth) {
2593cab2bb3Spatrick     const bool sticky = *hi << (2 * typeWidth - count) | *lo;
2603cab2bb3Spatrick     *lo = *hi >> (count - typeWidth) | sticky;
2613cab2bb3Spatrick     *hi = 0;
2623cab2bb3Spatrick   } else {
2633cab2bb3Spatrick     const bool sticky = *hi | *lo;
2643cab2bb3Spatrick     *lo = sticky;
2653cab2bb3Spatrick     *hi = 0;
2663cab2bb3Spatrick   }
2673cab2bb3Spatrick }
2683cab2bb3Spatrick 
2693cab2bb3Spatrick // Implements logb methods (logb, logbf, logbl) for IEEE-754. This avoids
2703cab2bb3Spatrick // pulling in a libm dependency from compiler-rt, but is not meant to replace
2713cab2bb3Spatrick // it (i.e. code calling logb() should get the one from libm, not this), hence
2723cab2bb3Spatrick // the __compiler_rt prefix.
__compiler_rt_logbX(fp_t x)2733cab2bb3Spatrick static __inline fp_t __compiler_rt_logbX(fp_t x) {
2743cab2bb3Spatrick   rep_t rep = toRep(x);
2753cab2bb3Spatrick   int exp = (rep & exponentMask) >> significandBits;
2763cab2bb3Spatrick 
2773cab2bb3Spatrick   // Abnormal cases:
2783cab2bb3Spatrick   // 1) +/- inf returns +inf; NaN returns NaN
2793cab2bb3Spatrick   // 2) 0.0 returns -inf
2803cab2bb3Spatrick   if (exp == maxExponent) {
2813cab2bb3Spatrick     if (((rep & signBit) == 0) || (x != x)) {
2823cab2bb3Spatrick       return x; // NaN or +inf: return x
2833cab2bb3Spatrick     } else {
2843cab2bb3Spatrick       return -x; // -inf: return -x
2853cab2bb3Spatrick     }
2863cab2bb3Spatrick   } else if (x == 0.0) {
2873cab2bb3Spatrick     // 0.0: return -inf
2883cab2bb3Spatrick     return fromRep(infRep | signBit);
2893cab2bb3Spatrick   }
2903cab2bb3Spatrick 
2913cab2bb3Spatrick   if (exp != 0) {
2923cab2bb3Spatrick     // Normal number
2933cab2bb3Spatrick     return exp - exponentBias; // Unbias exponent
2943cab2bb3Spatrick   } else {
2953cab2bb3Spatrick     // Subnormal number; normalize and repeat
2963cab2bb3Spatrick     rep &= absMask;
2973cab2bb3Spatrick     const int shift = 1 - normalize(&rep);
2983cab2bb3Spatrick     exp = (rep & exponentMask) >> significandBits;
2993cab2bb3Spatrick     return exp - exponentBias - shift; // Unbias exponent
3003cab2bb3Spatrick   }
3013cab2bb3Spatrick }
302*d89ec533Spatrick 
303*d89ec533Spatrick // Avoid using scalbn from libm. Unlike libc/libm scalbn, this function never
304*d89ec533Spatrick // sets errno on underflow/overflow.
__compiler_rt_scalbnX(fp_t x,int y)305*d89ec533Spatrick static __inline fp_t __compiler_rt_scalbnX(fp_t x, int y) {
306*d89ec533Spatrick   const rep_t rep = toRep(x);
307*d89ec533Spatrick   int exp = (rep & exponentMask) >> significandBits;
308*d89ec533Spatrick 
309*d89ec533Spatrick   if (x == 0.0 || exp == maxExponent)
310*d89ec533Spatrick     return x; // +/- 0.0, NaN, or inf: return x
311*d89ec533Spatrick 
312*d89ec533Spatrick   // Normalize subnormal input.
313*d89ec533Spatrick   rep_t sig = rep & significandMask;
314*d89ec533Spatrick   if (exp == 0) {
315*d89ec533Spatrick     exp += normalize(&sig);
316*d89ec533Spatrick     sig &= ~implicitBit; // clear the implicit bit again
317*d89ec533Spatrick   }
318*d89ec533Spatrick 
319*d89ec533Spatrick   if (__builtin_sadd_overflow(exp, y, &exp)) {
320*d89ec533Spatrick     // Saturate the exponent, which will guarantee an underflow/overflow below.
321*d89ec533Spatrick     exp = (y >= 0) ? INT_MAX : INT_MIN;
322*d89ec533Spatrick   }
323*d89ec533Spatrick 
324*d89ec533Spatrick   // Return this value: [+/-] 1.sig * 2 ** (exp - exponentBias).
325*d89ec533Spatrick   const rep_t sign = rep & signBit;
326*d89ec533Spatrick   if (exp >= maxExponent) {
327*d89ec533Spatrick     // Overflow, which could produce infinity or the largest-magnitude value,
328*d89ec533Spatrick     // depending on the rounding mode.
329*d89ec533Spatrick     return fromRep(sign | ((rep_t)(maxExponent - 1) << significandBits)) * 2.0f;
330*d89ec533Spatrick   } else if (exp <= 0) {
331*d89ec533Spatrick     // Subnormal or underflow. Use floating-point multiply to handle truncation
332*d89ec533Spatrick     // correctly.
333*d89ec533Spatrick     fp_t tmp = fromRep(sign | (REP_C(1) << significandBits) | sig);
334*d89ec533Spatrick     exp += exponentBias - 1;
335*d89ec533Spatrick     if (exp < 1)
336*d89ec533Spatrick       exp = 1;
337*d89ec533Spatrick     tmp *= fromRep((rep_t)exp << significandBits);
338*d89ec533Spatrick     return tmp;
339*d89ec533Spatrick   } else
340*d89ec533Spatrick     return fromRep(sign | ((rep_t)exp << significandBits) | sig);
341*d89ec533Spatrick }
342*d89ec533Spatrick 
343*d89ec533Spatrick // Avoid using fmax from libm.
__compiler_rt_fmaxX(fp_t x,fp_t y)344*d89ec533Spatrick static __inline fp_t __compiler_rt_fmaxX(fp_t x, fp_t y) {
345*d89ec533Spatrick   // If either argument is NaN, return the other argument. If both are NaN,
346*d89ec533Spatrick   // arbitrarily return the second one. Otherwise, if both arguments are +/-0,
347*d89ec533Spatrick   // arbitrarily return the first one.
348*d89ec533Spatrick   return (crt_isnan(x) || x < y) ? y : x;
349*d89ec533Spatrick }
350*d89ec533Spatrick 
3513cab2bb3Spatrick #endif
3523cab2bb3Spatrick 
3533cab2bb3Spatrick #if defined(SINGLE_PRECISION)
354*d89ec533Spatrick 
__compiler_rt_logbf(fp_t x)3553cab2bb3Spatrick static __inline fp_t __compiler_rt_logbf(fp_t x) {
3563cab2bb3Spatrick   return __compiler_rt_logbX(x);
3573cab2bb3Spatrick }
__compiler_rt_scalbnf(fp_t x,int y)358*d89ec533Spatrick static __inline fp_t __compiler_rt_scalbnf(fp_t x, int y) {
359*d89ec533Spatrick   return __compiler_rt_scalbnX(x, y);
360*d89ec533Spatrick }
__compiler_rt_fmaxf(fp_t x,fp_t y)361*d89ec533Spatrick static __inline fp_t __compiler_rt_fmaxf(fp_t x, fp_t y) {
362*d89ec533Spatrick #if defined(__aarch64__)
363*d89ec533Spatrick   // Use __builtin_fmaxf which turns into an fmaxnm instruction on AArch64.
364*d89ec533Spatrick   return __builtin_fmaxf(x, y);
365*d89ec533Spatrick #else
366*d89ec533Spatrick   // __builtin_fmaxf frequently turns into a libm call, so inline the function.
367*d89ec533Spatrick   return __compiler_rt_fmaxX(x, y);
368*d89ec533Spatrick #endif
369*d89ec533Spatrick }
370*d89ec533Spatrick 
3713cab2bb3Spatrick #elif defined(DOUBLE_PRECISION)
372*d89ec533Spatrick 
__compiler_rt_logb(fp_t x)3733cab2bb3Spatrick static __inline fp_t __compiler_rt_logb(fp_t x) {
3743cab2bb3Spatrick   return __compiler_rt_logbX(x);
3753cab2bb3Spatrick }
__compiler_rt_scalbn(fp_t x,int y)376*d89ec533Spatrick static __inline fp_t __compiler_rt_scalbn(fp_t x, int y) {
377*d89ec533Spatrick   return __compiler_rt_scalbnX(x, y);
378*d89ec533Spatrick }
__compiler_rt_fmax(fp_t x,fp_t y)379*d89ec533Spatrick static __inline fp_t __compiler_rt_fmax(fp_t x, fp_t y) {
380*d89ec533Spatrick #if defined(__aarch64__)
381*d89ec533Spatrick   // Use __builtin_fmax which turns into an fmaxnm instruction on AArch64.
382*d89ec533Spatrick   return __builtin_fmax(x, y);
383*d89ec533Spatrick #else
384*d89ec533Spatrick   // __builtin_fmax frequently turns into a libm call, so inline the function.
385*d89ec533Spatrick   return __compiler_rt_fmaxX(x, y);
386*d89ec533Spatrick #endif
387*d89ec533Spatrick }
388*d89ec533Spatrick 
3893cab2bb3Spatrick #elif defined(QUAD_PRECISION)
390*d89ec533Spatrick 
3913cab2bb3Spatrick #if defined(CRT_LDBL_128BIT)
__compiler_rt_logbl(fp_t x)3923cab2bb3Spatrick static __inline fp_t __compiler_rt_logbl(fp_t x) {
3933cab2bb3Spatrick   return __compiler_rt_logbX(x);
3943cab2bb3Spatrick }
__compiler_rt_scalbnl(fp_t x,int y)395*d89ec533Spatrick static __inline fp_t __compiler_rt_scalbnl(fp_t x, int y) {
396*d89ec533Spatrick   return __compiler_rt_scalbnX(x, y);
397*d89ec533Spatrick }
__compiler_rt_fmaxl(fp_t x,fp_t y)398*d89ec533Spatrick static __inline fp_t __compiler_rt_fmaxl(fp_t x, fp_t y) {
399*d89ec533Spatrick   return __compiler_rt_fmaxX(x, y);
400*d89ec533Spatrick }
4013cab2bb3Spatrick #else
4023cab2bb3Spatrick // The generic implementation only works for ieee754 floating point. For other
4033cab2bb3Spatrick // floating point types, continue to rely on the libm implementation for now.
__compiler_rt_logbl(long double x)4043cab2bb3Spatrick static __inline long double __compiler_rt_logbl(long double x) {
4053cab2bb3Spatrick   return crt_logbl(x);
4063cab2bb3Spatrick }
__compiler_rt_scalbnl(long double x,int y)407*d89ec533Spatrick static __inline long double __compiler_rt_scalbnl(long double x, int y) {
408*d89ec533Spatrick   return crt_scalbnl(x, y);
409*d89ec533Spatrick }
__compiler_rt_fmaxl(long double x,long double y)410*d89ec533Spatrick static __inline long double __compiler_rt_fmaxl(long double x, long double y) {
411*d89ec533Spatrick   return crt_fmaxl(x, y);
412*d89ec533Spatrick }
413*d89ec533Spatrick #endif // CRT_LDBL_128BIT
414*d89ec533Spatrick 
415*d89ec533Spatrick #endif // *_PRECISION
4163cab2bb3Spatrick 
4173cab2bb3Spatrick #endif // FP_LIB_HEADER
418