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