1bbb75554SSiva Chandra //===-- Single-precision 2^x function -------------------------------------===//
2bbb75554SSiva Chandra //
3bbb75554SSiva Chandra // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bbb75554SSiva Chandra // See https://llvm.org/LICENSE.txt for license information.
5bbb75554SSiva Chandra // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bbb75554SSiva Chandra //
7bbb75554SSiva Chandra //===----------------------------------------------------------------------===//
8bbb75554SSiva Chandra 
9bbb75554SSiva Chandra #include "src/math/exp2f.h"
1064721a33STue Ly #include "src/__support/FPUtil/BasicOperations.h"
1164721a33STue Ly #include "src/__support/FPUtil/FEnvImpl.h"
1264721a33STue Ly #include "src/__support/FPUtil/FMA.h"
1364721a33STue Ly #include "src/__support/FPUtil/FPBits.h"
1464721a33STue Ly #include "src/__support/FPUtil/PolyEval.h"
15bbb75554SSiva Chandra #include "src/__support/common.h"
16bbb75554SSiva Chandra 
1764721a33STue Ly #include <errno.h>
18bbb75554SSiva Chandra 
19bbb75554SSiva Chandra namespace __llvm_libc {
20bbb75554SSiva Chandra 
21*b9d87d74STue Ly // Lookup table for 2^(m * 2^(-6)) with m = 0, ..., 63.
2264721a33STue Ly // Table is generated with Sollya as follow:
2364721a33STue Ly // > display = hexadecimal;
24*b9d87d74STue Ly // > for i from 0 to 63 do { D(2^(i / 64)); };
25*b9d87d74STue Ly static constexpr double EXP_M[64] = {
26*b9d87d74STue Ly     0x1.0000000000000p0, 0x1.02c9a3e778061p0, 0x1.059b0d3158574p0,
27*b9d87d74STue Ly     0x1.0874518759bc8p0, 0x1.0b5586cf9890fp0, 0x1.0e3ec32d3d1a2p0,
28*b9d87d74STue Ly     0x1.11301d0125b51p0, 0x1.1429aaea92de0p0, 0x1.172b83c7d517bp0,
29*b9d87d74STue Ly     0x1.1a35beb6fcb75p0, 0x1.1d4873168b9aap0, 0x1.2063b88628cd6p0,
30*b9d87d74STue Ly     0x1.2387a6e756238p0, 0x1.26b4565e27cddp0, 0x1.29e9df51fdee1p0,
31*b9d87d74STue Ly     0x1.2d285a6e4030bp0, 0x1.306fe0a31b715p0, 0x1.33c08b26416ffp0,
32*b9d87d74STue Ly     0x1.371a7373aa9cbp0, 0x1.3a7db34e59ff7p0, 0x1.3dea64c123422p0,
33*b9d87d74STue Ly     0x1.4160a21f72e2ap0, 0x1.44e086061892dp0, 0x1.486a2b5c13cd0p0,
34*b9d87d74STue Ly     0x1.4bfdad5362a27p0, 0x1.4f9b2769d2ca7p0, 0x1.5342b569d4f82p0,
35*b9d87d74STue Ly     0x1.56f4736b527dap0, 0x1.5ab07dd485429p0, 0x1.5e76f15ad2148p0,
36*b9d87d74STue Ly     0x1.6247eb03a5585p0, 0x1.6623882552225p0, 0x1.6a09e667f3bcdp0,
37*b9d87d74STue Ly     0x1.6dfb23c651a2fp0, 0x1.71f75e8ec5f74p0, 0x1.75feb564267c9p0,
38*b9d87d74STue Ly     0x1.7a11473eb0187p0, 0x1.7e2f336cf4e62p0, 0x1.82589994cce13p0,
39*b9d87d74STue Ly     0x1.868d99b4492edp0, 0x1.8ace5422aa0dbp0, 0x1.8f1ae99157736p0,
40*b9d87d74STue Ly     0x1.93737b0cdc5e5p0, 0x1.97d829fde4e50p0, 0x1.9c49182a3f090p0,
41*b9d87d74STue Ly     0x1.a0c667b5de565p0, 0x1.a5503b23e255dp0, 0x1.a9e6b5579fdbfp0,
42*b9d87d74STue Ly     0x1.ae89f995ad3adp0, 0x1.b33a2b84f15fbp0, 0x1.b7f76f2fb5e47p0,
43*b9d87d74STue Ly     0x1.bcc1e904bc1d2p0, 0x1.c199bdd85529cp0, 0x1.c67f12e57d14bp0,
44*b9d87d74STue Ly     0x1.cb720dcef9069p0, 0x1.d072d4a07897cp0, 0x1.d5818dcfba487p0,
45*b9d87d74STue Ly     0x1.da9e603db3285p0, 0x1.dfc97337b9b5fp0, 0x1.e502ee78b3ff6p0,
46*b9d87d74STue Ly     0x1.ea4afa2a490dap0, 0x1.efa1bee615a27p0, 0x1.f50765b6e4540p0,
47*b9d87d74STue Ly     0x1.fa7c1819e90d8p0,
4864721a33STue Ly };
49bbb75554SSiva Chandra 
5064721a33STue Ly LLVM_LIBC_FUNCTION(float, exp2f, (float x)) {
5164721a33STue Ly   using FPBits = typename fputil::FPBits<float>;
5264721a33STue Ly   FPBits xbits(x);
5364721a33STue Ly 
54*b9d87d74STue Ly   uint32_t x_u = xbits.uintval();
55*b9d87d74STue Ly   uint32_t x_abs = x_u & 0x7fff'ffffU;
56*b9d87d74STue Ly 
57*b9d87d74STue Ly   // Exceptional values.
58*b9d87d74STue Ly   switch (x_u) {
59*b9d87d74STue Ly   case 0x3b42'9d37U: // x = 0x1.853a6ep-9f
60*b9d87d74STue Ly     if (fputil::get_round() == FE_TONEAREST)
61*b9d87d74STue Ly       return 0x1.00870ap+0f;
62*b9d87d74STue Ly     break;
63*b9d87d74STue Ly   case 0x3c02'a9adU: // x = 0x1.05535ap-7f
64*b9d87d74STue Ly     if (fputil::get_round() == FE_TONEAREST)
65*b9d87d74STue Ly       return 0x1.016b46p+0f;
66*b9d87d74STue Ly     break;
67*b9d87d74STue Ly   case 0x3ca6'6e26U: { // x = 0x1.4cdc4cp-6f
68*b9d87d74STue Ly     int round_mode = fputil::get_round();
69*b9d87d74STue Ly     if (round_mode == FE_TONEAREST || round_mode == FE_UPWARD)
70*b9d87d74STue Ly       return 0x1.03a16ap+0f;
71*b9d87d74STue Ly     return 0x1.03a168p+0f;
72*b9d87d74STue Ly   }
73*b9d87d74STue Ly   case 0x3d92'a282U: // x = 0x1.254504p-4f
74*b9d87d74STue Ly     if (fputil::get_round() == FE_UPWARD)
75*b9d87d74STue Ly       return 0x1.0d0688p+0f;
76*b9d87d74STue Ly     return 0x1.0d0686p+0f;
77*b9d87d74STue Ly   case 0xbcf3'a937U: // x = -0x1.e7526ep-6f
78*b9d87d74STue Ly     if (fputil::get_round() == FE_TONEAREST)
79*b9d87d74STue Ly       return 0x1.f58d62p-1f;
80*b9d87d74STue Ly     break;
81*b9d87d74STue Ly   case 0xb8d3'd026U: // x = -0x1.a7a04cp-14f
82*b9d87d74STue Ly     if (fputil::get_round() == FE_TONEAREST)
83*b9d87d74STue Ly       return 0x1.fff6d2p-1f;
84*b9d87d74STue Ly     break;
85*b9d87d74STue Ly   }
86*b9d87d74STue Ly 
87*b9d87d74STue Ly   // // When |x| >= 128, |x| < 2^-25, or x is nan
88*b9d87d74STue Ly   if (unlikely(x_abs >= 0x4300'0000U || x_abs <= 0x3280'0000U)) {
89*b9d87d74STue Ly     // |x| < 2^-25
90*b9d87d74STue Ly     if (x_abs <= 0x3280'0000U) {
91*b9d87d74STue Ly       return 1.0f + x;
92*b9d87d74STue Ly     }
93*b9d87d74STue Ly     // x >= 128
94*b9d87d74STue Ly     if (!xbits.get_sign()) {
95*b9d87d74STue Ly       // x is finite
96*b9d87d74STue Ly       if (x_u < 0x7f80'0000U) {
97*b9d87d74STue Ly         int rounding = fputil::get_round();
98*b9d87d74STue Ly         if (rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)
99*b9d87d74STue Ly           return static_cast<float>(FPBits(FPBits::MAX_NORMAL));
100*b9d87d74STue Ly 
101*b9d87d74STue Ly         errno = ERANGE;
102*b9d87d74STue Ly       }
103*b9d87d74STue Ly       // x is +inf or nan
104*b9d87d74STue Ly       return x + static_cast<float>(FPBits::inf());
105*b9d87d74STue Ly     }
106*b9d87d74STue Ly     // x < -150
107*b9d87d74STue Ly     if (x_u >= 0xc316'0000U) {
10864721a33STue Ly       // exp(-Inf) = 0
10964721a33STue Ly       if (xbits.is_inf())
110bbb75554SSiva Chandra         return 0.0f;
11164721a33STue Ly       // exp(nan) = nan
11264721a33STue Ly       if (xbits.is_nan())
11364721a33STue Ly         return x;
11464721a33STue Ly       if (fputil::get_round() == FE_UPWARD)
11564721a33STue Ly         return static_cast<float>(FPBits(FPBits::MIN_SUBNORMAL));
11664721a33STue Ly       if (x != 0.0f)
11764721a33STue Ly         errno = ERANGE;
11864721a33STue Ly       return 0.0f;
11964721a33STue Ly     }
12064721a33STue Ly   }
12164721a33STue Ly   // For -150 <= x < 128, to compute 2^x, we perform the following range
12264721a33STue Ly   // reduction: find hi, mid, lo such that:
12364721a33STue Ly   //   x = hi + mid + lo, in which
12464721a33STue Ly   //     hi is an integer,
125*b9d87d74STue Ly   //     mid * 2^6 is an integer
126*b9d87d74STue Ly   //     -2^(-7) <= lo < 2^-7.
12764721a33STue Ly   // In particular,
128*b9d87d74STue Ly   //   hi + mid = round(x * 2^6) * 2^(-6).
12964721a33STue Ly   // Then,
13064721a33STue Ly   //   2^(x) = 2^(hi + mid + lo) = 2^hi * 2^mid * 2^lo.
13164721a33STue Ly   // Multiply by 2^hi is simply adding hi to the exponent field.  We store
132*b9d87d74STue Ly   // exp(mid) in the lookup tables EXP_M.  exp(lo) is computed using a degree-4
13364721a33STue Ly   // minimax polynomial generated by Sollya.
134bbb75554SSiva Chandra 
135*b9d87d74STue Ly   // x_hi = round(hi + mid).
136*b9d87d74STue Ly   // The default rounding mode for float-to-int conversion in C++ is
137*b9d87d74STue Ly   // round-toward-zero. To make it round-to-nearest, we add (-1)^sign(x) * 0.5
138*b9d87d74STue Ly   // before conversion.
139*b9d87d74STue Ly   int x_hi =
140*b9d87d74STue Ly       static_cast<int>(x * 0x1.0p+6f + (xbits.get_sign() ? -0.5f : 0.5f));
14164721a33STue Ly   // For 2-complement integers, arithmetic right shift is the same as dividing
14264721a33STue Ly   // by a power of 2 and then round down (toward negative infinity).
143*b9d87d74STue Ly   int e_hi = (x_hi >> 6) +
144*b9d87d74STue Ly              static_cast<int>(fputil::FloatProperties<double>::EXPONENT_BIAS);
145*b9d87d74STue Ly   fputil::FPBits<double> exp_hi(
146*b9d87d74STue Ly       static_cast<uint64_t>(e_hi)
147*b9d87d74STue Ly       << fputil::FloatProperties<double>::MANTISSA_WIDTH);
148*b9d87d74STue Ly   // mid = x_hi & 0x0000'003fU;
149*b9d87d74STue Ly   double exp_hi_mid = static_cast<double>(exp_hi) * EXP_M[x_hi & 0x3f];
150*b9d87d74STue Ly   // Subtract (hi + mid) from x to get lo.
151*b9d87d74STue Ly   x -= static_cast<float>(x_hi) * 0x1.0p-6f;
152*b9d87d74STue Ly   double xd = static_cast<double>(x);
153*b9d87d74STue Ly   // Degree-4 minimax polynomial generated by Sollya with the following
15464721a33STue Ly   // commands:
15564721a33STue Ly   //   > display = hexadecimal;
156*b9d87d74STue Ly   //   > Q = fpminimax((2^x - 1)/x, 3, [|D...|], [-2^-7, 2^-7]);
15764721a33STue Ly   //   > Q;
15864721a33STue Ly   double exp_lo =
159*b9d87d74STue Ly       fputil::polyeval(xd, 0x1p0, 0x1.62e42fefa2417p-1, 0x1.ebfbdff82f809p-3,
160*b9d87d74STue Ly                        0x1.c6b0b92131c47p-5, 0x1.3b2ab6fb568a3p-7);
161*b9d87d74STue Ly   double result = exp_hi_mid * exp_lo;
162*b9d87d74STue Ly   return static_cast<float>(result);
163bbb75554SSiva Chandra }
164bbb75554SSiva Chandra 
165bbb75554SSiva Chandra } // namespace __llvm_libc
166