Index: runtime/vm/constants_arm64.h |
=================================================================== |
--- runtime/vm/constants_arm64.h (revision 0) |
+++ runtime/vm/constants_arm64.h (revision 0) |
@@ -0,0 +1,519 @@ |
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+#ifndef VM_CONSTANTS_ARM64_H_ |
+#define VM_CONSTANTS_ARM64_H_ |
+ |
+#include "platform/assert.h" |
+ |
+namespace dart { |
+ |
+enum Register { |
+ kFirstFreeCpuRegister = 0, |
+ R0 = 0, |
+ R1 = 1, |
+ R2 = 2, |
+ R3 = 3, |
+ R4 = 4, |
+ R5 = 5, |
+ R6 = 6, |
+ R7 = 7, |
+ R8 = 8, |
+ R9 = 9, |
+ R10 = 10, |
+ R11 = 11, |
+ R12 = 12, |
+ R13 = 13, |
+ R14 = 14, |
+ R15 = 15, |
+ R16 = 16, |
+ R17 = 17, |
+ R18 = 18, |
+ R19 = 19, |
+ R20 = 20, |
+ R21 = 21, |
+ R22 = 22, |
+ R23 = 23, |
+ R24 = 24, |
+ kLastFreeCpuRegister = 24, |
+ R25 = 25, // IP0 |
+ R26 = 26, // IP1 |
+ R27 = 27, // PP |
+ R28 = 28, // CTX |
+ R29 = 29, // FP |
+ R30 = 30, // LR |
+ R31 = 31, // ZR, SP |
+ kNumberOfCpuRegisters = 32, |
+ kNoRegister = -1, |
+ |
+ // Aliases. |
+ IP0 = R25, |
+ IP1 = R26, |
+ FP = R29, |
+ LR = R30, |
+ |
+ // Left abstract so we can avoid misuse. |
+ SP, |
+ ZR, |
+}; |
+ |
+enum VRegister { |
+ V0 = 0, |
+ V1 = 1, |
+ V2 = 2, |
+ V3 = 3, |
+ V4 = 4, |
+ V5 = 5, |
+ V6 = 6, |
+ V7 = 7, |
+ V8 = 8, |
+ V9 = 9, |
+ V10 = 10, |
+ V11 = 11, |
+ V12 = 12, |
+ V13 = 13, |
+ V14 = 14, |
+ V15 = 15, |
+ V16 = 16, |
+ V17 = 17, |
+ V18 = 18, |
+ V19 = 19, |
+ V20 = 20, |
+ V21 = 21, |
+ V22 = 22, |
+ V23 = 24, |
+ V24 = 24, |
+ V25 = 25, |
+ V26 = 26, |
+ V27 = 27, |
+ V28 = 28, |
+ V29 = 29, |
+ V30 = 30, |
+ V31 = 31, |
+ kNumberOfVRegisters = 32, |
+ kNoVRegister = -1, |
+}; |
+ |
+// Register alias for floating point scratch register. |
+const VRegister VTMP0 = V30; |
+const VRegister VTMP1 = V31; |
+ |
+// Architecture independent aliases. |
+typedef VRegister FpuRegister; |
+const FpuRegister FpuTMP = VTMP0; |
+const int kNumberOfFpuRegisters = kNumberOfVRegisters; |
+const FpuRegister kNoFpuRegister = kNoVRegister; |
+ |
+// Register aliases. |
+const Register TMP = R25; // Used as scratch register by assembler. |
+const Register TMP0 = R25; |
+const Register TMP1 = R26; |
+const Register CTX = R27; // Caches current context in generated code. |
+const Register PP = R26; // Caches object pool pointer in generated code. |
+const Register SPREG = R31; // Stack pointer register. |
+const Register FPREG = FP; // Frame pointer register. |
+const Register ICREG = R5; // IC data register. |
+ |
+// Exception object is passed in this register to the catch handlers when an |
+// exception is thrown. |
+const Register kExceptionObjectReg = R0; |
+ |
+// Stack trace object is passed in this register to the catch handlers when |
+// an exception is thrown. |
+const Register kStackTraceObjectReg = R1; |
+ |
+// Masks, sizes, etc. |
+const int kXRegSizeInBits = 64; |
+const int kWRegSizeInBits = 32; |
+const int64_t kXRegMask = 0xffffffffffffffffL; |
+const int64_t kWRegMask = 0x00000000ffffffffL; |
+ |
+// List of registers used in load/store multiple. |
+typedef uint32_t RegList; |
+const RegList kAllCpuRegistersList = 0xFFFF; |
+ |
+ |
+// C++ ABI call registers. |
+const RegList kAbiArgumentCpuRegs = |
+ (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) | |
+ (1 << R4) | (1 << R5) | (1 << R6) | (1 << R7); |
+const RegList kAbiPreservedCpuRegs = |
+ (1 << R19) | (1 << R20) | (1 << R21) | (1 << R22) | |
+ (1 << R23) | (1 << R24) | (1 << R25) | (1 << R26) | |
+ (1 << R27) | (1 << R28) | (1 << R29); |
+const int kAbiPreservedCpuRegCount = 11; |
+const VRegister kAbiFirstPreservedFpuReg = V8; |
+const VRegister kAbiLastPreservedFpuReg = V15; |
+const int kAbiPreservedFpuRegCount = 8; |
+ |
+// CPU registers available to Dart allocator. |
+const RegList kDartAvailableCpuRegs = |
+ (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) | |
+ (1 << R4) | (1 << R5) | (1 << R6) | (1 << R7) | |
+ (1 << R8) | (1 << R9) | (1 << R10) | (1 << R11) | |
+ (1 << R12) | (1 << R13) | (1 << R14) | (1 << R15) | |
+ (1 << R16) | (1 << R17) | (1 << R18) | (1 << R19) | |
+ (1 << R20) | (1 << R21) | (1 << R22) | (1 << R23) | |
+ (1 << R24); |
+ |
+// Registers available to Dart that are not preserved by runtime calls. |
+const RegList kDartVolatileCpuRegs = |
+ kDartAvailableCpuRegs & ~kAbiPreservedCpuRegs; |
+const int kDartVolatileCpuRegCount = 19; |
+const VRegister kDartFirstVolatileFpuReg = V0; |
+const VRegister kDartLastVolatileFpuReg = V7; |
+const int kDartVolatileFpuRegCount = 8; |
+ |
+static inline Register ConcreteRegister(Register r) { |
+ return ((r == ZR) || (r == SP)) ? R31 : r; |
+} |
+ |
+// Values for the condition field as defined in section A3.2. |
+enum Condition { |
+ kNoCondition = -1, |
+ EQ = 0, // equal |
+ NE = 1, // not equal |
+ CS = 2, // carry set/unsigned higher or same |
+ CC = 3, // carry clear/unsigned lower |
+ MI = 4, // minus/negative |
+ PL = 5, // plus/positive or zero |
+ VS = 6, // overflow |
+ VC = 7, // no overflow |
+ HI = 8, // unsigned higher |
+ LS = 9, // unsigned lower or same |
+ GE = 10, // signed greater than or equal |
+ LT = 11, // signed less than |
+ GT = 12, // signed greater than |
+ LE = 13, // signed less than or equal |
+ AL = 14, // always (unconditional) |
+ NV = 15, // special condition (refer to section C1.2.3) |
+ kMaxCondition = 16, |
+}; |
+ |
+enum Bits { |
+ B0 = (1 << 0), B1 = (1 << 1), B2 = (1 << 2), B3 = (1 << 3), |
+ B4 = (1 << 4), B5 = (1 << 5), B6 = (1 << 6), B7 = (1 << 7), |
+ B8 = (1 << 8), B9 = (1 << 9), B10 = (1 << 10), B11 = (1 << 11), |
+ B12 = (1 << 12), B13 = (1 << 13), B14 = (1 << 14), B15 = (1 << 15), |
+ B16 = (1 << 16), B17 = (1 << 17), B18 = (1 << 18), B19 = (1 << 19), |
+ B20 = (1 << 20), B21 = (1 << 21), B22 = (1 << 22), B23 = (1 << 23), |
+ B24 = (1 << 24), B25 = (1 << 25), B26 = (1 << 26), B27 = (1 << 27), |
+ B28 = (1 << 28), B29 = (1 << 29), B30 = (1 << 30), B31 = (1 << 31), |
+}; |
+ |
+enum OperandSize { |
+ kByte, |
+ kUnsignedByte, |
+ kHalfword, |
+ kUnsignedHalfword, |
+ kWord, |
+ kUnsignedWord, |
+ kDoubleWord, |
+ kSWord, |
+ kDWord, |
+}; |
+ |
+// Opcodes from C3 |
+// C3.1. |
+enum MainOp { |
+ DPImmediateMask = 0x1c000000, |
+ DPImmediateFixed = B28, |
+ |
+ CompareBranchMask = 0x1c000000, |
+ CompareBranchFixed = B28 | B26, |
+ |
+ LoadStoreMask = B27 | B25, |
+ LoadStoreFixed = B27, |
+ |
+ DPRegisterMask = 0x0e000000, |
+ DPRegisterFixed = B27 | B25, |
+ |
+ DPSimd1Mask = 0x1e000000, |
+ DPSimd1Fixed = B27 | B26 | B25, |
+ |
+ DPSimd2Mask = 0x1e000000, |
+ DPSimd2Fixed = B28 | DPSimd1Fixed, |
+}; |
+ |
+// C3.2.3 |
+enum ExceptionGenOp { |
+ ExceptionGenMask = 0xff000000, |
+ ExceptionGenFixed = CompareBranchFixed | B31 | B30, |
+ SVC = ExceptionGenFixed | B0, |
+ BRK = ExceptionGenFixed | B21, |
+ HLT = ExceptionGenFixed | B22, |
+}; |
+ |
+// C3.2.4 |
+enum SystemOp { |
+ SystemMask = 0xffc00000, |
+ SystemFixed = CompareBranchFixed | B31 | B30 | B24, |
+ HINT = SystemFixed | B17 | B16 | B13 | B4 | B3 | B2 | B1 | B0, |
+}; |
+ |
+// C3.2.7 |
+enum UnconditionalBranchRegOp { |
+ UnconditionalBranchRegMask = 0xfe000000, |
+ UnconditionalBranchRegFixed = CompareBranchFixed | B31 | B30 | B25, |
+ BR = UnconditionalBranchRegFixed | B20 | B19 | B18 | B17 | B16, |
+ BLR = BR | B21, |
+ RET = BR | B22, |
+}; |
+ |
+// C3.4.1 |
+enum AddSubImmOp { |
+ AddSubImmMask = 0x1f000000, |
+ AddSubImmFixed = DPImmediateFixed | B24, |
+ ADDI = AddSubImmFixed, |
+ SUBI = AddSubImmFixed | B30, |
+}; |
+ |
+// C3.4.5 |
+enum MoveWideOp { |
+ MoveWideMask = 0x1f800000, |
+ MoveWideFixed = DPImmediateFixed | B25 | B23, |
+ MOVN = MoveWideFixed, |
+ MOVZ = MoveWideFixed | B30, |
+ MOVK = MoveWideFixed | B30 | B29, |
+}; |
+ |
+ |
+// C3.5.1 |
+enum AddSubShiftExtOp { |
+ AddSubShiftExtMask = 0x1f200000, |
+ AddSubShiftExtFixed = DPRegisterFixed | B24, |
+ ADD = AddSubShiftExtFixed, |
+ SUB = AddSubShiftExtFixed | B30, |
+}; |
+ |
+#define APPLY_OP_LIST(_V) \ |
+_V(DPImmediate) \ |
+_V(CompareBranch) \ |
+_V(LoadStore) \ |
+_V(DPRegister) \ |
+_V(DPSimd1) \ |
+_V(DPSimd2) \ |
+_V(ExceptionGen) \ |
+_V(System) \ |
+_V(UnconditionalBranchReg) \ |
+_V(AddSubImm) \ |
+_V(MoveWide) \ |
+_V(AddSubShiftExt) \ |
+ |
+ |
+enum Shift { |
+ kNoShift = -1, |
+ LSL = 0, // Logical shift left |
+ LSR = 1, // Logical shift right |
+ ASR = 2, // Arithmetic shift right |
+ ROR = 3, // Rotate right |
+ kMaxShift = 4, |
+}; |
+ |
+enum Extend { |
+ kNoExtend = -1, |
+ UXTB = 0, |
+ UXTH = 1, |
+ UXTW = 2, |
+ UXTX = 3, |
+ SXTB = 4, |
+ SXTH = 5, |
+ SXTW = 6, |
+ SXTX = 7, |
+ kMaxExtend = 8, |
+}; |
+ |
+enum R31Type { |
+ R31IsSP, |
+ R31IsZR, |
+ R31IsUndef, |
+}; |
+ |
+// Constants used for the decoding or encoding of the individual fields of |
+// instructions. Based on the "Figure 3-1 ARM instruction set summary". |
+enum InstructionFields { |
+ // S-bit (modify condition register) |
+ kSShift = 29, |
+ kSBits = 1, |
+ |
+ // sf field. |
+ kSFShift = 31, |
+ kSFBits = 1, |
+ |
+ // Registers. |
+ kRdShift = 0, |
+ kRdBits = 5, |
+ kRnShift = 5, |
+ kRnBits = 5, |
+ kRaShift = 10, |
+ kRaBits = 5, |
+ kRmShift = 16, |
+ kRmBits = 5, |
+ |
+ // Immediates. |
+ kImm3Shift = 10, |
+ kImm3Bits = 3, |
+ kImm6Shift = 10, |
+ kImm6Bits = 6, |
+ kImm12Shift = 10, |
+ kImm12Bits = 12, |
+ kImm12ShiftShift = 22, |
+ kImm12ShiftBits = 2, |
+ kImm16Shift = 5, |
+ kImm16Bits = 16, |
+ |
+ // Shift and Extend. |
+ kShiftExtendShift = 21, |
+ kShiftExtendBits = 1, |
+ kShiftTypeShift = 22, |
+ kShiftTypeBits = 2, |
+ kExtendTypeShift = 13, |
+ kExtendTypeBits = 3, |
+ |
+ // Hint Fields. |
+ kHintCRmShift = 8, |
+ kHintCRmBits = 4, |
+ kHintOp2Shift = 5, |
+ kHintOp2Bits = 3, |
+}; |
+ |
+ |
+const uint32_t kImmExceptionIsRedirectedCall = 0xca11; |
+const uint32_t kImmExceptionIsUnreachable = 0xdebf; |
+const uint32_t kImmExceptionIsPrintf = 0xdeb1; |
+const uint32_t kImmExceptionIsDebug = 0xdeb0; |
+ |
+// The class Instr enables access to individual fields defined in the ARM |
+// architecture instruction set encoding as described in figure A3-1. |
+// |
+// Example: Test whether the instruction at ptr sets the condition code bits. |
+// |
+// bool InstructionSetsConditionCodes(byte* ptr) { |
+// Instr* instr = Instr::At(ptr); |
+// int type = instr->TypeField(); |
+// return ((type == 0) || (type == 1)) && instr->HasS(); |
+// } |
+// |
+class Instr { |
+ public: |
+ enum { |
+ kInstrSize = 4, |
+ kInstrSizeLog2 = 2, |
+ kPCReadOffset = 8 |
+ }; |
+ |
+ static const int32_t kNopInstruction = HINT; // hint #0 === nop. |
+ static const int32_t kBreakPointInstruction = // hlt #kImmExceptionIsDebug. |
+ HLT | (kImmExceptionIsDebug << kImm16Shift); |
+ static const int kBreakPointInstructionSize = kInstrSize; |
+ |
+ // Get the raw instruction bits. |
+ inline int32_t InstructionBits() const { |
+ return *reinterpret_cast<const int32_t*>(this); |
+ } |
+ |
+ // Set the raw instruction bits to value. |
+ inline void SetInstructionBits(int32_t value) { |
+ *reinterpret_cast<int32_t*>(this) = value; |
+ } |
+ |
+ // Read one particular bit out of the instruction bits. |
+ inline int Bit(int nr) const { |
+ return (InstructionBits() >> nr) & 1; |
+ } |
+ |
+ // Read a bit field out of the instruction bits. |
+ inline int Bits(int shift, int count) const { |
+ return (InstructionBits() >> shift) & ((1 << count) - 1); |
+ } |
+ |
+ |
+ inline int SField() const { return Bit(kSShift); } |
+ inline int SFField() const { return Bit(kSFShift); } |
+ inline Register RdField() const { return static_cast<Register>( |
+ Bits(kRdShift, kRdBits)); } |
+ inline Register RnField() const { return static_cast<Register>( |
+ Bits(kRnShift, kRnBits)); } |
+ inline Register RaField() const { return static_cast<Register>( |
+ Bits(kRaShift, kRaBits)); } |
+ inline Register RmField() const { return static_cast<Register>( |
+ Bits(kRmShift, kRmBits)); } |
+ |
+ // Immediates |
+ inline int Imm3Field() const { return Bits(kImm3Shift, kImm3Bits); } |
+ inline int Imm6Field() const { return Bits(kImm6Shift, kImm6Bits); } |
+ inline int Imm12Field() const { return Bits(kImm12Shift, kImm12Bits); } |
+ inline int Imm16Field() const { return Bits(kImm16Shift, kImm16Bits); } |
+ |
+ inline int Imm12ShiftField() const { |
+ return Bits(kImm12ShiftShift, kImm12ShiftBits); } |
+ |
+ // Shift and Extend. |
+ inline bool IsShift() const { return (Bit(kShiftExtendShift) == 0); } |
+ inline bool IsExtend() const { return (Bit(kShiftExtendShift) == 1); } |
+ inline Shift ShiftTypeField() const { |
+ return static_cast<Shift>(Bits(kShiftTypeShift, kShiftTypeBits)); } |
+ inline Extend ExtendTypeField() const { |
+ return static_cast<Extend>(Bits(kExtendTypeShift, kExtendTypeBits)); } |
+ inline int ShiftAmountField() const { return Imm6Field(); } |
+ inline int ExtShiftAmountField() const { return Imm3Field(); } |
+ |
+ // Instruction identification. |
+ #define IS_OP(op) \ |
+ inline bool Is##op##Op() const { \ |
+ return ((InstructionBits() & op##Mask) == (op##Fixed & op##Mask)); } |
+ APPLY_OP_LIST(IS_OP) |
+ #undef IS_OP |
+ |
+ inline bool HasS() const { return (SField() == 1); } |
+ |
+ // Indicate whether Rd can be the SP or ZR. This does not check that the |
+ // instruction actually has an Rd field. |
+ R31Type RdMode() const { |
+ // The following instructions use SP as Rd: |
+ // Add/sub (immediate) when not setting the flags. |
+ // Add/sub (extended) when not setting the flags. |
+ // Logical (immediate) when not setting the flags. |
+ // Otherwise, R31 is the ZR. |
+ if (IsAddSubImmOp() || (IsAddSubShiftExtOp() && IsExtend())) { |
+ if (HasS()) { |
+ return R31IsZR; |
+ } else { |
+ return R31IsSP; |
+ } |
+ } |
+ // TODO(zra): Handle for logical immediate operations. |
+ return R31IsZR; |
+ } |
+ |
+ // Indicate whether Rn can be SP or ZR. This does not check that the |
+ // instruction actually has an Rn field. |
+ R31Type RnMode() const { |
+ // The following instructions use SP as Rn: |
+ // All loads and stores. |
+ // Add/sub (immediate). |
+ // Add/sub (extended). |
+ // Otherwise, r31 is ZR. |
+ if (IsLoadStoreOp() || |
+ IsAddSubImmOp() || |
+ (IsAddSubShiftExtOp() && IsExtend())) { |
+ return R31IsSP; |
+ } |
+ return R31IsZR; |
+ } |
+ |
+ // Instructions are read out of a code stream. The only way to get a |
+ // reference to an instruction is to convert a pointer. There is no way |
+ // to allocate or create instances of class Instr. |
+ // Use the At(pc) function to create references to Instr. |
+ static Instr* At(uword pc) { return reinterpret_cast<Instr*>(pc); } |
+ |
+ private: |
+ DISALLOW_ALLOCATION(); |
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Instr); |
+}; |
+ |
+} // namespace dart |
+ |
+#endif // VM_CONSTANTS_ARM64_H_ |