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 #ifndef PANDA_INTERPRETER_MATH_HELPERS_H_
16 #define PANDA_INTERPRETER_MATH_HELPERS_H_
17
18 #include <cmath>
19 #include <functional>
20 #include <limits>
21 #include <type_traits>
22
23 #include "libpandabase/macros.h"
24
25 namespace panda::interpreter::math_helpers {
26
27 template <typename T>
28 struct bit_shl : public std::binary_function<T, T, T> { // NOLINT(readability-identifier-naming)
operatorbit_shl29 constexpr T operator()(const T &x, const T &y) const
30 {
31 using unsigned_type = std::make_unsigned_t<T>;
32 size_t mask = std::numeric_limits<unsigned_type>::digits - 1;
33 size_t shift = static_cast<unsigned_type>(y) & mask;
34 return static_cast<T>(static_cast<unsigned_type>(x) << shift);
35 }
36 };
37
38 template <typename T>
39 struct bit_shr : public std::binary_function<T, T, T> { // NOLINT(readability-identifier-naming)
operatorbit_shr40 constexpr T operator()(const T &x, const T &y) const
41 {
42 using unsigned_type = std::make_unsigned_t<T>;
43 size_t mask = std::numeric_limits<unsigned_type>::digits - 1;
44 size_t shift = static_cast<unsigned_type>(y) & mask;
45 return static_cast<T>(static_cast<unsigned_type>(x) >> shift);
46 }
47 };
48
49 template <typename T>
50 struct bit_ashr : public std::binary_function<T, T, T> { // NOLINT(readability-identifier-naming)
operatorbit_ashr51 constexpr T operator()(const T &x, const T &y) const
52 {
53 using unsigned_type = std::make_unsigned_t<T>;
54 size_t mask = std::numeric_limits<unsigned_type>::digits - 1;
55 size_t shift = static_cast<unsigned_type>(y) & mask;
56 return x >> shift; // NOLINT(hicpp-signed-bitwise)
57 }
58 };
59
60 template <typename T>
61 struct fmodulus : public std::binary_function<T, T, T> { // NOLINT(readability-identifier-naming)
operatorfmodulus62 constexpr T operator()(const T &x, const T &y) const
63 {
64 static_assert(std::is_floating_point_v<T>, "T should be floating point type");
65 return std::fmod(x, y);
66 }
67 };
68
69 template <typename T>
70 struct cmp : public std::binary_function<T, T, int32_t> { // NOLINT(readability-identifier-naming)
operatorcmp71 constexpr int32_t operator()(const T &x, const T &y) const
72 {
73 static_assert(std::is_integral_v<T>, "T should be integral type");
74
75 if (x > y) {
76 return 1;
77 }
78
79 if (x == y) {
80 return 0;
81 }
82
83 return -1;
84 }
85 };
86
87 template <typename T>
88 struct fcmpl : public std::binary_function<T, T, int32_t> { // NOLINT(readability-identifier-naming)
operatorfcmpl89 constexpr int32_t operator()(const T &x, const T &y) const
90 {
91 static_assert(std::is_floating_point_v<T>, "T should be floating point type");
92
93 if (x > y) {
94 return 1;
95 }
96
97 if (x == y) {
98 return 0;
99 }
100
101 return -1;
102 }
103 };
104
105 template <typename T>
106 struct fcmpg : public std::binary_function<T, T, int32_t> { // NOLINT(readability-identifier-naming)
operatorfcmpg107 constexpr int32_t operator()(const T &x, const T &y) const
108 {
109 static_assert(std::is_floating_point_v<T>, "T should be floating point type");
110
111 if (x < y) {
112 return -1;
113 }
114
115 if (x == y) {
116 return 0;
117 }
118
119 return 1;
120 }
121 };
122
123 template <typename T>
124 struct idivides : public std::binary_function<T, T, T> { // NOLINT(readability-identifier-naming)
operatoridivides125 constexpr T operator()(const T &x, const T &y) const
126 {
127 static_assert(std::is_integral_v<T>, "T should be integral type");
128
129 // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
130 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
131 if constexpr (std::is_signed_v<T>) {
132 constexpr T MIN = std::numeric_limits<T>::min();
133
134 if (UNLIKELY(x == MIN && y == -1)) {
135 return MIN;
136 }
137 }
138
139 return x / y;
140 }
141 };
142
143 template <typename T>
144 struct imodulus : public std::binary_function<T, T, T> { // NOLINT(readability-identifier-naming)
operatorimodulus145 constexpr T operator()(const T &x, const T &y) const
146 {
147 static_assert(std::is_integral_v<T>, "T should be integral type");
148
149 // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
150 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
151 if constexpr (std::is_signed_v<T>) {
152 constexpr T MIN = std::numeric_limits<T>::min();
153
154 if (UNLIKELY(x == MIN && y == -1)) {
155 return 0;
156 }
157 }
158
159 return x % y;
160 }
161 };
162
163 template <template <typename OpT> class Op, typename T>
SafeMath(T a,T b)164 ALWAYS_INLINE static inline T SafeMath(T a, T b)
165 {
166 using unsigned_T = std::make_unsigned_t<T>;
167 static_assert(std::is_signed<T>::value, "Expected T to be signed");
168 auto val1 = static_cast<unsigned_T>(a);
169 auto val2 = static_cast<unsigned_T>(b);
170 return static_cast<T>(Op<unsigned_T>()(val1, val2));
171 }
172
173 template <typename T>
174 struct Plus {
operatorPlus175 ALWAYS_INLINE inline T operator()(T a, T b)
176 {
177 return SafeMath<std::plus>(a, b);
178 }
179 };
180
181 template <typename T>
182 struct Minus {
operatorMinus183 ALWAYS_INLINE inline T operator()(T a, T b)
184 {
185 return SafeMath<std::minus>(a, b);
186 }
187 };
188
189 template <typename T>
190 struct Multiplies {
operatorMultiplies191 ALWAYS_INLINE inline T operator()(T a, T b)
192 {
193 return SafeMath<std::multiplies>(a, b);
194 }
195 };
196
197 template <typename T>
198 struct inc : public std::unary_function<T, T> { // NOLINT(readability-identifier-naming)
operatorinc199 constexpr T operator()(const T &x) const
200 {
201 return SafeMath<std::plus>(x, 1);
202 }
203 };
204
205 template <typename T>
206 struct dec : public std::unary_function<T, T> { // NOLINT(readability-identifier-naming)
operatordec207 constexpr T operator()(const T &x) const
208 {
209 return SafeMath<std::minus>(x, 1);
210 }
211 };
212
213 } // namespace panda::interpreter::math_helpers
214
215 #endif // PANDA_INTERPRETER_FRAME_H_
216