• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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