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 enum CallingConventionsVariant { kAapcs, kAapcsVfp, kDefaultAbi = kAapcs }; 29 30 protected: 31 enum class ArgumentClass { kInteger, kVFP, kReturnedViaIndirectPointer }; 32 33 template <typename Type, CallingConventionsVariant = kDefaultAbi, typename = void> 34 struct GuestArgumentInfo; 35 36 template <typename IntegerType, CallingConventionsVariant kCallingConventionsVarіant> 37 struct GuestArgumentInfo< 38 IntegerType, 39 kCallingConventionsVarіant, 40 std::enable_if_t<std::is_integral_v<IntegerType> && std::is_signed_v<IntegerType> && 41 sizeof(IntegerType) < 4>> { 42 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kInteger; 43 constexpr static unsigned kSize = sizeof(IntegerType); 44 // Use sizeof, not alignof for kAlignment because all integer types are naturally aligned on 45 // ARM, which is not guaranteed to be true for host. 46 constexpr static unsigned kAlignment = sizeof(IntegerType); 47 using GuestType = GuestType<int32_t>; 48 using HostType = int32_t; 49 }; 50 51 template <typename IntegerType, CallingConventionsVariant kCallingConventionsVarіant> 52 struct GuestArgumentInfo< 53 IntegerType, 54 kCallingConventionsVarіant, 55 std::enable_if_t<std::is_integral_v<IntegerType> && !std::is_signed_v<IntegerType> && 56 sizeof(IntegerType) < 4>> { 57 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kInteger; 58 constexpr static unsigned kSize = sizeof(IntegerType); 59 // Use sizeof, not alignof for kAlignment because all integer types are naturally aligned on 60 // ARM, which is not guaranteed to be true for host. 61 constexpr static unsigned kAlignment = sizeof(IntegerType); 62 using GuestType = GuestType<uint32_t>; 63 using HostType = uint32_t; 64 }; 65 66 template <typename IntegerType, CallingConventionsVariant kCallingConventionsVarіant> 67 struct GuestArgumentInfo< 68 IntegerType, 69 kCallingConventionsVarіant, 70 std::enable_if_t<std::is_integral_v<IntegerType> && sizeof(IntegerType) >= 4>> { 71 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kInteger; 72 constexpr static unsigned kSize = sizeof(IntegerType); 73 // Use sizeof, not alignof for kAlignment because all integer types are naturally aligned on 74 // ARM, which is not guaranteed to be true for host. 75 constexpr static unsigned kAlignment = sizeof(IntegerType); 76 using GuestType = GuestType<IntegerType>; 77 using HostType = IntegerType; 78 }; 79 80 template <typename EnumType, CallingConventionsVariant kCallingConventionsVarіant> 81 struct GuestArgumentInfo<EnumType, 82 kCallingConventionsVarіant, 83 std::enable_if_t<std::is_enum_v<EnumType>>> 84 : GuestArgumentInfo<std::underlying_type_t<EnumType>, kCallingConventionsVarіant> { 85 using GuestType = GuestType<EnumType>; 86 using HostType = EnumType; 87 }; 88 89 template <typename PointeeType, CallingConventionsVariant kCallingConventionsVarіant> 90 struct GuestArgumentInfo<PointeeType*, kCallingConventionsVarіant> { 91 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kInteger; 92 constexpr static unsigned kSize = 4; 93 constexpr static unsigned kAlignment = 4; 94 using GuestType = GuestType<PointeeType*>; 95 using HostType = PointeeType*; 96 }; 97 98 template <typename ResultType, 99 typename... ArgumentType, 100 CallingConventionsVariant kCallingConventionsVarіant> 101 struct GuestArgumentInfo<ResultType (*)(ArgumentType...), kCallingConventionsVarіant> { 102 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kInteger; 103 constexpr static unsigned kSize = 4; 104 constexpr static unsigned kAlignment = 4; 105 using GuestType = GuestType<ResultType (*)(ArgumentType...)>; 106 using HostType = ResultType (*)(ArgumentType...); 107 }; 108 109 template <> 110 struct GuestArgumentInfo<float, CallingConventionsVariant::kAapcs> { 111 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kInteger; 112 constexpr static unsigned kSize = 4; 113 constexpr static unsigned kAlignment = 4; 114 // using GuestType = intrinsics::Float32; 115 using GuestType = GuestType<float>; 116 // using HostType = intrinsics::Float32; 117 using HostType = float; 118 }; 119 120 template <> 121 struct GuestArgumentInfo<float, CallingConventionsVariant::kAapcsVfp> 122 : GuestArgumentInfo<float, CallingConventionsVariant::kAapcs> { 123 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kVFP; 124 }; 125 126 template <> 127 struct GuestArgumentInfo<double, CallingConventionsVariant::kAapcs> { 128 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kInteger; 129 constexpr static unsigned kSize = 8; 130 constexpr static unsigned kAlignment = 8; 131 constexpr static bool fp_argument = false; 132 // using GuestType = intrinsics::Float64; 133 using GuestType = GuestType<double>; 134 // using HostType = intrinsics::Float64; 135 using HostType = double; 136 }; 137 138 template <> 139 struct GuestArgumentInfo<double, CallingConventionsVariant::kAapcsVfp> 140 : GuestArgumentInfo<double, CallingConventionsVariant::kAapcs> { 141 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kVFP; 142 }; 143 144 template <typename LargeStructType, CallingConventionsVariant kCallingConventionsVarіant> 145 struct GuestArgumentInfo< 146 LargeStructType, 147 kCallingConventionsVarіant, 148 std::enable_if_t<std::is_class_v<LargeStructType> && (sizeof(LargeStructType) > 4)>> { 149 // Note: this is a kludge for now. When large structures are returned from function they are 150 // passed via hidden first argument. But when they are passed into function rules are quite 151 // complicated — we don't support them yet. 152 // 153 // Attempt to use it as an argument of function would cause compile-time error thus we can be 154 // sure this wouldn't affect us without us knowing it happened. 155 // 156 // Currently this class doesn't provide kSize and kAlignment members which means compilation 157 // error would happen during construction of kArgumentsInfo array in the ArgumentsInfoHelper. 158 // 159 // If, in the future, such members would be added then another error would be detected during 160 // processing of that array since ArgumentsInfoHelper explicitly parses all the possible values 161 // of kArgumentClass which is can process. 162 constexpr static ArgumentClass kArgumentClass = ArgumentClass::kReturnedViaIndirectPointer; 163 using GuestType = GuestType<LargeStructType>; 164 using HostType = LargeStructType; 165 }; 166 }; 167 168 } // namespace berberis 169 170 #endif // BERBERIS_GUEST_ABI_GUEST_ABI_ARCH_H_ 171