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