• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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_ARCH_H
17 #define PANDA_ARCH_H
18 
19 #include "macros.h"
20 #include "utils/math_helpers.h"
21 #include "utils/regmask.h"
22 #include "concepts.h"
23 
24 namespace ark {
25 
26 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
27 #define ARCH_LIST(D) \
28     D(NONE)          \
29     D(AARCH32)       \
30     D(AARCH64)       \
31     D(X86)           \
32     D(X86_64)
33 
34 enum class Arch {
35 // CC-OFFNXT(G.PRE.02) part name
36 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
37 #define DEF(v) v,
38     ARCH_LIST(DEF)
39 #undef DEF
40 };
41 
42 template <Arch ARCH>
43 struct ArchTraits;
44 
45 template <>
46 struct ArchTraits<Arch::AARCH32> {
47     static constexpr size_t CODE_ALIGNMENT = 8;
48     static constexpr size_t INSTRUCTION_ALIGNMENT = 4;
49     static constexpr size_t INSTRUCTION_MAX_SIZE_BITS = 32;
50     static constexpr size_t POINTER_SIZE = 4;
51     static constexpr bool IS_64_BITS = false;
52     static constexpr size_t THREAD_REG = 10;
53     static constexpr size_t CALLER_REG_MASK = 0x0000000f;
54     static constexpr size_t CALLER_FP_REG_MASK = 0x0000ffff;  // s0-s15 or d0-d7
55     static constexpr size_t CALLEE_REG_MASK = 0x000007f0;
56     static constexpr size_t CALLEE_FP_REG_MASK = 0xffff0000;  // s16-s31 or d8-d15
57     static constexpr bool SUPPORT_OSR = false;
58     static constexpr bool SUPPORT_DEOPTIMIZATION = true;
59     static constexpr const char *ISA_NAME = "arm";
60     static constexpr size_t DWARF_SP = 13;
61     static constexpr size_t DWARF_RIP = 15;
62     static constexpr size_t DWARF_FP = 11;
63     static constexpr size_t DWARF_LR = 14;
64     using WordType = uint32_t;
65 };
66 
67 inline constexpr size_t ChooseIrtocOptimizedFpRegmask()
68 {
69     constexpr size_t DEFAULT_FP_REGMASK = 0x00000100;
70     size_t regmask = DEFAULT_FP_REGMASK;
71 #include "plugins_regmasks.inl"
72     return regmask;
73 }
74 
75 template <>
76 struct ArchTraits<Arch::AARCH64> {
77     static constexpr size_t CODE_ALIGNMENT = 16;
78     static constexpr size_t INSTRUCTION_ALIGNMENT = 4;
79     static constexpr size_t INSTRUCTION_MAX_SIZE_BITS = 32;
80     static constexpr size_t POINTER_SIZE = 8;
81     static constexpr bool IS_64_BITS = true;
82     static constexpr size_t THREAD_REG = 28;
83     static constexpr size_t CALLER_REG_MASK = 0x0007ffff;
84     static constexpr size_t CALLER_FP_REG_MASK = 0xffff00ff;
85     static constexpr size_t CALLEE_REG_MASK = 0x1ff80000;
86     static constexpr size_t CALLEE_FP_REG_MASK = 0x0000ff00;
87     static constexpr size_t IRTOC_OPTIMIZED_CALLEE_REG_MASK = 0x1ff80000;
88     static constexpr size_t IRTOC_OPTIMIZED_CALLEE_FP_REG_MASK = ChooseIrtocOptimizedFpRegmask();
89     static constexpr bool SUPPORT_OSR = true;
90     static constexpr bool SUPPORT_DEOPTIMIZATION = true;
91     static constexpr const char *ISA_NAME = "arm64";
92     static constexpr size_t DWARF_SP = 31;
93     static constexpr size_t DWARF_RIP = 32;
94     static constexpr size_t DWARF_FP = 29;
95     static constexpr size_t DWARF_LR = 30;
96     using WordType = uint64_t;
97 };
98 
99 template <>
100 struct ArchTraits<Arch::X86> {
101     static constexpr size_t CODE_ALIGNMENT = 16;
102     static constexpr size_t INSTRUCTION_ALIGNMENT = 1;
103     static constexpr size_t INSTRUCTION_MAX_SIZE_BITS = 8;
104     static constexpr size_t POINTER_SIZE = 4;
105     static constexpr bool IS_64_BITS = false;
106     static constexpr size_t THREAD_REG = 0;
107     static constexpr size_t CALLER_REG_MASK = 0x00000000;
108     static constexpr size_t CALLER_FP_REG_MASK = 0x00000000;
109     static constexpr size_t CALLEE_REG_MASK = 0x00000001;
110     static constexpr size_t CALLEE_FP_REG_MASK =
111         0x00000001;  // NOTE(msherstennikov): fill once x86 codegen is supported
112     static constexpr bool SUPPORT_OSR = false;
113     static constexpr bool SUPPORT_DEOPTIMIZATION = false;
114     static constexpr const char *ISA_NAME = "x86";
115     static constexpr size_t DWARF_SP = 0;
116     static constexpr size_t DWARF_RIP = 0;
117     static constexpr size_t DWARF_FP = 0;
118     static constexpr size_t DWARF_LR = 0;
119     using WordType = uint32_t;
120 };
121 
122 template <>
123 struct ArchTraits<Arch::X86_64> {
124     static constexpr size_t CODE_ALIGNMENT = 16;
125     static constexpr size_t INSTRUCTION_ALIGNMENT = 1;
126     static constexpr size_t INSTRUCTION_MAX_SIZE_BITS = 8;
127     static constexpr size_t POINTER_SIZE = 8;
128     static constexpr bool IS_64_BITS = true;
129     static constexpr size_t THREAD_REG = 15;               // %r15
130     static constexpr size_t CALLER_REG_MASK = 0x000001FF;  // %rax, %rcx, %rdx, %rsi, %rdi, %r8, %r9, %r10, %r11
131     static constexpr size_t CALLER_FP_REG_MASK = 0x0000FFFF;
132     static constexpr size_t CALLEE_REG_MASK = 0x0000F800;  // %rbx, %r12, %r13, %r14, %r15
133     static constexpr size_t CALLEE_FP_REG_MASK = 0x00000000;
134     static constexpr bool SUPPORT_OSR = false;
135     static constexpr bool SUPPORT_DEOPTIMIZATION = true;
136     static constexpr const char *ISA_NAME = "x86_64";
137     static constexpr size_t DWARF_SP = 7;
138     static constexpr size_t DWARF_RIP = 16;
139     static constexpr size_t DWARF_FP = 6;
140     static constexpr size_t DWARF_LR = 0;
141     using WordType = uint64_t;
142 };
143 
144 template <>
145 struct ArchTraits<Arch::NONE> {
146     static constexpr size_t CODE_ALIGNMENT = 0;
147     static constexpr size_t INSTRUCTION_ALIGNMENT = 0;
148     static constexpr size_t INSTRUCTION_MAX_SIZE_BITS = 1;
149     static constexpr size_t POINTER_SIZE = 0;
150     static constexpr bool IS_64_BITS = false;
151     static constexpr size_t CALLEE_REG_MASK = 0x00000000;
152     static constexpr size_t CALLEE_FP_REG_MASK = 0x00000000;
153     static constexpr const char *ISA_NAME = "";
154     static constexpr size_t DWARF_SP = 0;
155     static constexpr size_t DWARF_RIP = 0;
156     static constexpr size_t DWARF_FP = 0;
157     static constexpr size_t DWARF_LR = 0;
158     using WordType = void;
159 };
160 
161 // CC-OFFNXT(G.PRE.06) solid logic
162 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage,-warnings-as-errors)
163 #define DEF_ARCH_PROPERTY_GETTER(func_name, property)                                                 \
164     /* CC-OFFNXT(G.PRE.02) namespace member */                                                        \
165     constexpr std::remove_const_t<decltype(ArchTraits<Arch::AARCH64>::property)> func_name(Arch arch) \
166     {                                                                                                 \
167         ASSERT(arch != Arch::NONE);                                                                   \
168         if (arch == Arch::X86) {                                                                      \
169             /* CC-OFFNXT(G.PRE.02, G.PRE.05) namespace member, function gen */                        \
170             return ArchTraits<Arch::X86>::property;                                                   \
171         }                                                                                             \
172         if (arch == Arch::X86_64) {                                                                   \
173             /* CC-OFFNXT(G.PRE.02, G.PRE.05) namespace member, function gen */                        \
174             return ArchTraits<Arch::X86_64>::property;                                                \
175         }                                                                                             \
176         if (arch == Arch::AARCH32) {                                                                  \
177             /* CC-OFFNXT(G.PRE.02, G.PRE.05) namespace member, function gen */                        \
178             return ArchTraits<Arch::AARCH32>::property;                                               \
179         }                                                                                             \
180         if (arch == Arch::AARCH64) {                                                                  \
181             /* CC-OFFNXT(G.PRE.02, G.PRE.05) namespace member, function gen */                        \
182             return ArchTraits<Arch::AARCH64>::property;                                               \
183         }                                                                                             \
184         UNREACHABLE();                                                                                \
185     }
186 
187 DEF_ARCH_PROPERTY_GETTER(DoesArchSupportDeoptimization, SUPPORT_DEOPTIMIZATION)
188 DEF_ARCH_PROPERTY_GETTER(GetCodeAlignment, CODE_ALIGNMENT)
189 DEF_ARCH_PROPERTY_GETTER(GetInstructionAlignment, INSTRUCTION_ALIGNMENT)
190 DEF_ARCH_PROPERTY_GETTER(GetInstructionSizeBits, INSTRUCTION_MAX_SIZE_BITS)
191 DEF_ARCH_PROPERTY_GETTER(Is64BitsArch, IS_64_BITS)
192 DEF_ARCH_PROPERTY_GETTER(PointerSize, POINTER_SIZE)
193 DEF_ARCH_PROPERTY_GETTER(GetThreadReg, THREAD_REG)
194 // constant is needed for correct call libdwarf-library
195 DEF_ARCH_PROPERTY_GETTER(GetIsaName, ISA_NAME)
196 DEF_ARCH_PROPERTY_GETTER(GetDwarfSP, DWARF_SP)
197 DEF_ARCH_PROPERTY_GETTER(GetDwarfRIP, DWARF_RIP)
198 DEF_ARCH_PROPERTY_GETTER(GetDwarfFP, DWARF_FP)
199 DEF_ARCH_PROPERTY_GETTER(GetDwarfLR, DWARF_LR)
200 
201 constexpr const char *GetArchString(Arch arch)
202 {
203     switch (arch) {
204 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
205 #define DEF(v)                               \
206     /* CC-OFFNXT(G.PRE.02) namespace name */ \
207     case Arch::v:                            \
208         return #v;  // CC-OFF(G.PRE.05, G.PRE.09) code generation
209         ARCH_LIST(DEF)
210 #undef DEF
211         default:
212             UNREACHABLE();
213     }
214 }
215 
216 constexpr RegMask GetCallerRegsMask(Arch arch, bool isFp)
217 {
218     switch (arch) {
219         case Arch::AARCH32:
220             return isFp ? ArchTraits<Arch::AARCH32>::CALLER_FP_REG_MASK : ArchTraits<Arch::AARCH32>::CALLER_REG_MASK;
221         case Arch::AARCH64:
222             return isFp ? ArchTraits<Arch::AARCH64>::CALLER_FP_REG_MASK : ArchTraits<Arch::AARCH64>::CALLER_REG_MASK;
223         case Arch::X86:
224             return isFp ? ArchTraits<Arch::X86>::CALLER_FP_REG_MASK : ArchTraits<Arch::X86>::CALLER_REG_MASK;
225         case Arch::X86_64:
226             return isFp ? ArchTraits<Arch::X86_64>::CALLER_FP_REG_MASK : ArchTraits<Arch::X86_64>::CALLER_REG_MASK;
227         default:
228             UNREACHABLE();
229     }
230 }
231 
232 constexpr RegMask GetCalleeRegsMask(Arch arch, bool isFp, bool irtocOptimized = false)
233 {
234     switch (arch) {
235         case Arch::AARCH32:
236             return isFp ? ArchTraits<Arch::AARCH32>::CALLEE_FP_REG_MASK : ArchTraits<Arch::AARCH32>::CALLEE_REG_MASK;
237         case Arch::AARCH64:
238             // return AARCH64Case(arch, isFp, irtocOptimized)
239             static_assert((~ArchTraits<Arch::AARCH64>::CALLEE_FP_REG_MASK &
240                            ArchTraits<Arch::AARCH64>::IRTOC_OPTIMIZED_CALLEE_FP_REG_MASK) == 0);
241             static_assert((~ArchTraits<Arch::AARCH64>::CALLEE_REG_MASK &
242                            ArchTraits<Arch::AARCH64>::IRTOC_OPTIMIZED_CALLEE_REG_MASK) == 0);
243             return isFp             ? irtocOptimized ? ArchTraits<Arch::AARCH64>::IRTOC_OPTIMIZED_CALLEE_FP_REG_MASK
244                                                      : ArchTraits<Arch::AARCH64>::CALLEE_FP_REG_MASK
245                    : irtocOptimized ? ArchTraits<Arch::AARCH64>::IRTOC_OPTIMIZED_CALLEE_REG_MASK
246                                     : ArchTraits<Arch::AARCH64>::CALLEE_REG_MASK;
247         case Arch::X86:
248             return isFp ? ArchTraits<Arch::X86>::CALLEE_FP_REG_MASK : ArchTraits<Arch::X86>::CALLEE_REG_MASK;
249         case Arch::X86_64:
250             return isFp ? ArchTraits<Arch::X86_64>::CALLEE_FP_REG_MASK : ArchTraits<Arch::X86_64>::CALLEE_REG_MASK;
251         default:
252             UNREACHABLE();
253     }
254 }
255 
256 inline constexpr size_t GetFirstCalleeReg(Arch arch, bool isFp)
257 {
258     if (arch == Arch::X86_64 && isFp) {
259         // in amd64 xmm regs are volatile, so we return first reg (1) > last reg(0) to imitate empty list;
260         // also number of registers = last reg (0) - first reg (1) + 1 == 0
261         return 1;
262     }
263 
264     return GetCalleeRegsMask(arch, isFp).GetMinRegister();
265 }
266 
267 inline constexpr size_t GetLastCalleeReg(Arch arch, bool isFp)
268 {
269     if (arch == Arch::X86_64 && isFp) {
270         return 0;
271     }
272 
273     return GetCalleeRegsMask(arch, isFp).GetMaxRegister();
274 }
275 
276 inline constexpr size_t GetCalleeRegsCount(Arch arch, bool isFp)
277 {
278     return GetCalleeRegsMask(arch, isFp).Count();
279 }
280 
281 inline constexpr size_t GetFirstCallerReg(Arch arch, bool isFp)
282 {
283     return GetCallerRegsMask(arch, isFp).GetMinRegister();
284 }
285 
286 inline constexpr size_t GetLastCallerReg(Arch arch, bool isFp)
287 {
288     return GetCallerRegsMask(arch, isFp).GetMaxRegister();
289 }
290 
291 inline constexpr size_t GetCallerRegsCount(Arch arch, bool isFp)
292 {
293     return GetCallerRegsMask(arch, isFp).Count();
294 }
295 
296 inline constexpr size_t GetRegsCount(Arch arch)
297 {
298     return GetCalleeRegsCount(arch, false) + GetCalleeRegsCount(arch, true) + GetCallerRegsCount(arch, false) +
299            GetCallerRegsCount(arch, true);
300 }
301 
302 #ifdef PANDA_TARGET_ARM32
303 static constexpr Arch RUNTIME_ARCH = Arch::AARCH32;
304 #elif defined(PANDA_TARGET_ARM64)
305 static constexpr Arch RUNTIME_ARCH = Arch::AARCH64;
306 #elif defined(PANDA_TARGET_X86)
307 static constexpr Arch RUNTIME_ARCH = Arch::X86;
308 #elif defined(PANDA_TARGET_AMD64)
309 static constexpr Arch RUNTIME_ARCH = Arch::X86_64;
310 #else
311 static constexpr Arch RUNTIME_ARCH = Arch::NONE;
312 #endif
313 
314 template <class String = std::string>
315 std::enable_if_t<is_stringable_v<String>, Arch> GetArchFromString(const String &str)
316 {
317     // NOTE(msherstennikov): implement using macro if "aarch64", "aarch32" and so on would be a proper choice
318     if (str == "arm64") {
319         return Arch::AARCH64;
320     }
321     if (str == "arm" || str == "arm32") {
322         return Arch::AARCH32;
323     }
324     if (str == "x86") {
325         return Arch::X86;
326     }
327     if (str == "x86_64" || str == "x64") {
328         return Arch::X86_64;
329     }
330     return Arch::NONE;
331 }
332 
333 template <class String = std::string>
334 std::enable_if_t<is_stringable_v<String>, String> GetStringFromArch(const Arch &arch)
335 {
336     if (arch == Arch::AARCH64) {
337         return "arm64";
338     }
339     if (arch == Arch::AARCH32) {
340         return "arm";
341     }
342     if (arch == Arch::X86) {
343         return "x86";
344     }
345     if (arch == Arch::X86_64) {
346         return "x86_64";
347     }
348     return "none";
349 }
350 
351 }  // namespace ark
352 
353 #endif  // PANDA_ARCH_H
354