• 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_ARCH_HELPERS_H_
17 #define PANDA_RUNTIME_ARCH_HELPERS_H_
18 
19 #include "libpandabase/utils/arch.h"
20 #include "libpandabase/utils/bit_utils.h"
21 #include "libpandabase/utils/span.h"
22 
23 namespace panda::arch {
24 
25 template <Arch A>
26 struct ExtArchTraits;
27 
28 #if !defined(PANDA_TARGET_ARM32_ABI_HARD)
29 template <>
30 struct ExtArchTraits<Arch::AARCH32> {
31     using signed_word_type = int32_t;
32     using unsigned_word_type = uint32_t;
33 
34     static constexpr size_t NUM_GP_ARG_REGS = 4;
35     static constexpr size_t GP_ARG_NUM_BYTES = NUM_GP_ARG_REGS * ArchTraits<Arch::AARCH32>::POINTER_SIZE;
36     static constexpr size_t NUM_FP_ARG_REGS = 0;
37     static constexpr size_t FP_ARG_NUM_BYTES = NUM_FP_ARG_REGS * ArchTraits<Arch::AARCH32>::POINTER_SIZE;
38     static constexpr size_t GPR_SIZE = ArchTraits<Arch::AARCH32>::POINTER_SIZE;
39     static constexpr size_t FPR_SIZE = 0;
40     static constexpr bool HARDFP = false;
41 };
42 #else   // !defined(PANDA_TARGET_ARM32_ABI_HARD)
43 template <>
44 struct ExtArchTraits<Arch::AARCH32> {
45     using signed_word_type = int32_t;
46     using unsigned_word_type = uint32_t;
47 
48     static constexpr size_t NUM_GP_ARG_REGS = 4;
49     static constexpr size_t GP_ARG_NUM_BYTES = NUM_GP_ARG_REGS * ArchTraits<Arch::AARCH32>::POINTER_SIZE;
50     static constexpr size_t NUM_FP_ARG_REGS = 16; /* s0 - s15 */
51     static constexpr size_t FP_ARG_NUM_BYTES = NUM_FP_ARG_REGS * ArchTraits<Arch::AARCH32>::POINTER_SIZE;
52     static constexpr size_t GPR_SIZE = ArchTraits<Arch::AARCH32>::POINTER_SIZE;
53     static constexpr size_t FPR_SIZE = ArchTraits<Arch::AARCH32>::POINTER_SIZE;
54     static constexpr bool HARDFP = true;
55 };
56 #endif  // !defined(PANDA_TARGET_ARM32_ABI_HARD)
57 
58 template <>
59 struct ExtArchTraits<Arch::AARCH64> {
60     using signed_word_type = int64_t;
61     using unsigned_word_type = uint64_t;
62 
63     static constexpr size_t NUM_GP_ARG_REGS = 8;
64     static constexpr size_t GP_ARG_NUM_BYTES = NUM_GP_ARG_REGS * ArchTraits<Arch::AARCH64>::POINTER_SIZE;
65     static constexpr size_t NUM_FP_ARG_REGS = 8;
66     static constexpr size_t FP_ARG_NUM_BYTES = NUM_FP_ARG_REGS * ArchTraits<Arch::AARCH64>::POINTER_SIZE;
67     static constexpr size_t GPR_SIZE = ArchTraits<Arch::AARCH64>::POINTER_SIZE;
68     static constexpr size_t FPR_SIZE = ArchTraits<Arch::AARCH64>::POINTER_SIZE;
69     static constexpr bool HARDFP = true;
70 };
71 
72 template <>
73 struct ExtArchTraits<Arch::X86_64> {
74     using signed_word_type = int64_t;
75     using unsigned_word_type = uint64_t;
76 
77     static constexpr size_t NUM_GP_ARG_REGS = 6;
78     static constexpr size_t GP_ARG_NUM_BYTES = NUM_GP_ARG_REGS * ArchTraits<Arch::X86_64>::POINTER_SIZE;
79     static constexpr size_t NUM_FP_ARG_REGS = 8;
80     static constexpr size_t FP_ARG_NUM_BYTES = NUM_FP_ARG_REGS * ArchTraits<Arch::X86_64>::POINTER_SIZE;
81     static constexpr size_t GPR_SIZE = ArchTraits<Arch::X86_64>::POINTER_SIZE;
82     static constexpr size_t FPR_SIZE = ArchTraits<Arch::X86_64>::POINTER_SIZE;
83     static constexpr bool HARDFP = true;
84 };
85 
86 template <class T>
87 inline uint8_t *AlignPtr(uint8_t *ptr)
88 {
89     return reinterpret_cast<uint8_t *>(RoundUp(reinterpret_cast<uintptr_t>(ptr), sizeof(T)));
90 }
91 
92 template <class T>
93 inline const uint8_t *AlignPtr(const uint8_t *ptr)
94 {
95     return reinterpret_cast<const uint8_t *>(RoundUp(reinterpret_cast<uintptr_t>(ptr), sizeof(T)));
96 }
97 
98 template <Arch A>
99 class ArgCounter {
100 public:
101     template <class T>
102     void Count()
103     {
104         constexpr size_t PTR_SIZE = ArchTraits<A>::POINTER_SIZE;
105         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
106         if constexpr (std::is_same<T, float>::value || std::is_same<T, double>::value) {
107             // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
108             if constexpr (ExtArchTraits<A>::HARDFP) {
109                 size_t num_bytes = std::max(sizeof(T), ExtArchTraits<A>::FPR_SIZE);
110                 fpr_arg_size_ = RoundUp(fpr_arg_size_, num_bytes);
111                 if (fpr_arg_size_ < ExtArchTraits<A>::FP_ARG_NUM_BYTES) {
112                     fpr_arg_size_ += num_bytes;
113                 } else {
114                     stack_size_ = RoundUp(stack_size_, num_bytes);
115                     stack_size_ += num_bytes;
116                 }
117                 return;
118             }
119         }
120 
121         size_t num_bytes = std::max(sizeof(T), PTR_SIZE);
122         gpr_arg_size_ = RoundUp(gpr_arg_size_, num_bytes);
123         if (gpr_arg_size_ < ExtArchTraits<A>::GP_ARG_NUM_BYTES) {
124             gpr_arg_size_ += num_bytes;
125         } else {
126             stack_size_ = RoundUp(stack_size_, num_bytes);
127             stack_size_ += num_bytes;
128         }
129     }
130 
131     size_t GetStackSize() const
132     {
133         return GetStackSpaceSize() / ArchTraits<A>::POINTER_SIZE;
134     }
135 
136     size_t GetStackSpaceSize() const
137     {
138         return RoundUp(ExtArchTraits<A>::FP_ARG_NUM_BYTES + ExtArchTraits<A>::GP_ARG_NUM_BYTES + stack_size_,
139                        2 * ArchTraits<A>::POINTER_SIZE);
140     }
141 
142 private:
143     size_t gpr_arg_size_ = 0;
144     size_t fpr_arg_size_ = 0;
145     size_t stack_size_ = 0;
146 };
147 
148 template <Arch A>
149 class ArgReader {
150 public:
151     ArgReader(const Span<uint8_t> &gpr_args, const Span<uint8_t> &fpr_args, const uint8_t *stack_args)
152         : gpr_args_(gpr_args), fpr_args_(fpr_args), stack_args_(stack_args)
153     {
154     }
155 
156     template <class T>
157     T Read()
158     {
159         return *ReadPtr<T>();
160     }
161 
162     template <class T>
163     const T *ReadPtr()
164     {
165         constexpr size_t PTR_SIZE = ArchTraits<A>::POINTER_SIZE;
166         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
167         if constexpr (std::is_same<T, double>::value || std::is_same<T, float>::value) {
168             // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
169             if constexpr (ExtArchTraits<A>::HARDFP) {
170                 const T *v;
171                 size_t read_bytes = std::max(sizeof(T), ExtArchTraits<A>::FPR_SIZE);
172                 fp_arg_bytes_read_ = RoundUp(fp_arg_bytes_read_, read_bytes);
173                 if (fp_arg_bytes_read_ < ExtArchTraits<A>::FP_ARG_NUM_BYTES) {
174                     v = reinterpret_cast<const T *>(fpr_args_.data() + fp_arg_bytes_read_);
175                     fp_arg_bytes_read_ += read_bytes;
176                 } else {
177                     stack_args_ = AlignPtr<T>(stack_args_);
178                     v = reinterpret_cast<const T *>(stack_args_);
179                     stack_args_ += read_bytes;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
180                 }
181                 return v;
182             }
183         }
184         size_t read_bytes = std::max(sizeof(T), PTR_SIZE);
185         gp_arg_bytes_read_ = RoundUp(gp_arg_bytes_read_, read_bytes);
186         const T *v;
187         if (gp_arg_bytes_read_ < ExtArchTraits<A>::GP_ARG_NUM_BYTES) {
188             v = reinterpret_cast<const T *>(gpr_args_.data() + gp_arg_bytes_read_);
189             gp_arg_bytes_read_ += read_bytes;
190         } else {
191             stack_args_ = AlignPtr<T>(stack_args_);
192             v = reinterpret_cast<const T *>(stack_args_);
193             stack_args_ += read_bytes;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
194         }
195         return v;
196     }
197 
198 private:
199     const Span<uint8_t> &gpr_args_;
200     const Span<uint8_t> &fpr_args_;
201     const uint8_t *stack_args_;
202     size_t gp_arg_bytes_read_ = 0;
203     size_t fp_arg_bytes_read_ = 0;
204 };
205 
206 template <Arch A>
207 class ArgWriter {
208 public:
209     ArgWriter(Span<uint8_t> *gpr_args, Span<uint8_t> *fpr_args, uint8_t *stack_args)
210         : gpr_args_(gpr_args), fpr_args_(fpr_args), stack_args_(stack_args)
211     {
212     }
213 
214     template <class T>
215     void Write(T v)
216     {
217         constexpr size_t PTR_SIZE = ArchTraits<A>::POINTER_SIZE;
218         size_t write_bytes = std::max(sizeof(T), PTR_SIZE);
219         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
220         if constexpr (std::is_same<T, float>::value || std::is_same<T, double>::value) {
221             // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
222             if constexpr (ExtArchTraits<A>::HARDFP) {
223                 size_t num_bytes = std::max(sizeof(T), ExtArchTraits<A>::FPR_SIZE);
224                 if (fp_arg_bytes_written_ < ExtArchTraits<A>::FP_ARG_NUM_BYTES) {
225                     *reinterpret_cast<T *>(fpr_args_->data() + fp_arg_bytes_written_) = v;
226                     fp_arg_bytes_written_ += num_bytes;
227                 } else {
228                     stack_args_ = AlignPtr<T>(stack_args_);
229                     *reinterpret_cast<T *>(stack_args_) = v;
230                     stack_args_ += write_bytes;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
231                 }
232                 return;
233             }
234         }
235         gp_arg_bytes_written_ = RoundUp(gp_arg_bytes_written_, write_bytes);
236         if (gp_arg_bytes_written_ < ExtArchTraits<A>::GP_ARG_NUM_BYTES) {
237             // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
238             if constexpr (std::is_integral<T>::value && sizeof(T) < PTR_SIZE) {
239                 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
240                 if constexpr (std::is_signed<T>::value) {
241                     *reinterpret_cast<typename ExtArchTraits<A>::signed_word_type *>(gpr_args_->data() +
242                                                                                      gp_arg_bytes_written_) = v;
243                 } else {  // NOLINT(readability-misleading-indentation)
244                     *reinterpret_cast<typename ExtArchTraits<A>::unsigned_word_type *>(gpr_args_->data() +
245                                                                                        gp_arg_bytes_written_) = v;
246                 }
247             } else {  // NOLINT(readability-misleading-indentation)
248                 *reinterpret_cast<T *>(gpr_args_->data() + gp_arg_bytes_written_) = v;
249             }
250             gp_arg_bytes_written_ += write_bytes;
251         } else {
252             stack_args_ = AlignPtr<T>(stack_args_);
253             *reinterpret_cast<T *>(stack_args_) = v;
254             stack_args_ += write_bytes;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
255         }
256     }
257 
258 private:
259     Span<uint8_t> *gpr_args_;
260     Span<uint8_t> *fpr_args_;
261     uint8_t *stack_args_;
262     size_t gp_arg_bytes_written_ = 0;
263     size_t fp_arg_bytes_written_ = 0;
264 };
265 
266 // This class is required due to specific calling conventions in AARCH32
267 template <>
268 class ArgWriter<Arch::AARCH32> {
269 public:
270     ArgWriter(Span<uint8_t> *gpr_args, Span<uint8_t> *fpr_args, uint8_t *stack_args)
271         : gpr_args_(gpr_args), fpr_args_(fpr_args), stack_args_(stack_args)
272     {
273     }
274 
275     template <class T>
276     void Write(T v)  // CODECHECK-NOLINT(C_RULE_ID_FUNCTION_SIZE)
277     {
278         constexpr size_t PTR_SIZE = ArchTraits<Arch::AARCH32>::POINTER_SIZE;
279         size_t write_bytes = std::max(sizeof(T), PTR_SIZE);
280         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
281         if constexpr (std::is_same<T, float>::value || std::is_same<T, double>::value) {
282             // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
283             if constexpr (ExtArchTraits<Arch::AARCH32>::HARDFP) {
284                 size_t num_bytes = std::max(sizeof(T), ExtArchTraits<Arch::AARCH32>::FPR_SIZE);
285 
286                 if (fp_arg_bytes_written_ < ExtArchTraits<Arch::AARCH32>::FP_ARG_NUM_BYTES &&
287                     (std::is_same<T, float>::value ||
288                      (fp_arg_bytes_written_ < ExtArchTraits<Arch::AARCH32>::FP_ARG_NUM_BYTES - sizeof(float))) &&
289                     !is_float_arm_stack_has_been_written_) {
290                     // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_NESTING_LEVEL)
291                     if (std::is_same<T, float>::value) {
292                         if (half_empty_register_offset_ == 0) {
293                             half_empty_register_offset_ = fp_arg_bytes_written_ + sizeof(float);
294                             *reinterpret_cast<T *>(fpr_args_->data() + fp_arg_bytes_written_) = v;
295                             fp_arg_bytes_written_ += num_bytes;
296                         } else {
297                             *reinterpret_cast<T *>(fpr_args_->data() + half_empty_register_offset_) = v;
298                             if (half_empty_register_offset_ == fp_arg_bytes_written_) {
299                                 fp_arg_bytes_written_ += num_bytes;
300                             }
301                             half_empty_register_offset_ = 0;
302                         }
303                     } else {
304                         fp_arg_bytes_written_ = RoundUp(fp_arg_bytes_written_, sizeof(T));
305                         *reinterpret_cast<T *>(fpr_args_->data() + fp_arg_bytes_written_) = v;
306                         fp_arg_bytes_written_ += num_bytes;
307                     }
308                 } else {
309                     is_float_arm_stack_has_been_written_ = true;
310                     stack_args_ = AlignPtr<T>(stack_args_);
311                     *reinterpret_cast<T *>(stack_args_) = v;
312                     stack_args_ += write_bytes;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
313                 }
314                 return;
315             }
316         }
317         gp_arg_bytes_written_ = RoundUp(gp_arg_bytes_written_, write_bytes);
318         if (gp_arg_bytes_written_ < ExtArchTraits<Arch::AARCH32>::GP_ARG_NUM_BYTES) {
319             // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
320             if constexpr (std::is_integral<T>::value && sizeof(T) < PTR_SIZE) {
321                 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
322                 if constexpr (std::is_signed<T>::value) {
323                     *reinterpret_cast<typename ExtArchTraits<Arch::AARCH32>::signed_word_type *>(
324                         gpr_args_->data() + gp_arg_bytes_written_) = v;
325                 } else {  // NOLINT(readability-misleading-indentation)
326                     *reinterpret_cast<typename ExtArchTraits<Arch::AARCH32>::unsigned_word_type *>(
327                         gpr_args_->data() + gp_arg_bytes_written_) = v;
328                 }
329             } else {  // NOLINT(readability-misleading-indentation)
330                 *reinterpret_cast<T *>(gpr_args_->data() + gp_arg_bytes_written_) = v;
331             }
332             gp_arg_bytes_written_ += write_bytes;
333         } else {
334             stack_args_ = AlignPtr<T>(stack_args_);
335             *reinterpret_cast<T *>(stack_args_) = v;
336             stack_args_ += write_bytes;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
337         }
338     }
339 
340 private:
341     Span<uint8_t> *gpr_args_;
342     Span<uint8_t> *fpr_args_;
343     uint8_t *stack_args_;
344     size_t gp_arg_bytes_written_ = 0;
345     size_t fp_arg_bytes_written_ = 0;
346     size_t half_empty_register_offset_ = 0;
347     bool is_float_arm_stack_has_been_written_ = false;
348 };
349 
350 }  // namespace panda::arch
351 
352 #endif  // PANDA_RUNTIME_ARCH_HELPERS_H_
353