OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #ifndef VM_CONSTANTS_ARM64_H_ |
| 6 #define VM_CONSTANTS_ARM64_H_ |
| 7 |
| 8 #include "platform/assert.h" |
| 9 |
| 10 namespace dart { |
| 11 |
| 12 enum Register { |
| 13 kFirstFreeCpuRegister = 0, |
| 14 R0 = 0, |
| 15 R1 = 1, |
| 16 R2 = 2, |
| 17 R3 = 3, |
| 18 R4 = 4, |
| 19 R5 = 5, |
| 20 R6 = 6, |
| 21 R7 = 7, |
| 22 R8 = 8, |
| 23 R9 = 9, |
| 24 R10 = 10, |
| 25 R11 = 11, |
| 26 R12 = 12, |
| 27 R13 = 13, |
| 28 R14 = 14, |
| 29 R15 = 15, |
| 30 R16 = 16, |
| 31 R17 = 17, |
| 32 R18 = 18, |
| 33 R19 = 19, |
| 34 R20 = 20, |
| 35 R21 = 21, |
| 36 R22 = 22, |
| 37 R23 = 23, |
| 38 R24 = 24, |
| 39 kLastFreeCpuRegister = 24, |
| 40 R25 = 25, // IP0 |
| 41 R26 = 26, // IP1 |
| 42 R27 = 27, // PP |
| 43 R28 = 28, // CTX |
| 44 R29 = 29, // FP |
| 45 R30 = 30, // LR |
| 46 R31 = 31, // ZR, SP |
| 47 kNumberOfCpuRegisters = 32, |
| 48 kNoRegister = -1, |
| 49 |
| 50 // Aliases. |
| 51 IP0 = R25, |
| 52 IP1 = R26, |
| 53 FP = R29, |
| 54 LR = R30, |
| 55 |
| 56 // Left abstract so we can avoid misuse. |
| 57 SP, |
| 58 ZR, |
| 59 }; |
| 60 |
| 61 enum VRegister { |
| 62 V0 = 0, |
| 63 V1 = 1, |
| 64 V2 = 2, |
| 65 V3 = 3, |
| 66 V4 = 4, |
| 67 V5 = 5, |
| 68 V6 = 6, |
| 69 V7 = 7, |
| 70 V8 = 8, |
| 71 V9 = 9, |
| 72 V10 = 10, |
| 73 V11 = 11, |
| 74 V12 = 12, |
| 75 V13 = 13, |
| 76 V14 = 14, |
| 77 V15 = 15, |
| 78 V16 = 16, |
| 79 V17 = 17, |
| 80 V18 = 18, |
| 81 V19 = 19, |
| 82 V20 = 20, |
| 83 V21 = 21, |
| 84 V22 = 22, |
| 85 V23 = 24, |
| 86 V24 = 24, |
| 87 V25 = 25, |
| 88 V26 = 26, |
| 89 V27 = 27, |
| 90 V28 = 28, |
| 91 V29 = 29, |
| 92 V30 = 30, |
| 93 V31 = 31, |
| 94 kNumberOfVRegisters = 32, |
| 95 kNoVRegister = -1, |
| 96 }; |
| 97 |
| 98 // Register alias for floating point scratch register. |
| 99 const VRegister VTMP0 = V30; |
| 100 const VRegister VTMP1 = V31; |
| 101 |
| 102 // Architecture independent aliases. |
| 103 typedef VRegister FpuRegister; |
| 104 const FpuRegister FpuTMP = VTMP0; |
| 105 const int kNumberOfFpuRegisters = kNumberOfVRegisters; |
| 106 const FpuRegister kNoFpuRegister = kNoVRegister; |
| 107 |
| 108 // Register aliases. |
| 109 const Register TMP = R25; // Used as scratch register by assembler. |
| 110 const Register TMP0 = R25; |
| 111 const Register TMP1 = R26; |
| 112 const Register CTX = R27; // Caches current context in generated code. |
| 113 const Register PP = R26; // Caches object pool pointer in generated code. |
| 114 const Register SPREG = R31; // Stack pointer register. |
| 115 const Register FPREG = FP; // Frame pointer register. |
| 116 const Register ICREG = R5; // IC data register. |
| 117 |
| 118 // Exception object is passed in this register to the catch handlers when an |
| 119 // exception is thrown. |
| 120 const Register kExceptionObjectReg = R0; |
| 121 |
| 122 // Stack trace object is passed in this register to the catch handlers when |
| 123 // an exception is thrown. |
| 124 const Register kStackTraceObjectReg = R1; |
| 125 |
| 126 // Masks, sizes, etc. |
| 127 const int kXRegSizeInBits = 64; |
| 128 const int kWRegSizeInBits = 32; |
| 129 const int64_t kXRegMask = 0xffffffffffffffffL; |
| 130 const int64_t kWRegMask = 0x00000000ffffffffL; |
| 131 |
| 132 // List of registers used in load/store multiple. |
| 133 typedef uint32_t RegList; |
| 134 const RegList kAllCpuRegistersList = 0xFFFF; |
| 135 |
| 136 |
| 137 // C++ ABI call registers. |
| 138 const RegList kAbiArgumentCpuRegs = |
| 139 (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) | |
| 140 (1 << R4) | (1 << R5) | (1 << R6) | (1 << R7); |
| 141 const RegList kAbiPreservedCpuRegs = |
| 142 (1 << R19) | (1 << R20) | (1 << R21) | (1 << R22) | |
| 143 (1 << R23) | (1 << R24) | (1 << R25) | (1 << R26) | |
| 144 (1 << R27) | (1 << R28) | (1 << R29); |
| 145 const int kAbiPreservedCpuRegCount = 11; |
| 146 const VRegister kAbiFirstPreservedFpuReg = V8; |
| 147 const VRegister kAbiLastPreservedFpuReg = V15; |
| 148 const int kAbiPreservedFpuRegCount = 8; |
| 149 |
| 150 // CPU registers available to Dart allocator. |
| 151 const RegList kDartAvailableCpuRegs = |
| 152 (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) | |
| 153 (1 << R4) | (1 << R5) | (1 << R6) | (1 << R7) | |
| 154 (1 << R8) | (1 << R9) | (1 << R10) | (1 << R11) | |
| 155 (1 << R12) | (1 << R13) | (1 << R14) | (1 << R15) | |
| 156 (1 << R16) | (1 << R17) | (1 << R18) | (1 << R19) | |
| 157 (1 << R20) | (1 << R21) | (1 << R22) | (1 << R23) | |
| 158 (1 << R24); |
| 159 |
| 160 // Registers available to Dart that are not preserved by runtime calls. |
| 161 const RegList kDartVolatileCpuRegs = |
| 162 kDartAvailableCpuRegs & ~kAbiPreservedCpuRegs; |
| 163 const int kDartVolatileCpuRegCount = 19; |
| 164 const VRegister kDartFirstVolatileFpuReg = V0; |
| 165 const VRegister kDartLastVolatileFpuReg = V7; |
| 166 const int kDartVolatileFpuRegCount = 8; |
| 167 |
| 168 static inline Register ConcreteRegister(Register r) { |
| 169 return ((r == ZR) || (r == SP)) ? R31 : r; |
| 170 } |
| 171 |
| 172 // Values for the condition field as defined in section A3.2. |
| 173 enum Condition { |
| 174 kNoCondition = -1, |
| 175 EQ = 0, // equal |
| 176 NE = 1, // not equal |
| 177 CS = 2, // carry set/unsigned higher or same |
| 178 CC = 3, // carry clear/unsigned lower |
| 179 MI = 4, // minus/negative |
| 180 PL = 5, // plus/positive or zero |
| 181 VS = 6, // overflow |
| 182 VC = 7, // no overflow |
| 183 HI = 8, // unsigned higher |
| 184 LS = 9, // unsigned lower or same |
| 185 GE = 10, // signed greater than or equal |
| 186 LT = 11, // signed less than |
| 187 GT = 12, // signed greater than |
| 188 LE = 13, // signed less than or equal |
| 189 AL = 14, // always (unconditional) |
| 190 NV = 15, // special condition (refer to section C1.2.3) |
| 191 kMaxCondition = 16, |
| 192 }; |
| 193 |
| 194 enum Bits { |
| 195 B0 = (1 << 0), B1 = (1 << 1), B2 = (1 << 2), B3 = (1 << 3), |
| 196 B4 = (1 << 4), B5 = (1 << 5), B6 = (1 << 6), B7 = (1 << 7), |
| 197 B8 = (1 << 8), B9 = (1 << 9), B10 = (1 << 10), B11 = (1 << 11), |
| 198 B12 = (1 << 12), B13 = (1 << 13), B14 = (1 << 14), B15 = (1 << 15), |
| 199 B16 = (1 << 16), B17 = (1 << 17), B18 = (1 << 18), B19 = (1 << 19), |
| 200 B20 = (1 << 20), B21 = (1 << 21), B22 = (1 << 22), B23 = (1 << 23), |
| 201 B24 = (1 << 24), B25 = (1 << 25), B26 = (1 << 26), B27 = (1 << 27), |
| 202 B28 = (1 << 28), B29 = (1 << 29), B30 = (1 << 30), B31 = (1 << 31), |
| 203 }; |
| 204 |
| 205 enum OperandSize { |
| 206 kByte, |
| 207 kUnsignedByte, |
| 208 kHalfword, |
| 209 kUnsignedHalfword, |
| 210 kWord, |
| 211 kUnsignedWord, |
| 212 kDoubleWord, |
| 213 kSWord, |
| 214 kDWord, |
| 215 }; |
| 216 |
| 217 // Opcodes from C3 |
| 218 // C3.1. |
| 219 enum MainOp { |
| 220 DPImmediateMask = 0x1c000000, |
| 221 DPImmediateFixed = B28, |
| 222 |
| 223 CompareBranchMask = 0x1c000000, |
| 224 CompareBranchFixed = B28 | B26, |
| 225 |
| 226 LoadStoreMask = B27 | B25, |
| 227 LoadStoreFixed = B27, |
| 228 |
| 229 DPRegisterMask = 0x0e000000, |
| 230 DPRegisterFixed = B27 | B25, |
| 231 |
| 232 DPSimd1Mask = 0x1e000000, |
| 233 DPSimd1Fixed = B27 | B26 | B25, |
| 234 |
| 235 DPSimd2Mask = 0x1e000000, |
| 236 DPSimd2Fixed = B28 | DPSimd1Fixed, |
| 237 }; |
| 238 |
| 239 // C3.2.3 |
| 240 enum ExceptionGenOp { |
| 241 ExceptionGenMask = 0xff000000, |
| 242 ExceptionGenFixed = CompareBranchFixed | B31 | B30, |
| 243 SVC = ExceptionGenFixed | B0, |
| 244 BRK = ExceptionGenFixed | B21, |
| 245 HLT = ExceptionGenFixed | B22, |
| 246 }; |
| 247 |
| 248 // C3.2.4 |
| 249 enum SystemOp { |
| 250 SystemMask = 0xffc00000, |
| 251 SystemFixed = CompareBranchFixed | B31 | B30 | B24, |
| 252 HINT = SystemFixed | B17 | B16 | B13 | B4 | B3 | B2 | B1 | B0, |
| 253 }; |
| 254 |
| 255 // C3.2.7 |
| 256 enum UnconditionalBranchRegOp { |
| 257 UnconditionalBranchRegMask = 0xfe000000, |
| 258 UnconditionalBranchRegFixed = CompareBranchFixed | B31 | B30 | B25, |
| 259 BR = UnconditionalBranchRegFixed | B20 | B19 | B18 | B17 | B16, |
| 260 BLR = BR | B21, |
| 261 RET = BR | B22, |
| 262 }; |
| 263 |
| 264 // C3.4.1 |
| 265 enum AddSubImmOp { |
| 266 AddSubImmMask = 0x1f000000, |
| 267 AddSubImmFixed = DPImmediateFixed | B24, |
| 268 ADDI = AddSubImmFixed, |
| 269 SUBI = AddSubImmFixed | B30, |
| 270 }; |
| 271 |
| 272 // C3.4.5 |
| 273 enum MoveWideOp { |
| 274 MoveWideMask = 0x1f800000, |
| 275 MoveWideFixed = DPImmediateFixed | B25 | B23, |
| 276 MOVN = MoveWideFixed, |
| 277 MOVZ = MoveWideFixed | B30, |
| 278 MOVK = MoveWideFixed | B30 | B29, |
| 279 }; |
| 280 |
| 281 |
| 282 // C3.5.1 |
| 283 enum AddSubShiftExtOp { |
| 284 AddSubShiftExtMask = 0x1f200000, |
| 285 AddSubShiftExtFixed = DPRegisterFixed | B24, |
| 286 ADD = AddSubShiftExtFixed, |
| 287 SUB = AddSubShiftExtFixed | B30, |
| 288 }; |
| 289 |
| 290 #define APPLY_OP_LIST(_V) \ |
| 291 _V(DPImmediate) \ |
| 292 _V(CompareBranch) \ |
| 293 _V(LoadStore) \ |
| 294 _V(DPRegister) \ |
| 295 _V(DPSimd1) \ |
| 296 _V(DPSimd2) \ |
| 297 _V(ExceptionGen) \ |
| 298 _V(System) \ |
| 299 _V(UnconditionalBranchReg) \ |
| 300 _V(AddSubImm) \ |
| 301 _V(MoveWide) \ |
| 302 _V(AddSubShiftExt) \ |
| 303 |
| 304 |
| 305 enum Shift { |
| 306 kNoShift = -1, |
| 307 LSL = 0, // Logical shift left |
| 308 LSR = 1, // Logical shift right |
| 309 ASR = 2, // Arithmetic shift right |
| 310 ROR = 3, // Rotate right |
| 311 kMaxShift = 4, |
| 312 }; |
| 313 |
| 314 enum Extend { |
| 315 kNoExtend = -1, |
| 316 UXTB = 0, |
| 317 UXTH = 1, |
| 318 UXTW = 2, |
| 319 UXTX = 3, |
| 320 SXTB = 4, |
| 321 SXTH = 5, |
| 322 SXTW = 6, |
| 323 SXTX = 7, |
| 324 kMaxExtend = 8, |
| 325 }; |
| 326 |
| 327 enum R31Type { |
| 328 R31IsSP, |
| 329 R31IsZR, |
| 330 R31IsUndef, |
| 331 }; |
| 332 |
| 333 // Constants used for the decoding or encoding of the individual fields of |
| 334 // instructions. Based on the "Figure 3-1 ARM instruction set summary". |
| 335 enum InstructionFields { |
| 336 // S-bit (modify condition register) |
| 337 kSShift = 29, |
| 338 kSBits = 1, |
| 339 |
| 340 // sf field. |
| 341 kSFShift = 31, |
| 342 kSFBits = 1, |
| 343 |
| 344 // Registers. |
| 345 kRdShift = 0, |
| 346 kRdBits = 5, |
| 347 kRnShift = 5, |
| 348 kRnBits = 5, |
| 349 kRaShift = 10, |
| 350 kRaBits = 5, |
| 351 kRmShift = 16, |
| 352 kRmBits = 5, |
| 353 |
| 354 // Immediates. |
| 355 kImm3Shift = 10, |
| 356 kImm3Bits = 3, |
| 357 kImm6Shift = 10, |
| 358 kImm6Bits = 6, |
| 359 kImm12Shift = 10, |
| 360 kImm12Bits = 12, |
| 361 kImm12ShiftShift = 22, |
| 362 kImm12ShiftBits = 2, |
| 363 kImm16Shift = 5, |
| 364 kImm16Bits = 16, |
| 365 |
| 366 // Shift and Extend. |
| 367 kShiftExtendShift = 21, |
| 368 kShiftExtendBits = 1, |
| 369 kShiftTypeShift = 22, |
| 370 kShiftTypeBits = 2, |
| 371 kExtendTypeShift = 13, |
| 372 kExtendTypeBits = 3, |
| 373 |
| 374 // Hint Fields. |
| 375 kHintCRmShift = 8, |
| 376 kHintCRmBits = 4, |
| 377 kHintOp2Shift = 5, |
| 378 kHintOp2Bits = 3, |
| 379 }; |
| 380 |
| 381 |
| 382 const uint32_t kImmExceptionIsRedirectedCall = 0xca11; |
| 383 const uint32_t kImmExceptionIsUnreachable = 0xdebf; |
| 384 const uint32_t kImmExceptionIsPrintf = 0xdeb1; |
| 385 const uint32_t kImmExceptionIsDebug = 0xdeb0; |
| 386 |
| 387 // The class Instr enables access to individual fields defined in the ARM |
| 388 // architecture instruction set encoding as described in figure A3-1. |
| 389 // |
| 390 // Example: Test whether the instruction at ptr sets the condition code bits. |
| 391 // |
| 392 // bool InstructionSetsConditionCodes(byte* ptr) { |
| 393 // Instr* instr = Instr::At(ptr); |
| 394 // int type = instr->TypeField(); |
| 395 // return ((type == 0) || (type == 1)) && instr->HasS(); |
| 396 // } |
| 397 // |
| 398 class Instr { |
| 399 public: |
| 400 enum { |
| 401 kInstrSize = 4, |
| 402 kInstrSizeLog2 = 2, |
| 403 kPCReadOffset = 8 |
| 404 }; |
| 405 |
| 406 static const int32_t kNopInstruction = HINT; // hint #0 === nop. |
| 407 static const int32_t kBreakPointInstruction = // hlt #kImmExceptionIsDebug. |
| 408 HLT | (kImmExceptionIsDebug << kImm16Shift); |
| 409 static const int kBreakPointInstructionSize = kInstrSize; |
| 410 |
| 411 // Get the raw instruction bits. |
| 412 inline int32_t InstructionBits() const { |
| 413 return *reinterpret_cast<const int32_t*>(this); |
| 414 } |
| 415 |
| 416 // Set the raw instruction bits to value. |
| 417 inline void SetInstructionBits(int32_t value) { |
| 418 *reinterpret_cast<int32_t*>(this) = value; |
| 419 } |
| 420 |
| 421 // Read one particular bit out of the instruction bits. |
| 422 inline int Bit(int nr) const { |
| 423 return (InstructionBits() >> nr) & 1; |
| 424 } |
| 425 |
| 426 // Read a bit field out of the instruction bits. |
| 427 inline int Bits(int shift, int count) const { |
| 428 return (InstructionBits() >> shift) & ((1 << count) - 1); |
| 429 } |
| 430 |
| 431 |
| 432 inline int SField() const { return Bit(kSShift); } |
| 433 inline int SFField() const { return Bit(kSFShift); } |
| 434 inline Register RdField() const { return static_cast<Register>( |
| 435 Bits(kRdShift, kRdBits)); } |
| 436 inline Register RnField() const { return static_cast<Register>( |
| 437 Bits(kRnShift, kRnBits)); } |
| 438 inline Register RaField() const { return static_cast<Register>( |
| 439 Bits(kRaShift, kRaBits)); } |
| 440 inline Register RmField() const { return static_cast<Register>( |
| 441 Bits(kRmShift, kRmBits)); } |
| 442 |
| 443 // Immediates |
| 444 inline int Imm3Field() const { return Bits(kImm3Shift, kImm3Bits); } |
| 445 inline int Imm6Field() const { return Bits(kImm6Shift, kImm6Bits); } |
| 446 inline int Imm12Field() const { return Bits(kImm12Shift, kImm12Bits); } |
| 447 inline int Imm16Field() const { return Bits(kImm16Shift, kImm16Bits); } |
| 448 |
| 449 inline int Imm12ShiftField() const { |
| 450 return Bits(kImm12ShiftShift, kImm12ShiftBits); } |
| 451 |
| 452 // Shift and Extend. |
| 453 inline bool IsShift() const { return (Bit(kShiftExtendShift) == 0); } |
| 454 inline bool IsExtend() const { return (Bit(kShiftExtendShift) == 1); } |
| 455 inline Shift ShiftTypeField() const { |
| 456 return static_cast<Shift>(Bits(kShiftTypeShift, kShiftTypeBits)); } |
| 457 inline Extend ExtendTypeField() const { |
| 458 return static_cast<Extend>(Bits(kExtendTypeShift, kExtendTypeBits)); } |
| 459 inline int ShiftAmountField() const { return Imm6Field(); } |
| 460 inline int ExtShiftAmountField() const { return Imm3Field(); } |
| 461 |
| 462 // Instruction identification. |
| 463 #define IS_OP(op) \ |
| 464 inline bool Is##op##Op() const { \ |
| 465 return ((InstructionBits() & op##Mask) == (op##Fixed & op##Mask)); } |
| 466 APPLY_OP_LIST(IS_OP) |
| 467 #undef IS_OP |
| 468 |
| 469 inline bool HasS() const { return (SField() == 1); } |
| 470 |
| 471 // Indicate whether Rd can be the SP or ZR. This does not check that the |
| 472 // instruction actually has an Rd field. |
| 473 R31Type RdMode() const { |
| 474 // The following instructions use SP as Rd: |
| 475 // Add/sub (immediate) when not setting the flags. |
| 476 // Add/sub (extended) when not setting the flags. |
| 477 // Logical (immediate) when not setting the flags. |
| 478 // Otherwise, R31 is the ZR. |
| 479 if (IsAddSubImmOp() || (IsAddSubShiftExtOp() && IsExtend())) { |
| 480 if (HasS()) { |
| 481 return R31IsZR; |
| 482 } else { |
| 483 return R31IsSP; |
| 484 } |
| 485 } |
| 486 // TODO(zra): Handle for logical immediate operations. |
| 487 return R31IsZR; |
| 488 } |
| 489 |
| 490 // Indicate whether Rn can be SP or ZR. This does not check that the |
| 491 // instruction actually has an Rn field. |
| 492 R31Type RnMode() const { |
| 493 // The following instructions use SP as Rn: |
| 494 // All loads and stores. |
| 495 // Add/sub (immediate). |
| 496 // Add/sub (extended). |
| 497 // Otherwise, r31 is ZR. |
| 498 if (IsLoadStoreOp() || |
| 499 IsAddSubImmOp() || |
| 500 (IsAddSubShiftExtOp() && IsExtend())) { |
| 501 return R31IsSP; |
| 502 } |
| 503 return R31IsZR; |
| 504 } |
| 505 |
| 506 // Instructions are read out of a code stream. The only way to get a |
| 507 // reference to an instruction is to convert a pointer. There is no way |
| 508 // to allocate or create instances of class Instr. |
| 509 // Use the At(pc) function to create references to Instr. |
| 510 static Instr* At(uword pc) { return reinterpret_cast<Instr*>(pc); } |
| 511 |
| 512 private: |
| 513 DISALLOW_ALLOCATION(); |
| 514 DISALLOW_IMPLICIT_CONSTRUCTORS(Instr); |
| 515 }; |
| 516 |
| 517 } // namespace dart |
| 518 |
| 519 #endif // VM_CONSTANTS_ARM64_H_ |
OLD | NEW |