• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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_RUNTIME_INTERPRETER_MATH_HELPERS_H_
17 #define PANDA_RUNTIME_INTERPRETER_MATH_HELPERS_H_
18 
19 #include <cmath>
20 #include <functional>
21 #include <limits>
22 #include <type_traits>
23 
24 #include "libpandabase/macros.h"
25 
26 namespace panda::interpreter::math_helpers {
27 
28 template <typename T>
29 struct bit_shl : public std::binary_function<T, T, T> {  // NOLINT(readability-identifier-naming)
operatorbit_shl30     constexpr T operator()(const T &x, const T &y) const
31     {
32         using unsigned_type = std::make_unsigned_t<T>;
33         size_t mask = std::numeric_limits<unsigned_type>::digits - 1;
34         size_t shift = static_cast<unsigned_type>(y) & mask;
35         return static_cast<T>(static_cast<unsigned_type>(x) << shift);
36     }
37 };
38 
39 template <typename T>
40 struct bit_shr : public std::binary_function<T, T, T> {  // NOLINT(readability-identifier-naming)
operatorbit_shr41     constexpr T operator()(const T &x, const T &y) const
42     {
43         using unsigned_type = std::make_unsigned_t<T>;
44         size_t mask = std::numeric_limits<unsigned_type>::digits - 1;
45         size_t shift = static_cast<unsigned_type>(y) & mask;
46         return static_cast<T>(static_cast<unsigned_type>(x) >> shift);
47     }
48 };
49 
50 template <typename T>
51 struct bit_ashr : public std::binary_function<T, T, T> {  // NOLINT(readability-identifier-naming)
operatorbit_ashr52     constexpr T operator()(const T &x, const T &y) const
53     {
54         using unsigned_type = std::make_unsigned_t<T>;
55         size_t mask = std::numeric_limits<unsigned_type>::digits - 1;
56         size_t shift = static_cast<unsigned_type>(y) & mask;
57         return x >> shift;  // NOLINT(hicpp-signed-bitwise)
58     }
59 };
60 
61 template <typename T>
62 struct fmodulus : public std::binary_function<T, T, T> {  // NOLINT(readability-identifier-naming)
operatorfmodulus63     constexpr T operator()(const T &x, const T &y) const
64     {
65         static_assert(std::is_floating_point_v<T>, "T should be floating point type");
66         return std::fmod(x, y);
67     }
68 };
69 
70 template <typename T>
71 struct cmp : public std::binary_function<T, T, int32_t> {  // NOLINT(readability-identifier-naming)
operatorcmp72     constexpr int32_t operator()(const T &x, const T &y) const
73     {
74         static_assert(std::is_integral_v<T>, "T should be integral type");
75 
76         if (x > y) {
77             return 1;
78         }
79 
80         if (x == y) {
81             return 0;
82         }
83 
84         return -1;
85     }
86 };
87 
88 template <typename T>
89 struct fcmpl : public std::binary_function<T, T, int32_t> {  // NOLINT(readability-identifier-naming)
operatorfcmpl90     constexpr int32_t operator()(const T &x, const T &y) const
91     {
92         static_assert(std::is_floating_point_v<T>, "T should be floating point type");
93 
94         if (std::isnan(x) || std::isnan(y)) {
95             return -1;  // this is the difference between fcmpl and fcmpg for NAN
96         }
97 
98         if (x < y) {
99             return -1;
100         }
101 
102         if (x > y) {
103             return 1;
104         }
105 
106         return 0;
107     }
108 };
109 
110 template <typename T>
111 struct fcmpg : public std::binary_function<T, T, int32_t> {  // NOLINT(readability-identifier-naming)
operatorfcmpg112     constexpr int32_t operator()(const T &x, const T &y) const
113     {
114         static_assert(std::is_floating_point_v<T>, "T should be floating point type");
115 
116         if (std::isnan(x) || std::isnan(y)) {
117             return 1;  // this is the difference between fcmpl and fcmpg for NAN
118         }
119 
120         if (x < y) {
121             return -1;
122         }
123 
124         if (x > y) {
125             return 1;
126         }
127 
128         return 0;
129     }
130 };
131 
132 template <typename T>
133 struct idivides : public std::binary_function<T, T, T> {  // NOLINT(readability-identifier-naming)
operatoridivides134     constexpr T operator()(const T &x, const T &y) const
135     {
136         static_assert(std::is_integral_v<T>, "T should be integral type");
137 
138         // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
139         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
140         if constexpr (std::is_signed_v<T>) {
141             constexpr T MIN = std::numeric_limits<T>::min();
142 
143             if (UNLIKELY(x == MIN && y == -1)) {
144                 return MIN;
145             }
146         }
147 
148         return x / y;
149     }
150 };
151 
152 template <typename T>
153 struct imodulus : public std::binary_function<T, T, T> {  // NOLINT(readability-identifier-naming)
operatorimodulus154     constexpr T operator()(const T &x, const T &y) const
155     {
156         static_assert(std::is_integral_v<T>, "T should be integral type");
157 
158         // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
159         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
160         if constexpr (std::is_signed_v<T>) {
161             constexpr T MIN = std::numeric_limits<T>::min();
162 
163             if (UNLIKELY(x == MIN && y == -1)) {
164                 return 0;
165             }
166         }
167 
168         return x % y;
169     }
170 };
171 
172 template <template <typename OpT> class Op, typename T>
SafeMath(T a,T b)173 ALWAYS_INLINE static inline T SafeMath(T a, T b)
174 {
175     using unsigned_T = std::make_unsigned_t<T>;
176     static_assert(std::is_signed<T>::value, "Expected T to be signed");
177     auto val1 = static_cast<unsigned_T>(a);
178     auto val2 = static_cast<unsigned_T>(b);
179     return static_cast<T>(Op<unsigned_T>()(val1, val2));
180 }
181 
182 template <typename T>
183 struct Plus {
operatorPlus184     ALWAYS_INLINE inline T operator()(T a, T b)
185     {
186         return SafeMath<std::plus>(a, b);
187     }
188 };
189 
190 template <typename T>
191 struct Minus {
operatorMinus192     ALWAYS_INLINE inline T operator()(T a, T b)
193     {
194         return SafeMath<std::minus>(a, b);
195     }
196 };
197 
198 template <typename T>
199 struct Multiplies {
operatorMultiplies200     ALWAYS_INLINE inline T operator()(T a, T b)
201     {
202         return SafeMath<std::multiplies>(a, b);
203     }
204 };
205 
206 template <typename T>
207 struct inc : public std::unary_function<T, T> {  // NOLINT(readability-identifier-naming)
operatorinc208     constexpr T operator()(const T &x) const
209     {
210         return SafeMath<std::plus>(x, 1);
211     }
212 };
213 
214 template <typename T>
215 struct dec : public std::unary_function<T, T> {  // NOLINT(readability-identifier-naming)
operatordec216     constexpr T operator()(const T &x) const
217     {
218         return SafeMath<std::minus>(x, 1);
219     }
220 };
221 
222 }  // namespace panda::interpreter::math_helpers
223 
224 #endif  // PANDA_RUNTIME_INTERPRETER_MATH_HELPERS_H_
225