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