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 27namespace panda::ecmascript::base { 28class MathHelper { 29public: 30 static constexpr uint32_t GetIntLog2(const uint32_t X) 31 { 32 return static_cast<uint32_t>(panda_bit_utils_ctz(X)); 33 } 34 35 static constexpr uint64_t GetIntLog2(const uint64_t X) 36 { 37 return static_cast<uint64_t>(panda_bit_utils_ctzll(X)); 38 } 39 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 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 63template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type> 64inline 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 73inline 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 84inline 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 95inline 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 104inline 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 113inline 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 121inline 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. 131template <typename T> 132inline 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 147template <typename SignedType> 148inline 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 159template <typename SignedType> 160inline 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 171template <typename SignedType> 172inline 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 183template <typename SignedType> 184inline 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 191template <typename SignedType> 192inline 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