| 1 | //===-- ARMBaseInfo.h - Top level definitions for ARM -------- --*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file contains small standalone helper functions and enum definitions for |
| 10 | // the ARM target useful for the compiler back-end and the MC libraries. |
| 11 | // As such, it deliberately does not include references to LLVM core |
| 12 | // code gen types, passes, etc.. |
| 13 | // |
| 14 | //===----------------------------------------------------------------------===// |
| 15 | |
| 16 | #ifndef LLVM_LIB_TARGET_ARM_MCTARGETDESC_ARMBASEINFO_H |
| 17 | #define LLVM_LIB_TARGET_ARM_MCTARGETDESC_ARMBASEINFO_H |
| 18 | |
| 19 | #include "ARMMCTargetDesc.h" |
| 20 | #include "llvm/Support/ErrorHandling.h" |
| 21 | #include "Utils/ARMBaseInfo.h" |
| 22 | |
| 23 | namespace llvm { |
| 24 | |
| 25 | namespace ARM_PROC { |
| 26 | enum IMod { |
| 27 | IE = 2, |
| 28 | ID = 3 |
| 29 | }; |
| 30 | |
| 31 | enum IFlags { |
| 32 | F = 1, |
| 33 | I = 2, |
| 34 | A = 4 |
| 35 | }; |
| 36 | |
| 37 | inline static const char *IFlagsToString(unsigned val) { |
| 38 | switch (val) { |
| 39 | default: llvm_unreachable("Unknown iflags operand" ); |
| 40 | case F: return "f" ; |
| 41 | case I: return "i" ; |
| 42 | case A: return "a" ; |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | inline static const char *IModToString(unsigned val) { |
| 47 | switch (val) { |
| 48 | default: llvm_unreachable("Unknown imod operand" ); |
| 49 | case IE: return "ie" ; |
| 50 | case ID: return "id" ; |
| 51 | } |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | namespace ARM_MB { |
| 56 | // The Memory Barrier Option constants map directly to the 4-bit encoding of |
| 57 | // the option field for memory barrier operations. |
| 58 | enum MemBOpt { |
| 59 | RESERVED_0 = 0, |
| 60 | OSHLD = 1, |
| 61 | OSHST = 2, |
| 62 | OSH = 3, |
| 63 | RESERVED_4 = 4, |
| 64 | NSHLD = 5, |
| 65 | NSHST = 6, |
| 66 | NSH = 7, |
| 67 | RESERVED_8 = 8, |
| 68 | ISHLD = 9, |
| 69 | ISHST = 10, |
| 70 | ISH = 11, |
| 71 | RESERVED_12 = 12, |
| 72 | LD = 13, |
| 73 | ST = 14, |
| 74 | SY = 15 |
| 75 | }; |
| 76 | |
| 77 | inline static const char *MemBOptToString(unsigned val, bool HasV8) { |
| 78 | switch (val) { |
| 79 | default: llvm_unreachable("Unknown memory operation" ); |
| 80 | case SY: return "sy" ; |
| 81 | case ST: return "st" ; |
| 82 | case LD: return HasV8 ? "ld" : "#0xd" ; |
| 83 | case RESERVED_12: return "#0xc" ; |
| 84 | case ISH: return "ish" ; |
| 85 | case ISHST: return "ishst" ; |
| 86 | case ISHLD: return HasV8 ? "ishld" : "#0x9" ; |
| 87 | case RESERVED_8: return "#0x8" ; |
| 88 | case NSH: return "nsh" ; |
| 89 | case NSHST: return "nshst" ; |
| 90 | case NSHLD: return HasV8 ? "nshld" : "#0x5" ; |
| 91 | case RESERVED_4: return "#0x4" ; |
| 92 | case OSH: return "osh" ; |
| 93 | case OSHST: return "oshst" ; |
| 94 | case OSHLD: return HasV8 ? "oshld" : "#0x1" ; |
| 95 | case RESERVED_0: return "#0x0" ; |
| 96 | } |
| 97 | } |
| 98 | } // namespace ARM_MB |
| 99 | |
| 100 | namespace ARM_TSB { |
| 101 | enum TraceSyncBOpt { |
| 102 | CSYNC = 0 |
| 103 | }; |
| 104 | |
| 105 | inline static const char *TraceSyncBOptToString(unsigned val) { |
| 106 | switch (val) { |
| 107 | default: |
| 108 | llvm_unreachable("Unknown trace synchronization barrier operation" ); |
| 109 | case CSYNC: return "csync" ; |
| 110 | } |
| 111 | } |
| 112 | } // namespace ARM_TSB |
| 113 | |
| 114 | namespace ARM_ISB { |
| 115 | enum InstSyncBOpt { |
| 116 | RESERVED_0 = 0, |
| 117 | RESERVED_1 = 1, |
| 118 | RESERVED_2 = 2, |
| 119 | RESERVED_3 = 3, |
| 120 | RESERVED_4 = 4, |
| 121 | RESERVED_5 = 5, |
| 122 | RESERVED_6 = 6, |
| 123 | RESERVED_7 = 7, |
| 124 | RESERVED_8 = 8, |
| 125 | RESERVED_9 = 9, |
| 126 | RESERVED_10 = 10, |
| 127 | RESERVED_11 = 11, |
| 128 | RESERVED_12 = 12, |
| 129 | RESERVED_13 = 13, |
| 130 | RESERVED_14 = 14, |
| 131 | SY = 15 |
| 132 | }; |
| 133 | |
| 134 | inline static const char *InstSyncBOptToString(unsigned val) { |
| 135 | switch (val) { |
| 136 | default: |
| 137 | llvm_unreachable("Unknown memory operation" ); |
| 138 | case RESERVED_0: return "#0x0" ; |
| 139 | case RESERVED_1: return "#0x1" ; |
| 140 | case RESERVED_2: return "#0x2" ; |
| 141 | case RESERVED_3: return "#0x3" ; |
| 142 | case RESERVED_4: return "#0x4" ; |
| 143 | case RESERVED_5: return "#0x5" ; |
| 144 | case RESERVED_6: return "#0x6" ; |
| 145 | case RESERVED_7: return "#0x7" ; |
| 146 | case RESERVED_8: return "#0x8" ; |
| 147 | case RESERVED_9: return "#0x9" ; |
| 148 | case RESERVED_10: return "#0xa" ; |
| 149 | case RESERVED_11: return "#0xb" ; |
| 150 | case RESERVED_12: return "#0xc" ; |
| 151 | case RESERVED_13: return "#0xd" ; |
| 152 | case RESERVED_14: return "#0xe" ; |
| 153 | case SY: return "sy" ; |
| 154 | } |
| 155 | } |
| 156 | } // namespace ARM_ISB |
| 157 | |
| 158 | /// isARMLowRegister - Returns true if the register is a low register (r0-r7). |
| 159 | /// |
| 160 | static inline bool isARMLowRegister(MCRegister Reg) { |
| 161 | using namespace ARM; |
| 162 | switch (Reg.id()) { |
| 163 | case R0: case R1: case R2: case R3: |
| 164 | case R4: case R5: case R6: case R7: |
| 165 | return true; |
| 166 | default: |
| 167 | return false; |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | /// ARMII - This namespace holds all of the target specific flags that |
| 172 | /// instruction info tracks. |
| 173 | /// |
| 174 | namespace ARMII { |
| 175 | |
| 176 | /// ARM Index Modes |
| 177 | enum IndexMode { |
| 178 | IndexModeNone = 0, |
| 179 | IndexModePre = 1, |
| 180 | IndexModePost = 2, |
| 181 | IndexModeUpd = 3 |
| 182 | }; |
| 183 | |
| 184 | /// ARM Addressing Modes |
| 185 | enum AddrMode { |
| 186 | AddrModeNone = 0, |
| 187 | AddrMode1 = 1, |
| 188 | AddrMode2 = 2, |
| 189 | AddrMode3 = 3, |
| 190 | AddrMode4 = 4, |
| 191 | AddrMode5 = 5, |
| 192 | AddrMode6 = 6, |
| 193 | AddrModeT1_1 = 7, |
| 194 | AddrModeT1_2 = 8, |
| 195 | AddrModeT1_4 = 9, |
| 196 | AddrModeT1_s = 10, // i8 * 4 for pc and sp relative data |
| 197 | AddrModeT2_i12 = 11, |
| 198 | AddrModeT2_i8 = 12, // +/- i8 |
| 199 | AddrModeT2_i8pos = 13, // + i8 |
| 200 | AddrModeT2_i8neg = 14, // - i8 |
| 201 | AddrModeT2_so = 15, |
| 202 | AddrModeT2_pc = 16, // +/- i12 for pc relative data |
| 203 | AddrModeT2_i8s4 = 17, // i8 * 4 |
| 204 | AddrMode_i12 = 18, |
| 205 | AddrMode5FP16 = 19, // i8 * 2 |
| 206 | AddrModeT2_ldrex = 20, // i8 * 4, with unscaled offset in MCInst |
| 207 | AddrModeT2_i7s4 = 21, // i7 * 4 |
| 208 | AddrModeT2_i7s2 = 22, // i7 * 2 |
| 209 | AddrModeT2_i7 = 23, // i7 * 1 |
| 210 | }; |
| 211 | |
| 212 | inline static const char *AddrModeToString(AddrMode addrmode) { |
| 213 | switch (addrmode) { |
| 214 | case AddrModeNone: return "AddrModeNone" ; |
| 215 | case AddrMode1: return "AddrMode1" ; |
| 216 | case AddrMode2: return "AddrMode2" ; |
| 217 | case AddrMode3: return "AddrMode3" ; |
| 218 | case AddrMode4: return "AddrMode4" ; |
| 219 | case AddrMode5: return "AddrMode5" ; |
| 220 | case AddrMode5FP16: return "AddrMode5FP16" ; |
| 221 | case AddrMode6: return "AddrMode6" ; |
| 222 | case AddrModeT1_1: return "AddrModeT1_1" ; |
| 223 | case AddrModeT1_2: return "AddrModeT1_2" ; |
| 224 | case AddrModeT1_4: return "AddrModeT1_4" ; |
| 225 | case AddrModeT1_s: return "AddrModeT1_s" ; |
| 226 | case AddrModeT2_i12: return "AddrModeT2_i12" ; |
| 227 | case AddrModeT2_i8: return "AddrModeT2_i8" ; |
| 228 | case AddrModeT2_i8pos: return "AddrModeT2_i8pos" ; |
| 229 | case AddrModeT2_i8neg: return "AddrModeT2_i8neg" ; |
| 230 | case AddrModeT2_so: return "AddrModeT2_so" ; |
| 231 | case AddrModeT2_pc: return "AddrModeT2_pc" ; |
| 232 | case AddrModeT2_i8s4: return "AddrModeT2_i8s4" ; |
| 233 | case AddrMode_i12: return "AddrMode_i12" ; |
| 234 | case AddrModeT2_ldrex: return "AddrModeT2_ldrex" ; |
| 235 | case AddrModeT2_i7s4: return "AddrModeT2_i7s4" ; |
| 236 | case AddrModeT2_i7s2: return "AddrModeT2_i7s2" ; |
| 237 | case AddrModeT2_i7: return "AddrModeT2_i7" ; |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | /// Target Operand Flag enum. |
| 242 | enum TOF { |
| 243 | //===------------------------------------------------------------------===// |
| 244 | // ARM Specific MachineOperand flags. |
| 245 | |
| 246 | MO_NO_FLAG = 0, |
| 247 | |
| 248 | /// MO_LO16 - On a symbol operand, this represents a relocation containing |
| 249 | /// lower 16 bit of the address. Used only via movw instruction. |
| 250 | MO_LO16 = 0x1, |
| 251 | |
| 252 | /// MO_HI16 - On a symbol operand, this represents a relocation containing |
| 253 | /// higher 16 bit of the address. Used only via movt instruction. |
| 254 | MO_HI16 = 0x2, |
| 255 | |
| 256 | /// MO_OPTION_MASK - Most flags are mutually exclusive; this mask selects |
| 257 | /// just that part of the flag set. |
| 258 | MO_OPTION_MASK = 0xf03, |
| 259 | |
| 260 | /// MO_COFFSTUB - On a symbol operand "FOO", this indicates that the |
| 261 | /// reference is actually to the ".refptr.FOO" symbol. This is used for |
| 262 | /// stub symbols on windows. |
| 263 | MO_COFFSTUB = 0x4, |
| 264 | |
| 265 | /// MO_GOT - On a symbol operand, this represents a GOT relative relocation. |
| 266 | MO_GOT = 0x8, |
| 267 | |
| 268 | /// MO_SBREL - On a symbol operand, this represents a static base relative |
| 269 | /// relocation. Used in movw and movt instructions. |
| 270 | MO_SBREL = 0x10, |
| 271 | |
| 272 | /// MO_DLLIMPORT - On a symbol operand, this represents that the reference |
| 273 | /// to the symbol is for an import stub. This is used for DLL import |
| 274 | /// storage class indication on Windows. |
| 275 | MO_DLLIMPORT = 0x20, |
| 276 | |
| 277 | /// MO_SECREL - On a symbol operand this indicates that the immediate is |
| 278 | /// the offset from beginning of section. |
| 279 | /// |
| 280 | /// This is the TLS offset for the COFF/Windows TLS mechanism. |
| 281 | MO_SECREL = 0x40, |
| 282 | |
| 283 | /// MO_NONLAZY - This is an independent flag, on a symbol operand "FOO" it |
| 284 | /// represents a symbol which, if indirect, will get special Darwin mangling |
| 285 | /// as a non-lazy-ptr indirect symbol (i.e. "L_FOO$non_lazy_ptr"). Can be |
| 286 | /// combined with MO_LO16, MO_HI16 or MO_NO_FLAG (in a constant-pool, for |
| 287 | /// example). |
| 288 | MO_NONLAZY = 0x80, |
| 289 | |
| 290 | /// MO_LO_0_7 - On a symbol operand, this represents a relocation containing |
| 291 | /// bits 0 through 7 of the address. Used only with Thumb1 MOV and ADD |
| 292 | // instructions. |
| 293 | MO_LO_0_7 = 0x100, |
| 294 | |
| 295 | /// MO_LO_8_15 - On a symbol operand, this represents a relocation |
| 296 | /// containing |
| 297 | /// bits 8 through 15 of the address. Used only with Thumb1 MOV and ADD |
| 298 | // instructions. |
| 299 | MO_LO_8_15 = 0x200, |
| 300 | |
| 301 | /// MO_HI_0_7 - On a symbol operand, this represents a relocation containing |
| 302 | /// bits 16 through 23 of the address. Used only with Thumb1 MOV and ADD |
| 303 | // instructions. |
| 304 | MO_HI_0_7 = 0x400, |
| 305 | |
| 306 | /// MO_HI_8_15 - On a symbol operand, this represents a relocation |
| 307 | /// containing |
| 308 | /// bits 24 through 31 of the address. Used only with Thumb1 MOV and ADD |
| 309 | // instructions. |
| 310 | MO_HI_8_15 = 0x800 |
| 311 | }; |
| 312 | |
| 313 | enum { |
| 314 | //===------------------------------------------------------------------===// |
| 315 | // Instruction Flags. |
| 316 | |
| 317 | //===------------------------------------------------------------------===// |
| 318 | // This four-bit field describes the addressing mode used. |
| 319 | AddrModeMask = 0x1f, // The AddrMode enums are declared in ARMBaseInfo.h |
| 320 | |
| 321 | // IndexMode - Unindex, pre-indexed, or post-indexed are valid for load |
| 322 | // and store ops only. Generic "updating" flag is used for ld/st multiple. |
| 323 | // The index mode enums are declared in ARMBaseInfo.h |
| 324 | IndexModeShift = 5, |
| 325 | IndexModeMask = 3 << IndexModeShift, |
| 326 | |
| 327 | //===------------------------------------------------------------------===// |
| 328 | // Instruction encoding formats. |
| 329 | // |
| 330 | FormShift = 7, |
| 331 | FormMask = 0x3f << FormShift, |
| 332 | |
| 333 | // Pseudo instructions |
| 334 | Pseudo = 0 << FormShift, |
| 335 | |
| 336 | // Multiply instructions |
| 337 | MulFrm = 1 << FormShift, |
| 338 | |
| 339 | // Branch instructions |
| 340 | BrFrm = 2 << FormShift, |
| 341 | BrMiscFrm = 3 << FormShift, |
| 342 | |
| 343 | // Data Processing instructions |
| 344 | DPFrm = 4 << FormShift, |
| 345 | DPSoRegFrm = 5 << FormShift, |
| 346 | |
| 347 | // Load and Store |
| 348 | LdFrm = 6 << FormShift, |
| 349 | StFrm = 7 << FormShift, |
| 350 | LdMiscFrm = 8 << FormShift, |
| 351 | StMiscFrm = 9 << FormShift, |
| 352 | LdStMulFrm = 10 << FormShift, |
| 353 | |
| 354 | LdStExFrm = 11 << FormShift, |
| 355 | |
| 356 | // Miscellaneous arithmetic instructions |
| 357 | ArithMiscFrm = 12 << FormShift, |
| 358 | SatFrm = 13 << FormShift, |
| 359 | |
| 360 | // Extend instructions |
| 361 | ExtFrm = 14 << FormShift, |
| 362 | |
| 363 | // VFP formats |
| 364 | VFPUnaryFrm = 15 << FormShift, |
| 365 | VFPBinaryFrm = 16 << FormShift, |
| 366 | VFPConv1Frm = 17 << FormShift, |
| 367 | VFPConv2Frm = 18 << FormShift, |
| 368 | VFPConv3Frm = 19 << FormShift, |
| 369 | VFPConv4Frm = 20 << FormShift, |
| 370 | VFPConv5Frm = 21 << FormShift, |
| 371 | VFPLdStFrm = 22 << FormShift, |
| 372 | VFPLdStMulFrm = 23 << FormShift, |
| 373 | VFPMiscFrm = 24 << FormShift, |
| 374 | |
| 375 | // Thumb format |
| 376 | ThumbFrm = 25 << FormShift, |
| 377 | |
| 378 | // Miscelleaneous format |
| 379 | MiscFrm = 26 << FormShift, |
| 380 | |
| 381 | // NEON formats |
| 382 | NGetLnFrm = 27 << FormShift, |
| 383 | NSetLnFrm = 28 << FormShift, |
| 384 | NDupFrm = 29 << FormShift, |
| 385 | NLdStFrm = 30 << FormShift, |
| 386 | N1RegModImmFrm= 31 << FormShift, |
| 387 | N2RegFrm = 32 << FormShift, |
| 388 | NVCVTFrm = 33 << FormShift, |
| 389 | NVDupLnFrm = 34 << FormShift, |
| 390 | N2RegVShLFrm = 35 << FormShift, |
| 391 | N2RegVShRFrm = 36 << FormShift, |
| 392 | N3RegFrm = 37 << FormShift, |
| 393 | N3RegVShFrm = 38 << FormShift, |
| 394 | NVExtFrm = 39 << FormShift, |
| 395 | NVMulSLFrm = 40 << FormShift, |
| 396 | NVTBLFrm = 41 << FormShift, |
| 397 | N3RegCplxFrm = 43 << FormShift, |
| 398 | |
| 399 | //===------------------------------------------------------------------===// |
| 400 | // Misc flags. |
| 401 | |
| 402 | // UnaryDP - Indicates this is a unary data processing instruction, i.e. |
| 403 | // it doesn't have a Rn operand. |
| 404 | UnaryDP = 1 << 13, |
| 405 | |
| 406 | // Xform16Bit - Indicates this Thumb2 instruction may be transformed into |
| 407 | // a 16-bit Thumb instruction if certain conditions are met. |
| 408 | Xform16Bit = 1 << 14, |
| 409 | |
| 410 | // ThumbArithFlagSetting - The instruction is a 16-bit flag setting Thumb |
| 411 | // instruction. Used by the parser to determine whether to require the 'S' |
| 412 | // suffix on the mnemonic (when not in an IT block) or preclude it (when |
| 413 | // in an IT block). |
| 414 | ThumbArithFlagSetting = 1 << 19, |
| 415 | |
| 416 | // Whether an instruction can be included in an MVE tail-predicated loop, |
| 417 | // though extra validity checks may need to be performed too. |
| 418 | ValidForTailPredication = 1 << 20, |
| 419 | |
| 420 | // Whether an instruction writes to the top/bottom half of a vector element |
| 421 | // and leaves the other half untouched. |
| 422 | RetainsPreviousHalfElement = 1 << 21, |
| 423 | |
| 424 | // Whether the instruction produces a scalar result from vector operands. |
| 425 | HorizontalReduction = 1 << 22, |
| 426 | |
| 427 | // Whether this instruction produces a vector result that is larger than |
| 428 | // its input, typically reading from the top/bottom halves of the input(s). |
| 429 | DoubleWidthResult = 1 << 23, |
| 430 | |
| 431 | // The vector element size for MVE instructions. 00 = i8, 01 = i16, 10 = i32 |
| 432 | // and 11 = i64. This is the largest type if multiple are present, so a |
| 433 | // MVE_VMOVLs8bh is ize 01=i16, as it extends from a i8 to a i16. There are |
| 434 | // some caveats so cannot be used blindly, such as exchanging VMLADAVA's and |
| 435 | // complex instructions, which may use different input lanes. |
| 436 | VecSizeShift = 24, |
| 437 | VecSize = 3 << VecSizeShift, |
| 438 | |
| 439 | //===------------------------------------------------------------------===// |
| 440 | // Code domain. |
| 441 | DomainShift = 15, |
| 442 | DomainMask = 15 << DomainShift, |
| 443 | DomainGeneral = 0 << DomainShift, |
| 444 | DomainVFP = 1 << DomainShift, |
| 445 | DomainNEON = 2 << DomainShift, |
| 446 | DomainNEONA8 = 4 << DomainShift, |
| 447 | DomainMVE = 8 << DomainShift, |
| 448 | |
| 449 | //===------------------------------------------------------------------===// |
| 450 | // Field shifts - such shifts are used to set field while generating |
| 451 | // machine instructions. |
| 452 | // |
| 453 | // FIXME: This list will need adjusting/fixing as the MC code emitter |
| 454 | // takes shape and the ARMCodeEmitter.cpp bits go away. |
| 455 | ShiftTypeShift = 4, |
| 456 | |
| 457 | M_BitShift = 5, |
| 458 | ShiftImmShift = 5, |
| 459 | ShiftShift = 7, |
| 460 | N_BitShift = 7, |
| 461 | ImmHiShift = 8, |
| 462 | SoRotImmShift = 8, |
| 463 | = 8, |
| 464 | ExtRotImmShift = 10, |
| 465 | RegRdLoShift = 12, |
| 466 | RegRdShift = 12, |
| 467 | RegRdHiShift = 16, |
| 468 | RegRnShift = 16, |
| 469 | S_BitShift = 20, |
| 470 | W_BitShift = 21, |
| 471 | AM3_I_BitShift = 22, |
| 472 | D_BitShift = 22, |
| 473 | U_BitShift = 23, |
| 474 | P_BitShift = 24, |
| 475 | I_BitShift = 25, |
| 476 | CondShift = 28 |
| 477 | }; |
| 478 | |
| 479 | } // end namespace ARMII |
| 480 | |
| 481 | } // end namespace llvm; |
| 482 | |
| 483 | #endif |
| 484 | |