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