• 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_LIBPANDABASE_UTILS_ARCH_H_
17 #define PANDA_LIBPANDABASE_UTILS_ARCH_H_
18 
19 #include "macros.h"
20 #include "utils/math_helpers.h"
21 #include "concepts.h"
22 
23 namespace panda {
24 
25 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
26 #define ARCH_LIST(D) \
27     D(NONE)          \
28     D(AARCH32)       \
29     D(AARCH64)       \
30     D(X86)           \
31     D(X86_64)
32 
33 enum class Arch {
34 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
35 #define DEF(v) v,
36     ARCH_LIST(DEF)
37 #undef DEF
38 };
39 
40 template <Arch arch>
41 struct ArchTraits;
42 
43 template <>
44 struct ArchTraits<Arch::AARCH32> {
45     static constexpr size_t CODE_ALIGNMENT = 8;
46     static constexpr size_t INSTRUCTION_ALIGNMENT = 2;
47     static constexpr size_t INSTRUCTION_MAX_SIZE_BITS = 32;
48     static constexpr size_t POINTER_SIZE = 4;
49     static constexpr bool IS_64_BITS = false;
50     static constexpr size_t THREAD_REG = 10;
51     static constexpr size_t CALLER_REG_MASK = 0x0000000f;
52     static constexpr size_t CALLER_FP_REG_MASK = 0x0000ffff;
53     static constexpr size_t CALLEE_REG_MASK = 0x000007f0;
54     static constexpr size_t CALLEE_FP_REG_MASK = 0x0000ff00;
55     static constexpr bool SUPPORT_OSR = false;
56     static constexpr bool SUPPORT_DEOPTIMIZATION = true;
57     using WordType = uint32_t;
58 };
59 
60 template <>
61 struct ArchTraits<Arch::AARCH64> {
62     static constexpr size_t CODE_ALIGNMENT = 16;
63     static constexpr size_t INSTRUCTION_ALIGNMENT = 4;
64     static constexpr size_t INSTRUCTION_MAX_SIZE_BITS = 32;
65     static constexpr size_t POINTER_SIZE = 8;
66     static constexpr bool IS_64_BITS = true;
67     static constexpr size_t THREAD_REG = 28;
68     static constexpr size_t CALLER_REG_MASK = 0x0007ffff;
69     static constexpr size_t CALLER_FP_REG_MASK = 0xffff00ff;
70     static constexpr size_t CALLEE_REG_MASK = 0x1ff80000;
71     static constexpr size_t CALLEE_FP_REG_MASK = 0x0000ff00;
72     static constexpr bool SUPPORT_OSR = true;
73     static constexpr bool SUPPORT_DEOPTIMIZATION = true;
74     using WordType = uint64_t;
75 };
76 
77 template <>
78 struct ArchTraits<Arch::X86> {
79     static constexpr size_t CODE_ALIGNMENT = 16;
80     static constexpr size_t INSTRUCTION_ALIGNMENT = 1;
81     static constexpr size_t INSTRUCTION_MAX_SIZE_BITS = 8;
82     static constexpr size_t POINTER_SIZE = 4;
83     static constexpr bool IS_64_BITS = false;
84     static constexpr size_t THREAD_REG = 0;
85     static constexpr size_t CALLER_REG_MASK = 0x00000000;
86     static constexpr size_t CALLER_FP_REG_MASK = 0x00000000;
87     static constexpr size_t CALLEE_REG_MASK = 0x00000001;
88     static constexpr size_t CALLEE_FP_REG_MASK = 0x00000001;
89     static constexpr bool SUPPORT_OSR = false;
90     static constexpr bool SUPPORT_DEOPTIMIZATION = false;
91     using WordType = uint32_t;
92 };
93 
94 template <>
95 struct ArchTraits<Arch::X86_64> {
96     static constexpr size_t CODE_ALIGNMENT = 16;
97     static constexpr size_t INSTRUCTION_ALIGNMENT = 1;
98     static constexpr size_t INSTRUCTION_MAX_SIZE_BITS = 8;
99     static constexpr size_t POINTER_SIZE = 8;
100     static constexpr bool IS_64_BITS = true;
101     static constexpr size_t THREAD_REG = 15;               // %r15
102     static constexpr size_t CALLER_REG_MASK = 0x000001FF;  // %rax, %rcx, %rdx, %rsi, %rdi, %r8, %r9, %r10, %r11
103     static constexpr size_t CALLER_FP_REG_MASK = 0x0000FFFF;
104     static constexpr size_t CALLEE_REG_MASK = 0x0000F800;  // %rbx, %r12, %r13, %r14, %r15
105     static constexpr size_t CALLEE_FP_REG_MASK = 0x00000000;
106     static constexpr bool SUPPORT_OSR = false;
107     static constexpr bool SUPPORT_DEOPTIMIZATION = true;
108     using WordType = uint64_t;
109 };
110 
111 template <>
112 struct ArchTraits<Arch::NONE> {
113     static constexpr size_t CODE_ALIGNMENT = 0;
114     static constexpr size_t INSTRUCTION_ALIGNMENT = 0;
115     static constexpr size_t INSTRUCTION_MAX_SIZE_BITS = 1;
116     static constexpr size_t POINTER_SIZE = 0;
117     static constexpr bool IS_64_BITS = false;
118     static constexpr size_t CALLEE_REG_MASK = 0x00000000;
119     static constexpr size_t CALLEE_FP_REG_MASK = 0x00000000;
120     using WordType = void;
121 };
122 
123 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage,-warnings-as-errors)
124 #define DEF_ARCH_PROPERTY_GETTER(func_name, property)                                                 \
125     constexpr std::remove_const_t<decltype(ArchTraits<Arch::AARCH64>::property)> func_name(Arch arch) \
126     {                                                                                                 \
127         ASSERT(arch != Arch::NONE);                                                                   \
128         if (arch == Arch::X86) {                                                                      \
129             return ArchTraits<Arch::X86>::property;                                                   \
130         }                                                                                             \
131         if (arch == Arch::X86_64) {                                                                   \
132             return ArchTraits<Arch::X86_64>::property;                                                \
133         }                                                                                             \
134         if (arch == Arch::AARCH32) {                                                                  \
135             return ArchTraits<Arch::AARCH32>::property;                                               \
136         }                                                                                             \
137         if (arch == Arch::AARCH64) {                                                                  \
138             return ArchTraits<Arch::AARCH64>::property;                                               \
139         }                                                                                             \
140         UNREACHABLE();                                                                                \
141     }
142 
143 DEF_ARCH_PROPERTY_GETTER(DoesArchSupportDeoptimization, SUPPORT_DEOPTIMIZATION)
144 DEF_ARCH_PROPERTY_GETTER(GetCodeAlignment, CODE_ALIGNMENT)
145 DEF_ARCH_PROPERTY_GETTER(GetInstructionAlignment, INSTRUCTION_ALIGNMENT)
146 DEF_ARCH_PROPERTY_GETTER(GetInstructionSizeBits, INSTRUCTION_MAX_SIZE_BITS)
147 DEF_ARCH_PROPERTY_GETTER(Is64BitsArch, IS_64_BITS)
148 DEF_ARCH_PROPERTY_GETTER(PointerSize, POINTER_SIZE)
149 DEF_ARCH_PROPERTY_GETTER(GetThreadReg, THREAD_REG)
150 
151 constexpr const char *GetArchString(Arch arch)
152 {
153     switch (arch) {
154 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
155 #define DEF(v)    \
156     case Arch::v: \
157         return #v;
158         ARCH_LIST(DEF)
159 #undef DEF
160         default:
161             UNREACHABLE();
162             return "NONE";
163     }
164 }
165 
166 inline constexpr size_t GetCallerRegsMask(Arch arch, bool is_fp)
167 {
168     switch (arch) {
169         case Arch::AARCH32:
170             return is_fp ? ArchTraits<Arch::AARCH32>::CALLER_FP_REG_MASK : ArchTraits<Arch::AARCH32>::CALLER_REG_MASK;
171         case Arch::AARCH64:
172             return is_fp ? ArchTraits<Arch::AARCH64>::CALLER_FP_REG_MASK : ArchTraits<Arch::AARCH64>::CALLER_REG_MASK;
173         case Arch::X86:
174             return is_fp ? ArchTraits<Arch::X86>::CALLER_FP_REG_MASK : ArchTraits<Arch::X86>::CALLER_REG_MASK;
175         case Arch::X86_64:
176             return is_fp ? ArchTraits<Arch::X86_64>::CALLER_FP_REG_MASK : ArchTraits<Arch::X86_64>::CALLER_REG_MASK;
177         default:
178             UNREACHABLE();
179             return 0;
180     }
181 }
182 
183 inline constexpr size_t GetCalleeRegsMask(Arch arch, bool is_fp)
184 {
185     switch (arch) {
186         case Arch::AARCH32:
187             return is_fp ? ArchTraits<Arch::AARCH32>::CALLEE_FP_REG_MASK : ArchTraits<Arch::AARCH32>::CALLEE_REG_MASK;
188         case Arch::AARCH64:
189             return is_fp ? ArchTraits<Arch::AARCH64>::CALLEE_FP_REG_MASK : ArchTraits<Arch::AARCH64>::CALLEE_REG_MASK;
190         case Arch::X86:
191             return is_fp ? ArchTraits<Arch::X86>::CALLEE_FP_REG_MASK : ArchTraits<Arch::X86>::CALLEE_REG_MASK;
192         case Arch::X86_64:
193             return is_fp ? ArchTraits<Arch::X86_64>::CALLEE_FP_REG_MASK : ArchTraits<Arch::X86_64>::CALLEE_REG_MASK;
194         default:
195             UNREACHABLE();
196             return 0;
197     }
198 }
199 
200 static constexpr size_t LAST_BIT_IN_MASK = 63;
201 
202 inline constexpr size_t GetFirstCalleeReg(Arch arch, bool is_fp)
203 {
204     if (arch == Arch::X86_64 && is_fp) {
205         // in amd64 xmm regs are volatile, so we return first reg (1) > last reg(0) to imitate empty list;
206         // also number of registers = last reg (0) - first reg (1) + 1 == 0
207         return 1;
208     }
209 
210     size_t mask = GetCalleeRegsMask(arch, is_fp);
211     return mask == 0 ? 0 : helpers::math::Ctz(mask);
212 }
213 
214 inline constexpr size_t GetLastCalleeReg(Arch arch, bool is_fp)
215 {
216     if (arch == Arch::X86_64 && is_fp) {
217         return 0;
218     }
219 
220     size_t mask = GetCalleeRegsMask(arch, is_fp);
221     constexpr size_t BIT32 = 32;
222     return BIT32 - 1 - helpers::math::Clz(mask);
223 }
224 
225 inline constexpr size_t GetCalleeRegsCount(Arch arch, bool is_fp)
226 {
227     return (GetLastCalleeReg(arch, is_fp) + 1) - GetFirstCalleeReg(arch, is_fp);
228 }
229 
230 inline constexpr size_t GetFirstCallerReg(Arch arch, bool is_fp)
231 {
232     size_t mask = GetCallerRegsMask(arch, is_fp);
233     return mask == 0 ? 0 : helpers::math::Ctz(mask);
234 }
235 
236 inline constexpr size_t GetLastCallerReg(Arch arch, bool is_fp)
237 {
238     size_t mask = GetCallerRegsMask(arch, is_fp);
239     constexpr size_t BIT32 = 32;
240     return BIT32 - 1 - helpers::math::Clz(mask);
241 }
242 
243 inline constexpr size_t GetCallerRegsCount(Arch arch, bool is_fp)
244 {
245     return GetLastCallerReg(arch, is_fp) - GetFirstCallerReg(arch, is_fp) + 1;
246 }
247 
248 #ifdef PANDA_TARGET_ARM32
249 static constexpr Arch RUNTIME_ARCH = Arch::AARCH32;
250 #elif defined(PANDA_TARGET_ARM64)
251 static constexpr Arch RUNTIME_ARCH = Arch::AARCH64;
252 #elif defined(PANDA_TARGET_X86)
253 static constexpr Arch RUNTIME_ARCH = Arch::X86;
254 #elif defined(PANDA_TARGET_AMD64)
255 static constexpr Arch RUNTIME_ARCH = Arch::X86_64;
256 #else
257 static constexpr Arch RUNTIME_ARCH = Arch::NONE;
258 #endif
259 
260 template <class String = std::string>
261 std::enable_if_t<is_stringable_v<String>, Arch> GetArchFromString(const String &str)
262 {
263     if (str == "arm64") {
264         return Arch::AARCH64;
265     }
266     if (str == "arm") {
267         return Arch::AARCH32;
268     }
269     if (str == "x86") {
270         return Arch::X86;
271     }
272     if (str == "x86_64") {
273         return Arch::X86_64;
274     }
275     return Arch::NONE;
276 }
277 
278 template <class String = std::string>
279 std::enable_if_t<is_stringable_v<String>, String> GetStringFromArch(const Arch &arch)
280 {
281     if (arch == Arch::AARCH64) {
282         return "arm64";
283     }
284     if (arch == Arch::AARCH32) {
285         return "arm";
286     }
287     if (arch == Arch::X86) {
288         return "x86";
289     }
290     if (arch == Arch::X86_64) {
291         return "x86_64";
292     }
293     return "none";
294 }
295 
296 }  // namespace panda
297 
298 #endif  // PANDA_LIBPANDABASE_UTILS_ARCH_H_
299