• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef PANDA_PLUGINS_ETS_RUNTIME_DTOA_HELPER
17 #define PANDA_PLUGINS_ETS_RUNTIME_DTOA_HELPER
18 
19 #include <cstdint>
20 #include <cstddef>
21 #include <array>
22 #include "globals.h"
23 #include "macros.h"
24 #include "include/coretypes/tagged_value.h"
25 
26 // Almost copy of ets_runtime/ecmascript/base/dtoa_helper.h
27 
28 namespace ark::ets::intrinsics::helpers {
29 class DtoaHelper {
30 public:
DtoaHelper(char * buffer)31     explicit DtoaHelper(char *buffer) : buffer_(buffer) {}
32     void Dtoa(double value);
33 
GetPoint()34     int GetPoint()
35     {
36         return point_;
37     }
38 
GetDigits()39     int GetDigits()
40     {
41         return length_;
42     }
43 
44 private:
45     static constexpr int CACHED_POWERS_OFFSET = 348;
46     static constexpr double D_1_LOG2_10 = 0x1.34413509f79ffp-2;  // 1 / lg(10)
47     static constexpr int Q = -61;
48     static constexpr int INDEX = 20;
49     static constexpr int MIN_DECIMAL_EXPONENT = -348;
50     static constexpr auto POW10 = std::array {1ULL,
51                                               10ULL,
52                                               100ULL,
53                                               1000ULL,
54                                               10000ULL,
55                                               100000ULL,
56                                               1000000ULL,
57                                               10000000ULL,
58                                               100000000ULL,
59                                               1000000000ULL,
60                                               10000000000ULL,
61                                               100000000000ULL,
62                                               1000000000000ULL,
63                                               10000000000000ULL,
64                                               100000000000000ULL,
65                                               1000000000000000ULL,
66                                               10000000000000000ULL,
67                                               100000000000000000ULL,
68                                               1000000000000000000ULL,
69                                               10000000000000000000ULL};
70 
71     static constexpr uint32_t TEN = 10;
72     static constexpr uint32_t TEN2POW = 100;
73     static constexpr uint32_t TEN3POW = 1000;
74     static constexpr uint32_t TEN4POW = 10000;
75     static constexpr uint32_t TEN5POW = 100000;
76     static constexpr uint32_t TEN6POW = 1000000;
77     static constexpr uint32_t TEN7POW = 10000000;
78     static constexpr uint32_t TEN8POW = 100000000;
79 
80     // DiyFp is a floating-point number type, consists of a uint64 significand and one integer exponent.
81     class DiyFp {
82     public:
DiyFp()83         DiyFp() : f_(), e_() {}
DiyFp(uint64_t fp,int exp)84         DiyFp(uint64_t fp, int exp) : f_(fp), e_(exp) {}
85 
DiyFp(double d)86         explicit DiyFp(double d)
87         {
88             union {
89                 double d;
90                 uint64_t u64;
91             } u = {d};
92 
93             int biasedE =
94                 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
95                 static_cast<int>((u.u64 & coretypes::DOUBLE_EXPONENT_MASK) >> coretypes::DOUBLE_SIGNIFICAND_SIZE);
96             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
97             uint64_t significand = (u.u64 & coretypes::DOUBLE_SIGNIFICAND_MASK);
98             if (biasedE != 0) {
99                 f_ = significand + coretypes::DOUBLE_HIDDEN_BIT;
100                 e_ = biasedE - DP_EXPONENT_BIAS;
101             } else {
102                 f_ = significand;
103                 e_ = DP_MIN_EXPONENT + 1;
104             }
105         }
106 
107         DiyFp operator-(const DiyFp &rhs) const
108         {
109             return DiyFp(f_ - rhs.f_, e_);
110         }
111 
112         DiyFp operator*(const DiyFp &rhs) const
113         {
114             constexpr uint64_t M32 = UINT32_MAX;
115             const uint64_t a = f_ >> BITS_PER_UINT32;
116             const uint64_t b = f_ & M32;
117             const uint64_t c = rhs.f_ >> BITS_PER_UINT32;
118             const uint64_t d = rhs.f_ & M32;
119             const uint64_t ac = a * c;
120             const uint64_t bc = b * c;
121             const uint64_t ad = a * d;
122             const uint64_t bd = b * d;
123             uint64_t tmp = (bd >> BITS_PER_UINT32) + (ad & M32) + (bc & M32);
124             tmp += 1U << ROUND_BITS;  // mult_round
125             return DiyFp(ac + (ad >> BITS_PER_UINT32) + (bc >> BITS_PER_UINT32) + (tmp >> BITS_PER_UINT32),
126                          e_ + rhs.e_ + BITS_PER_UINT64);
127         }
128 
Normalize()129         DiyFp Normalize() const
130         {
131             DiyFp res = *this;
132             while ((res.f_ & coretypes::DOUBLE_HIDDEN_BIT) == 0) {
133                 res.f_ <<= 1U;
134                 res.e_--;
135             }
136             res.f_ <<= (DIY_SIGNIFICAND_SIZE - coretypes::DOUBLE_SIGNIFICAND_SIZE - 1);
137             res.e_ = res.e_ - (DIY_SIGNIFICAND_SIZE - coretypes::DOUBLE_SIGNIFICAND_SIZE - 1);
138             return res;
139         }
140 
NormalizeBoundary()141         DiyFp NormalizeBoundary() const
142         {
143             DiyFp res = *this;
144             while ((res.f_ & (coretypes::DOUBLE_HIDDEN_BIT << 1U)) == 0) {
145                 res.f_ <<= 1U;
146                 res.e_--;
147             }
148             res.f_ <<= (DIY_SIGNIFICAND_SIZE - coretypes::DOUBLE_SIGNIFICAND_SIZE - 2);         // 2: parameter
149             res.e_ = res.e_ - (DIY_SIGNIFICAND_SIZE - coretypes::DOUBLE_SIGNIFICAND_SIZE - 2);  // 2: parameter
150             return res;
151         }
152 
NormalizedBoundaries(DiyFp * minus,DiyFp * plus)153         void NormalizedBoundaries(DiyFp *minus, DiyFp *plus) const
154         {
155             DiyFp pl = DiyFp((f_ << 1U) + 1, e_ - 1).NormalizeBoundary();
156             DiyFp mi = (f_ == coretypes::DOUBLE_HIDDEN_BIT) ? DiyFp((f_ << 2U) - 1, e_ - 2)
157                                                             : DiyFp((f_ << 1U) - 1, e_ - 1);  // 2: parameter
158             ASSERT(mi.e_ >= pl.e_);
159             mi.f_ <<= static_cast<uint32_t>(mi.e_ - pl.e_);
160             mi.e_ = pl.e_;
161             *plus = pl;
162             *minus = mi;
163         }
164 
165         static constexpr uint32_t ROUND_BITS = BITS_PER_UINT32 - 1;
166         static constexpr uint32_t DIY_SIGNIFICAND_SIZE = BITS_PER_UINT64;
167         static constexpr int32_t DP_EXPONENT_BIAS =
168             coretypes::DOUBLE_EXPONENT_BIAS + coretypes::DOUBLE_SIGNIFICAND_SIZE;
169         static constexpr int32_t DP_MAX_EXPONENT = coretypes::DOUBLE_EXPONENT_MAX - DP_EXPONENT_BIAS;
170         static constexpr int32_t DP_MIN_EXPONENT = -DP_EXPONENT_BIAS;
171         static constexpr int32_t DP_DENORMAL_EXPONENT = -DP_EXPONENT_BIAS + 1;
172 
173     private:
174         uint64_t f_;
175         int e_;
176         friend class DtoaHelper;
177     };
178 
179     DiyFp GetCachedPower(int e);
180     static DiyFp GetCachedPowerByIndex(std::size_t index);
181     void GrisuRound(uint64_t delta, uint64_t rest, uint64_t tenKappa, uint64_t distance);
182     static int CountDecimalDigit32(uint32_t n);
183     static uint32_t PopDigit(int kappa, uint32_t &p1);
184     void DigitGen(const DiyFp &w, const DiyFp &mp, uint64_t delta);
185     void Grisu(double value);
186 
187 private:
188     char *buffer_;
189     int length_ {};
190     int point_ {};
191     int k_ {};
192 };
193 }  // namespace ark::ets::intrinsics::helpers
194 #endif  // PANDA_PLUGINS_ETS_RUNTIME_DTOA_HELPER