1 /**
2 * Copyright (c) 2021-2022 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 ECMASCRIPT_BASE_MATH_HELPER_H
17 #define ECMASCRIPT_BASE_MATH_HELPER_H
18
19 #include <cstdint>
20 #include <cmath>
21
22 #include "ecmascript/base/bit_helper.h"
23
24 #define panda_bit_utils_ctz __builtin_ctz // NOLINT(cppcoreguidelines-macro-usage)
25 #define panda_bit_utils_ctzll __builtin_ctzll // NOLINT(cppcoreguidelines-macro-usage)
26
27 namespace panda::ecmascript::base {
28 class MathHelper {
29 public:
GetIntLog2(const uint32_t X)30 static constexpr uint32_t GetIntLog2(const uint32_t X)
31 {
32 return static_cast<uint32_t>(panda_bit_utils_ctz(X));
33 }
34
GetIntLog2(const uint64_t X)35 static constexpr uint64_t GetIntLog2(const uint64_t X)
36 {
37 return static_cast<uint64_t>(panda_bit_utils_ctzll(X));
38 }
39
Asinh(double input)40 static double Asinh(double input)
41 {
42 #if defined(PANDA_TARGET_WINDOWS)
43 if (input == 0 && !std::signbit(input)) {
44 // +0.0(double) is the special case for std::asinh() function compiled in linux for windows.
45 return +0.0;
46 }
47 #endif
48 return std::asinh(input);
49 }
50
Atanh(double input)51 static inline double Atanh(double input)
52 {
53 #if defined(PANDA_TARGET_WINDOWS)
54 if (input == 0 && std::signbit(input)) {
55 // -0.0(double) is the special case for std::atanh() function compiled in linux for windows.
56 return -0.0;
57 }
58 #endif
59 return std::atanh(input);
60 }
61 };
62
63 template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
WhichPowerOfTwo(T value)64 inline constexpr int WhichPowerOfTwo(T value)
65 {
66 // Ensure the size of the integer is no more than 8 bytes (64 bits).
67 static_assert(sizeof(T) <= 8);
68 // Use __builtin_ctzll for 8 bytes (64 bits) and __builtin_ctz for 32-bit integers.
69 return sizeof(T) == 8 ? __builtin_ctzll(static_cast<uint64_t>(value)) : __builtin_ctz(static_cast<uint32_t>(value));
70 }
71
72
SignedDiv32(int32_t lhs,int32_t rhs)73 inline int32_t SignedDiv32(int32_t lhs, int32_t rhs)
74 {
75 if (rhs == 0) {
76 return 0;
77 }
78 if (rhs == -1) {
79 return lhs == std::numeric_limits<int32_t>::min() ? lhs : -lhs;
80 }
81 return lhs / rhs;
82 }
83
SignedDiv64(int64_t lhs,int64_t rhs)84 inline int64_t SignedDiv64(int64_t lhs, int64_t rhs)
85 {
86 if (rhs == 0) {
87 return 0;
88 }
89 if (rhs == -1) {
90 return lhs == std::numeric_limits<int64_t>::min() ? lhs : -lhs;
91 }
92 return lhs / rhs;
93 }
94
SignedMod32(int32_t lhs,int32_t rhs)95 inline int32_t SignedMod32(int32_t lhs, int32_t rhs)
96 {
97 if (rhs == 0 || rhs == -1) {
98 return 0;
99 }
100 return lhs % rhs;
101 }
102
103
SignedAddOverflow32(int32_t lhs,int32_t rhs,int32_t * val)104 inline bool SignedAddOverflow32(int32_t lhs, int32_t rhs, int32_t *val)
105 {
106 uint32_t res = static_cast<uint32_t>(lhs) + static_cast<uint32_t>(rhs);
107 *val = base::bit_cast<int32_t>(res);
108 // Check for overflow by examining the sign bit.(bit 31 in a 32-bit integer)
109 return ((res ^ static_cast<uint32_t>(lhs)) & (res ^ static_cast<uint32_t>(rhs)) & (1U << 31)) != 0;
110 }
111
112
SignedSubOverflow32(int32_t lhs,int32_t rhs,int32_t * val)113 inline bool SignedSubOverflow32(int32_t lhs, int32_t rhs, int32_t *val)
114 {
115 uint32_t res = static_cast<uint32_t>(lhs) - static_cast<uint32_t>(rhs);
116 *val = base::bit_cast<int32_t>(res);
117 // Check for overflow by examining the sign bit.(bit 31 in a 32-bit integer)
118 return ((res ^ static_cast<uint32_t>(lhs)) & (res ^ ~static_cast<uint32_t>(rhs)) & (1U << 31)) != 0;
119 }
120
SignedMulOverflow32(int32_t lhs,int32_t rhs,int32_t * val)121 inline bool SignedMulOverflow32(int32_t lhs, int32_t rhs, int32_t *val)
122 {
123 int64_t result = int64_t{lhs} * int64_t{rhs};
124 *val = static_cast<int32_t>(result);
125 using limits = std::numeric_limits<int32_t>;
126 return result < limits::min() || result > limits::max();
127 }
128
129
130 // Returns the quotient x/y, avoiding C++ undefined behavior if y == 0.
131 template <typename T>
Divide(T x,T y)132 inline T Divide(T x, T y)
133 {
134 if (y != 0) {
135 return x / y;
136 }
137 if (x == 0 || x != x) {
138 return std::numeric_limits<T>::quiet_NaN();
139 }
140 if ((x >= 0) == (std::signbit(y) == 0)) {
141 return std::numeric_limits<T>::infinity();
142 }
143 return -std::numeric_limits<T>::infinity();
144 }
145
146
147 template <typename SignedType>
AddWithWraparound(SignedType a,SignedType b)148 inline SignedType AddWithWraparound(SignedType a, SignedType b)
149 {
150 static_assert(std::is_integral<SignedType>::value && std::is_signed<SignedType>::value,
151 "use this for signed integer types");
152 using UnsignedType = typename std::make_unsigned<SignedType>::type;
153 UnsignedType aUnsigned = static_cast<UnsignedType>(a);
154 UnsignedType bUnsigned = static_cast<UnsignedType>(b);
155 UnsignedType result = aUnsigned + bUnsigned;
156 return static_cast<SignedType>(result);
157 }
158
159 template <typename SignedType>
SubWithWraparound(SignedType a,SignedType b)160 inline SignedType SubWithWraparound(SignedType a, SignedType b)
161 {
162 static_assert(std::is_integral<SignedType>::value && std::is_signed<SignedType>::value,
163 "use this for signed integer types");
164 using UnsignedType = typename std::make_unsigned<SignedType>::type;
165 UnsignedType aUnsigned = static_cast<UnsignedType>(a);
166 UnsignedType bUnsigned = static_cast<UnsignedType>(b);
167 UnsignedType result = aUnsigned - bUnsigned;
168 return static_cast<SignedType>(result);
169 }
170
171 template <typename SignedType>
MulWithWraparound(SignedType a,SignedType b)172 inline SignedType MulWithWraparound(SignedType a, SignedType b)
173 {
174 static_assert(std::is_integral<SignedType>::value && std::is_signed<SignedType>::value,
175 "use this for signed integer types");
176 using UnsignedType = typename std::make_unsigned<SignedType>::type;
177 UnsignedType aUnsigned = static_cast<UnsignedType>(a);
178 UnsignedType bUnsigned = static_cast<UnsignedType>(b);
179 UnsignedType result = aUnsigned * bUnsigned;
180 return static_cast<SignedType>(result);
181 }
182
183 template <typename SignedType>
ShlWithWraparound(SignedType a,SignedType b)184 inline SignedType ShlWithWraparound(SignedType a, SignedType b)
185 {
186 using UnsignedType = typename std::make_unsigned<SignedType>::type;
187 const UnsignedType kMask = (sizeof(a) * 8) - 1;
188 return static_cast<SignedType>(static_cast<UnsignedType>(a) << (static_cast<UnsignedType>(b) & kMask));
189 }
190
191 template <typename SignedType>
NegateWithWraparound(SignedType a)192 inline SignedType NegateWithWraparound(SignedType a)
193 {
194 static_assert(std::is_integral<SignedType>::value && std::is_signed<SignedType>::value,
195 "use this for signed integer types");
196 if (a == std::numeric_limits<SignedType>::min()) {
197 return a;
198 }
199 return -a;
200 }
201 } // panda::ecmascript::base
202
203 #endif // ECMASCRIPT_BASE_MATH_HELPER_H
204