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