• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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 ark::interpreter::math_helpers {
26 
27 template <typename T>
28 struct bit_shl {  // NOLINT(readability-identifier-naming)
operatorbit_shl29     constexpr T operator()(const T &x, const T &y) const
30     {
31         using UnsignedType = std::make_unsigned_t<T>;
32         size_t mask = std::numeric_limits<UnsignedType>::digits - 1;
33         size_t shift = static_cast<UnsignedType>(y) & mask;
34         return static_cast<T>(static_cast<UnsignedType>(x) << shift);
35     }
36 };
37 
38 template <typename T>
39 struct bit_shr {  // NOLINT(readability-identifier-naming)
operatorbit_shr40     constexpr T operator()(const T &x, const T &y) const
41     {
42         using UnsignedType = std::make_unsigned_t<T>;
43         size_t mask = std::numeric_limits<UnsignedType>::digits - 1;
44         size_t shift = static_cast<UnsignedType>(y) & mask;
45         return static_cast<T>(static_cast<UnsignedType>(x) >> shift);
46     }
47 };
48 
49 template <typename T>
50 struct bit_ashr {  // NOLINT(readability-identifier-naming)
operatorbit_ashr51     constexpr T operator()(const T &x, const T &y) const
52     {
53         using UnsignedType = std::make_unsigned_t<T>;
54         size_t mask = std::numeric_limits<UnsignedType>::digits - 1;
55         size_t shift = static_cast<UnsignedType>(y) & mask;
56         return x >> shift;  // NOLINT(hicpp-signed-bitwise)
57     }
58 };
59 
60 template <typename T>
61 struct fmodulus {  // 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 {  // 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 {  // 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 {  // 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 {  // 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             if (UNLIKELY(x == MIN && y == -1)) {
134                 return MIN;
135             }
136         }
137 
138         return x / y;
139     }
140 };
141 
142 template <typename T>
143 struct imodulus {  // NOLINT(readability-identifier-naming)
operatorimodulus144     constexpr T operator()(const T &x, const T &y) const
145     {
146         static_assert(std::is_integral_v<T>, "T should be integral type");
147 
148         // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
149         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
150         if constexpr (std::is_signed_v<T>) {
151             constexpr T MIN = std::numeric_limits<T>::min();
152             if (UNLIKELY(x == MIN && y == -1)) {
153                 return 0;
154             }
155         }
156 
157         return x % y;
158     }
159 };
160 
161 template <template <typename OpT> class Op, typename T>
SafeMath(T a,T b)162 ALWAYS_INLINE static inline T SafeMath(T a, T b)
163 {
164     using UnsignedT = std::make_unsigned_t<T>;
165     static_assert(std::is_signed<T>::value, "Expected T to be signed");
166     auto val1 = static_cast<UnsignedT>(a);
167     auto val2 = static_cast<UnsignedT>(b);
168     return static_cast<T>(Op<UnsignedT>()(val1, val2));
169 }
170 
171 template <typename T>
172 struct Plus {
operatorPlus173     ALWAYS_INLINE inline T operator()(T a, T b)
174     {
175         return SafeMath<std::plus>(a, b);
176     }
177 };
178 
179 template <typename T>
180 struct Minus {
operatorMinus181     ALWAYS_INLINE inline T operator()(T a, T b)
182     {
183         return SafeMath<std::minus>(a, b);
184     }
185 };
186 
187 template <typename T>
188 struct Multiplies {
operatorMultiplies189     ALWAYS_INLINE inline T operator()(T a, T b)
190     {
191         return SafeMath<std::multiplies>(a, b);
192     }
193 };
194 
195 template <typename T>
196 struct inc {  // NOLINT(readability-identifier-naming)
operatorinc197     constexpr T operator()(const T &x) const
198     {
199         return SafeMath<std::plus>(x, 1);
200     }
201 };
202 
203 template <typename T>
204 struct dec {  // NOLINT(readability-identifier-naming)
operatordec205     constexpr T operator()(const T &x) const
206     {
207         return SafeMath<std::minus>(x, 1);
208     }
209 };
210 
211 }  // namespace ark::interpreter::math_helpers
212 
213 #endif  // PANDA_INTERPRETER_FRAME_H_
214