diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
commit | 344a3780b2e33f6ca763666c380202b18aab72a3 (patch) | |
tree | f0b203ee6eb71d7fdd792373e3c81eb18d6934dd /compiler-rt/lib/builtins/fp_lib.h | |
parent | b60736ec1405bb0a8dd40989f67ef4c93da068ab (diff) | |
download | src-344a3780b2e33f6ca763666c380202b18aab72a3.tar.gz src-344a3780b2e33f6ca763666c380202b18aab72a3.zip |
Vendor import of llvm-project main 88e66fa60ae5, the last commit beforevendor/llvm-project/llvmorg-13-init-16847-g88e66fa60ae5vendor/llvm-project/llvmorg-12.0.1-rc2-0-ge7dac564cd0evendor/llvm-project/llvmorg-12.0.1-0-gfed41342a82f
the upstream release/13.x branch was created.
Diffstat (limited to 'compiler-rt/lib/builtins/fp_lib.h')
-rw-r--r-- | compiler-rt/lib/builtins/fp_lib.h | 95 |
1 files changed, 93 insertions, 2 deletions
diff --git a/compiler-rt/lib/builtins/fp_lib.h b/compiler-rt/lib/builtins/fp_lib.h index f22feafa4e69..3fb13a033a14 100644 --- a/compiler-rt/lib/builtins/fp_lib.h +++ b/compiler-rt/lib/builtins/fp_lib.h @@ -299,28 +299,119 @@ static __inline fp_t __compiler_rt_logbX(fp_t x) { return exp - exponentBias - shift; // Unbias exponent } } + +// Avoid using scalbn from libm. Unlike libc/libm scalbn, this function never +// sets errno on underflow/overflow. +static __inline fp_t __compiler_rt_scalbnX(fp_t x, int y) { + const rep_t rep = toRep(x); + int exp = (rep & exponentMask) >> significandBits; + + if (x == 0.0 || exp == maxExponent) + return x; // +/- 0.0, NaN, or inf: return x + + // Normalize subnormal input. + rep_t sig = rep & significandMask; + if (exp == 0) { + exp += normalize(&sig); + sig &= ~implicitBit; // clear the implicit bit again + } + + if (__builtin_sadd_overflow(exp, y, &exp)) { + // Saturate the exponent, which will guarantee an underflow/overflow below. + exp = (y >= 0) ? INT_MAX : INT_MIN; + } + + // Return this value: [+/-] 1.sig * 2 ** (exp - exponentBias). + const rep_t sign = rep & signBit; + if (exp >= maxExponent) { + // Overflow, which could produce infinity or the largest-magnitude value, + // depending on the rounding mode. + return fromRep(sign | ((rep_t)(maxExponent - 1) << significandBits)) * 2.0f; + } else if (exp <= 0) { + // Subnormal or underflow. Use floating-point multiply to handle truncation + // correctly. + fp_t tmp = fromRep(sign | (REP_C(1) << significandBits) | sig); + exp += exponentBias - 1; + if (exp < 1) + exp = 1; + tmp *= fromRep((rep_t)exp << significandBits); + return tmp; + } else + return fromRep(sign | ((rep_t)exp << significandBits) | sig); +} + +// Avoid using fmax from libm. +static __inline fp_t __compiler_rt_fmaxX(fp_t x, fp_t y) { + // If either argument is NaN, return the other argument. If both are NaN, + // arbitrarily return the second one. Otherwise, if both arguments are +/-0, + // arbitrarily return the first one. + return (crt_isnan(x) || x < y) ? y : x; +} + #endif #if defined(SINGLE_PRECISION) + static __inline fp_t __compiler_rt_logbf(fp_t x) { return __compiler_rt_logbX(x); } +static __inline fp_t __compiler_rt_scalbnf(fp_t x, int y) { + return __compiler_rt_scalbnX(x, y); +} +static __inline fp_t __compiler_rt_fmaxf(fp_t x, fp_t y) { +#if defined(__aarch64__) + // Use __builtin_fmaxf which turns into an fmaxnm instruction on AArch64. + return __builtin_fmaxf(x, y); +#else + // __builtin_fmaxf frequently turns into a libm call, so inline the function. + return __compiler_rt_fmaxX(x, y); +#endif +} + #elif defined(DOUBLE_PRECISION) + static __inline fp_t __compiler_rt_logb(fp_t x) { return __compiler_rt_logbX(x); } +static __inline fp_t __compiler_rt_scalbn(fp_t x, int y) { + return __compiler_rt_scalbnX(x, y); +} +static __inline fp_t __compiler_rt_fmax(fp_t x, fp_t y) { +#if defined(__aarch64__) + // Use __builtin_fmax which turns into an fmaxnm instruction on AArch64. + return __builtin_fmax(x, y); +#else + // __builtin_fmax frequently turns into a libm call, so inline the function. + return __compiler_rt_fmaxX(x, y); +#endif +} + #elif defined(QUAD_PRECISION) + #if defined(CRT_LDBL_128BIT) static __inline fp_t __compiler_rt_logbl(fp_t x) { return __compiler_rt_logbX(x); } +static __inline fp_t __compiler_rt_scalbnl(fp_t x, int y) { + return __compiler_rt_scalbnX(x, y); +} +static __inline fp_t __compiler_rt_fmaxl(fp_t x, fp_t y) { + return __compiler_rt_fmaxX(x, y); +} #else // The generic implementation only works for ieee754 floating point. For other // floating point types, continue to rely on the libm implementation for now. static __inline long double __compiler_rt_logbl(long double x) { return crt_logbl(x); } -#endif -#endif +static __inline long double __compiler_rt_scalbnl(long double x, int y) { + return crt_scalbnl(x, y); +} +static __inline long double __compiler_rt_fmaxl(long double x, long double y) { + return crt_fmaxl(x, y); +} +#endif // CRT_LDBL_128BIT + +#endif // *_PRECISION #endif // FP_LIB_HEADER |