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