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