1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef BERBERIS_GUEST_ABI_GUEST_ABI_ARCH_H_ 18 #define BERBERIS_GUEST_ABI_GUEST_ABI_ARCH_H_ 19 20 #include <array> 21 22 #include "berberis/guest_abi/guest_type.h" 23 24 namespace berberis { 25 26 class GuestAbi { 27 public: 28 // Currently we only support one calling covention for ARM64 but ARM have two and we may need to 29 // support more than one in the future. 30 enum CallingConventionsVariant { kAapcs64, kDefaultAbi = kAapcs64 }; 31 32 protected: 33 enum class ArgumentClass { kInteger, kVFP, kLargeStructType }; 34 35 template <typename Type, typename = void> 36 struct GuestArgumentInfo; 37 38 template <typename IntegerType> 39 struct GuestArgumentInfo<IntegerType, std::enable_if_t<std::is_integral_v<IntegerType>>> { 40 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kInteger; 41 constexpr static unsigned kSize = sizeof(IntegerType); 42 // Use sizeof, not alignof for kAlignment because all integer types are naturally aligned on 43 // ARM, which is not guaranteed to be true for host. 44 constexpr static unsigned kAlignment = sizeof(IntegerType); 45 using GuestType = GuestType<IntegerType>; 46 using HostType = IntegerType; 47 }; 48 49 template <typename EnumType> 50 struct GuestArgumentInfo<EnumType, std::enable_if_t<std::is_enum_v<EnumType>>> 51 : GuestArgumentInfo<std::underlying_type_t<EnumType>> { 52 using GuestType = GuestType<EnumType>; 53 using HostType = EnumType; 54 }; 55 56 template <typename PointeeType> 57 struct GuestArgumentInfo<PointeeType*> { 58 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kInteger; 59 constexpr static unsigned kSize = 8; 60 constexpr static unsigned kAlignment = 8; 61 using GuestType = GuestType<PointeeType*>; 62 using HostType = PointeeType*; 63 }; 64 65 template <typename ResultType, typename... ArgumentType> 66 struct GuestArgumentInfo<ResultType (*)(ArgumentType...)> { 67 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kInteger; 68 constexpr static unsigned kSize = 8; 69 constexpr static unsigned kAlignment = 8; 70 using GuestType = GuestType<ResultType (*)(ArgumentType...)>; 71 using HostType = ResultType (*)(ArgumentType...); 72 }; 73 74 template <> 75 struct GuestArgumentInfo<float> { 76 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kVFP; 77 constexpr static unsigned kSize = 4; 78 constexpr static unsigned kAlignment = 4; 79 // using GuestType = intrinsics::Float32; 80 using GuestType = GuestType<float>; 81 // using HostType = intrinsics::Float32; 82 using HostType = float; 83 }; 84 85 template <> 86 struct GuestArgumentInfo<double> { 87 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kVFP; 88 constexpr static unsigned kSize = 8; 89 constexpr static unsigned kAlignment = 8; 90 // using GuestType = intrinsics::Float64; 91 using GuestType = GuestType<double>; 92 // using HostType = intrinsics::Float64; 93 using HostType = double; 94 }; 95 96 template <typename LargeStructType> 97 struct GuestArgumentInfo< 98 LargeStructType, 99 std::enable_if_t<std::is_class_v<LargeStructType> && (sizeof(LargeStructType) > 16)>> { 100 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kLargeStructType; 101 // Note: when large structure is passed or returned it's kept in memory aalocated by caller 102 // and pointer to it is passed instead. We are describing that pointer below. 103 constexpr static unsigned kSize = 8; 104 constexpr static unsigned kAlignment = 8; 105 // Note: despite the fact that we have pointer to structure passed, but actual structure we 106 // keep information about underlying structure type here. 107 // This is for passing structure as a function argument: we have to make it const to makes sure 108 // it wouldn't be changed by accident and it's easier to do with this declaration. 109 using GuestType = GuestType<LargeStructType>; 110 using HostType = LargeStructType; 111 }; 112 }; 113 114 } // namespace berberis 115 116 #endif // BERBERIS_GUEST_ABI_GUEST_ABI_ARCH_H_ 117