// Copyright (c) 2013, 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 RUNTIME_VM_CONSTANTS_ARM_H_ #define RUNTIME_VM_CONSTANTS_ARM_H_ #ifndef RUNTIME_VM_CONSTANTS_H_ #error Do not include constants_arm.h directly; use constants.h instead. #endif #include "platform/assert.h" #include "platform/globals.h" #include "vm/constants_base.h" namespace dart { // LR register should not be used directly in handwritten assembly patterns, // because it might contain return address. Instead use macross CLOBBERS_LR, // SPILLS_RETURN_ADDRESS_FROM_LR_TO_REGISTER, // RESTORES_RETURN_ADDRESS_FROM_REGISTER_TO_LR, SPILLS_LR_TO_FRAME, // RESTORES_LR_FROM_FRAME, READS_RETURN_ADDRESS_FROM_LR, // WRITES_RETURN_ADDRESS_TO_LR to get access to LR constant in a checked way. // // To prevent accidental use of LR constant we rename it to // LR_DO_NOT_USE_DIRECTLY (while keeping the code in this file and other files // which are permitted to access LR constant the same by defining LR as // LR_DO_NOT_USE_DIRECTLY). You can also use LINK_REGISTER if you need // to compare LR register code. #define LR LR_DO_NOT_USE_DIRECTLY // We support both VFPv3-D16 and VFPv3-D32 profiles, but currently only one at // a time. #if defined(__ARM_ARCH_7A__) #define VFPv3_D32 #elif defined(TARGET_ARCH_ARM) && !defined(HOST_ARCH_ARM) // If we're running in the simulator, use all 32. #define VFPv3_D32 #else #define VFPv3_D16 #endif #if defined(VFPv3_D16) == defined(VFPv3_D32) #error "Exactly one of VFPv3_D16 or VFPv3_D32 can be defined at a time." #endif // The Linux/Android ABI and the iOS ABI differ in their choice of frame // pointer, their treatment of R9, and the interprocedural stack alignment. // EABI (Linux, Android) // See "Procedure Call Standard for the ARM Architecture". // R0-R1: Argument / result / volatile // R2-R3: Argument / volatile // R4-R10: Preserved // R11: Frame pointer // R12: Volatile // R13: Stack pointer // R14: Link register // R15: Program counter // Stack alignment: 4 bytes always, 8 bytes at public interfaces // Linux (Debian armhf) and Android also differ in whether floating point // arguments are passed in floating point registers. Linux uses hardfp and // Android uses softfp. See TargetCPUFeatures::hardfp_supported(). // iOS ABI // See "iOS ABI Function Call Guide" // R0-R1: Argument / result / volatile // R2-R3: Argument / volatile // R4-R6: Preserved // R7: Frame pointer // R8-R11: Preserved // R12: Volatile // R13: Stack pointer // R14: Link register // R15: Program counter // Stack alignment: 4 bytes always, 4 bytes at public interfaces // iOS passes floating point arguments in integer registers (softfp) enum Register { R0 = 0, R1 = 1, R2 = 2, R3 = 3, R4 = 4, R5 = 5, // PP R6 = 6, // CODE R7 = 7, // iOS FP R8 = 8, R9 = 9, R10 = 10, // THR R11 = 11, // Linux FP R12 = 12, // IP aka TMP R13 = 13, // SP R14 = 14, // LR R15 = 15, // PC kNumberOfCpuRegisters = 16, kNoRegister = -1, // Signals an illegal register. // Aliases. #if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS) FP = R7, NOTFP = R11, #else FP = R11, NOTFP = R7, #endif IP = R12, SP = R13, LR = R14, // Note: direct access to this constant is not allowed. See above. PC = R15, }; // Values for single-precision floating point registers. enum SRegister { kNoSRegister = -1, S0 = 0, S1 = 1, S2 = 2, S3 = 3, S4 = 4, S5 = 5, S6 = 6, S7 = 7, S8 = 8, S9 = 9, S10 = 10, S11 = 11, S12 = 12, S13 = 13, S14 = 14, S15 = 15, S16 = 16, S17 = 17, S18 = 18, S19 = 19, S20 = 20, S21 = 21, S22 = 22, S23 = 23, S24 = 24, S25 = 25, S26 = 26, S27 = 27, S28 = 28, S29 = 29, S30 = 30, S31 = 31, kNumberOfSRegisters = 32, }; // Values for double-precision floating point registers. enum DRegister { kNoDRegister = -1, D0 = 0, D1 = 1, D2 = 2, D3 = 3, D4 = 4, D5 = 5, D6 = 6, D7 = 7, D8 = 8, D9 = 9, D10 = 10, D11 = 11, D12 = 12, D13 = 13, D14 = 14, D15 = 15, #if defined(VFPv3_D16) kNumberOfDRegisters = 16, // Leaving these defined, but marking them as kNoDRegister to avoid polluting // other parts of the code with #ifdef's. Instead, query kNumberOfDRegisters // to see which registers are valid. D16 = kNoDRegister, D17 = kNoDRegister, D18 = kNoDRegister, D19 = kNoDRegister, D20 = kNoDRegister, D21 = kNoDRegister, D22 = kNoDRegister, D23 = kNoDRegister, D24 = kNoDRegister, D25 = kNoDRegister, D26 = kNoDRegister, D27 = kNoDRegister, D28 = kNoDRegister, D29 = kNoDRegister, D30 = kNoDRegister, D31 = kNoDRegister, #else D16 = 16, D17 = 17, D18 = 18, D19 = 19, D20 = 20, D21 = 21, D22 = 22, D23 = 23, D24 = 24, D25 = 25, D26 = 26, D27 = 27, D28 = 28, D29 = 29, D30 = 30, D31 = 31, kNumberOfDRegisters = 32, #endif kNumberOfOverlappingDRegisters = 16, }; enum QRegister { kNoQRegister = -1, Q0 = 0, Q1 = 1, Q2 = 2, Q3 = 3, Q4 = 4, Q5 = 5, Q6 = 6, Q7 = 7, #if defined(VFPv3_D16) kNumberOfQRegisters = 8, Q8 = kNoQRegister, Q9 = kNoQRegister, Q10 = kNoQRegister, Q11 = kNoQRegister, Q12 = kNoQRegister, Q13 = kNoQRegister, Q14 = kNoQRegister, Q15 = kNoQRegister, #else Q8 = 8, Q9 = 9, Q10 = 10, Q11 = 11, Q12 = 12, Q13 = 13, Q14 = 14, Q15 = 15, kNumberOfQRegisters = 16, #endif }; static inline DRegister EvenDRegisterOf(QRegister q) { return static_cast(q * 2); } static inline DRegister OddDRegisterOf(QRegister q) { return static_cast((q * 2) + 1); } static inline SRegister EvenSRegisterOf(DRegister d) { #if defined(VFPv3_D32) // When we have 32 D registers, the S registers only overlap the first 16. // That is, there are only 32 S registers. ASSERT(d < D16); #endif return static_cast(d * 2); } static inline SRegister OddSRegisterOf(DRegister d) { #if defined(VFPv3_D32) ASSERT(d < D16); #endif return static_cast((d * 2) + 1); } static inline QRegister QRegisterOf(DRegister d) { return static_cast(d / 2); } static inline QRegister QRegisterOf(SRegister s) { return static_cast(s / 4); } static inline DRegister DRegisterOf(SRegister s) { return static_cast(s / 2); } // Register aliases for floating point scratch registers. const QRegister QTMP = Q7; // Overlaps with DTMP, STMP. const DRegister DTMP = EvenDRegisterOf(QTMP); // Overlaps with STMP. const SRegister STMP DART_USED = EvenSRegisterOf(DTMP); // Architecture independent aliases. typedef QRegister FpuRegister; const FpuRegister FpuTMP = QTMP; const int kNumberOfFpuRegisters = kNumberOfQRegisters; const FpuRegister kNoFpuRegister = kNoQRegister; extern const char* cpu_reg_names[kNumberOfCpuRegisters]; extern const char* fpu_reg_names[kNumberOfFpuRegisters]; extern const char* fpu_s_reg_names[kNumberOfSRegisters]; extern const char* fpu_d_reg_names[kNumberOfDRegisters]; // Register aliases. const Register TMP = IP; // Used as scratch register by assembler. const Register TMP2 = kNoRegister; // There is no second assembler temporary. const Register PP = R5; // Caches object pool pointer in generated code. const Register DISPATCH_TABLE_REG = NOTFP; // Dispatch table register. const Register SPREG = SP; // Stack pointer register. const Register FPREG = FP; // Frame pointer register. const Register ARGS_DESC_REG = R4; const Register CODE_REG = R6; const Register THR = R10; // Caches current thread in generated code. const Register CALLEE_SAVED_TEMP = R8; // R15 encodes APSR in the vmrs instruction. const Register APSR = R15; // ABI for catch-clause entry point. const Register kExceptionObjectReg = R0; const Register kStackTraceObjectReg = R1; // ABI for write barrier stub. const Register kWriteBarrierObjectReg = R1; const Register kWriteBarrierValueReg = R0; const Register kWriteBarrierSlotReg = R9; // ABI for allocation stubs. const Register kAllocationStubTypeArgumentsReg = R3; // Common ABI for shared slow path stubs. struct SharedSlowPathStubABI { static const Register kResultReg = R0; }; // ABI for instantiation stubs. struct InstantiationABI { static const Register kUninstantiatedTypeArgumentsReg = R3; static const Register kInstantiatorTypeArgumentsReg = R2; static const Register kFunctionTypeArgumentsReg = R1; static const Register kResultTypeArgumentsReg = R0; static const Register kResultTypeReg = R0; }; // Registers in addition to those listed in TypeTestABI used inside the // implementation of type testing stubs that are _not_ preserved. struct TTSInternalRegs { static const Register kInstanceTypeArgumentsReg = R4; static const Register kScratchReg = R9; static const intptr_t kInternalRegisters = (1 << kInstanceTypeArgumentsReg) | (1 << kScratchReg); }; // Registers in addition to those listed in TypeTestABI used inside the // implementation of subtype test cache stubs that are _not_ preserved. struct STCInternalRegs { static const Register kInstanceCidOrFunctionReg = R9; static const intptr_t kInternalRegisters = (1 << kInstanceCidOrFunctionReg); }; // Calling convention when calling TypeTestingStub and SubtypeTestCacheStub. struct TypeTestABI { static const Register kInstanceReg = R0; static const Register kDstTypeReg = R8; static const Register kInstantiatorTypeArgumentsReg = R2; static const Register kFunctionTypeArgumentsReg = R1; static const Register kSubtypeTestCacheReg = R3; static const Register kScratchReg = R4; // For calls to InstanceOfStub. static const Register kInstanceOfResultReg = kInstanceReg; // For calls to SubtypeNTestCacheStub. Must be saved by the caller if the // original value is needed after the call. static const Register kSubtypeTestCacheResultReg = kSubtypeTestCacheReg; // Registers that need saving across SubtypeTestCacheStub calls. static const intptr_t kSubtypeTestCacheStubCallerSavedRegisters = 1 << kSubtypeTestCacheReg; static const intptr_t kPreservedAbiRegisters = (1 << kInstanceReg) | (1 << kDstTypeReg) | (1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg); static const intptr_t kNonPreservedAbiRegisters = TTSInternalRegs::kInternalRegisters | STCInternalRegs::kInternalRegisters | (1 << kSubtypeTestCacheReg) | (1 << kScratchReg) | (1 << kSubtypeTestCacheResultReg) | (1 << CODE_REG); static const intptr_t kAbiRegisters = kPreservedAbiRegisters | kNonPreservedAbiRegisters; }; // Calling convention when calling AssertSubtypeStub. struct AssertSubtypeABI { static const Register kSubTypeReg = R0; static const Register kSuperTypeReg = R8; static const Register kInstantiatorTypeArgumentsReg = R2; static const Register kFunctionTypeArgumentsReg = R1; static const Register kDstNameReg = R3; static const intptr_t kAbiRegisters = (1 << kSubTypeReg) | (1 << kSuperTypeReg) | (1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg) | (1 << kDstNameReg); // No result register, as AssertSubtype is only run for side effect // (throws if the subtype check fails). }; // ABI for InitStaticFieldStub. struct InitStaticFieldABI { static const Register kFieldReg = R0; static const Register kResultReg = R0; }; // ABI for InitInstanceFieldStub. struct InitInstanceFieldABI { static const Register kInstanceReg = R1; static const Register kFieldReg = R2; static const Register kResultReg = R0; }; // Registers used inside the implementation of InitLateInstanceFieldStub. struct InitLateInstanceFieldInternalRegs { static const Register kFunctionReg = R0; static const Register kAddressReg = R3; static const Register kScratchReg = R4; }; // ABI for LateInitializationError stubs. struct LateInitializationErrorABI { static const Register kFieldReg = R9; }; // ABI for ThrowStub. struct ThrowABI { static const Register kExceptionReg = R0; }; // ABI for ReThrowStub. struct ReThrowABI { static const Register kExceptionReg = R0; static const Register kStackTraceReg = R1; }; // ABI for AssertBooleanStub. struct AssertBooleanABI { static const Register kObjectReg = R0; }; // ABI for RangeErrorStub. struct RangeErrorABI { static const Register kLengthReg = R0; static const Register kIndexReg = R1; }; // ABI for AllocateMint*Stub. struct AllocateMintABI { static const Register kResultReg = R0; static const Register kTempReg = R1; }; // ABI for AllocateArrayStub. struct AllocateTypedDataArrayABI { static const Register kLengthReg = R4; static const Register kResultReg = R0; }; // ABI for DispatchTableNullErrorStub and consequently for all dispatch // table calls (though normal functions will not expect or use this // register). This ABI is added to distinguish memory corruption errors from // null errors. struct DispatchTableNullErrorABI { static const Register kClassIdReg = R0; }; // TODO(regis): Add ABIs for type testing stubs and is-type test stubs instead // of reusing the constants of the instantiation stubs ABI. // List of registers used in load/store multiple. typedef uint16_t RegList; const RegList kAllCpuRegistersList = 0xFFFF; // C++ ABI call registers. const RegList kAbiArgumentCpuRegs = (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3); #if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS) const RegList kAbiPreservedCpuRegs = (1 << R4) | (1 << R5) | (1 << R6) | (1 << R8) | (1 << R10) | (1 << R11); const int kAbiPreservedCpuRegCount = 6; #else const RegList kAbiPreservedCpuRegs = (1 << R4) | (1 << R5) | (1 << R6) | (1 << R7) | (1 << R8) | (1 << R9) | (1 << R10); const int kAbiPreservedCpuRegCount = 7; #endif const QRegister kAbiFirstPreservedFpuReg = Q4; const QRegister kAbiLastPreservedFpuReg = Q7; const int kAbiPreservedFpuRegCount = 4; const RegList kReservedCpuRegisters = (1 << SPREG) | (1 << FPREG) | (1 << TMP) | (1 << PP) | (1 << THR) | (1 << LR) | (1 << PC) | (1 << NOTFP); constexpr intptr_t kNumberOfReservedCpuRegisters = 8; // CPU registers available to Dart allocator. constexpr RegList kDartAvailableCpuRegs = kAllCpuRegistersList & ~kReservedCpuRegisters; constexpr int kNumberOfDartAvailableCpuRegs = kNumberOfCpuRegisters - kNumberOfReservedCpuRegisters; const intptr_t kStoreBufferWrapperSize = 24; // Registers available to Dart that are not preserved by runtime calls. const RegList kDartVolatileCpuRegs = kDartAvailableCpuRegs & ~kAbiPreservedCpuRegs; #if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS) const int kDartVolatileCpuRegCount = 6; #else const int kDartVolatileCpuRegCount = 5; #endif const QRegister kDartFirstVolatileFpuReg = Q0; const QRegister kDartLastVolatileFpuReg = Q3; const int kDartVolatileFpuRegCount = 4; #define R(REG) (1 << REG) class CallingConventions { public: static const intptr_t kArgumentRegisters = kAbiArgumentCpuRegs; static const Register ArgumentRegisters[]; static const intptr_t kNumArgRegs = 4; static const Register kPointerToReturnStructRegisterCall = R0; static const intptr_t kFpuArgumentRegisters = 0; static const FpuRegister FpuArgumentRegisters[]; static const intptr_t kNumFpuArgRegs = 4; static const DRegister FpuDArgumentRegisters[]; static const intptr_t kNumDFpuArgRegs = 8; static const SRegister FpuSArgumentRegisters[]; static const intptr_t kNumSFpuArgRegs = 16; static constexpr bool kArgumentIntRegXorFpuReg = false; static constexpr intptr_t kCalleeSaveCpuRegisters = kAbiPreservedCpuRegs; // Whether larger than wordsize arguments are aligned to even registers. static constexpr AlignmentStrategy kArgumentRegisterAlignment = kAlignedToWordSizeBut8AlignedTo8; // How stack arguments are aligned. static constexpr AlignmentStrategy kArgumentStackAlignment = kAlignedToWordSizeBut8AlignedTo8; // How fields in compounds are aligned. #if defined(TARGET_OS_MACOS_IOS) static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSizeBut8AlignedTo4; #else static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize; #endif // Whether 1 or 2 byte-sized arguments or return values are passed extended // to 4 bytes. static constexpr ExtensionStrategy kReturnRegisterExtension = kExtendedTo4; static constexpr ExtensionStrategy kArgumentRegisterExtension = kExtendedTo4; static constexpr ExtensionStrategy kArgumentStackExtension = kExtendedTo4; static constexpr Register kReturnReg = R0; static constexpr Register kSecondReturnReg = R1; static constexpr FpuRegister kReturnFpuReg = Q0; static constexpr Register kPointerToReturnStructRegisterReturn = kReturnReg; // We choose these to avoid overlap between themselves and reserved registers. static constexpr Register kFirstNonArgumentRegister = R8; static constexpr Register kSecondNonArgumentRegister = R9; static constexpr Register kFfiAnyNonAbiRegister = R4; static constexpr Register kStackPointerRegister = SPREG; COMPILE_ASSERT( ((R(kFirstNonArgumentRegister) | R(kSecondNonArgumentRegister)) & (kArgumentRegisters | R(kPointerToReturnStructRegisterCall))) == 0); }; #undef 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) kSpecialCondition = 15, // special condition (refer to section A3.2.1) kNumberOfConditions = 16, // Platform-independent variants declared for all platforms EQUAL = EQ, ZERO = EQUAL, NOT_EQUAL = NE, NOT_ZERO = NOT_EQUAL, LESS = LT, LESS_EQUAL = LE, GREATER_EQUAL = GE, GREATER = GT, UNSIGNED_LESS = CC, UNSIGNED_LESS_EQUAL = LS, UNSIGNED_GREATER = HI, UNSIGNED_GREATER_EQUAL = CS, OVERFLOW = VS, NO_OVERFLOW = VC, kInvalidCondition = 16 }; static inline Condition InvertCondition(Condition c) { COMPILE_ASSERT((EQ ^ NE) == 1); COMPILE_ASSERT((CS ^ CC) == 1); COMPILE_ASSERT((MI ^ PL) == 1); COMPILE_ASSERT((VS ^ VC) == 1); COMPILE_ASSERT((HI ^ LS) == 1); COMPILE_ASSERT((GE ^ LT) == 1); COMPILE_ASSERT((GT ^ LE) == 1); ASSERT(c != AL); ASSERT(c != kSpecialCondition); ASSERT(c != kInvalidCondition); return static_cast(c ^ 1); } // Opcodes for Data-processing instructions (instructions with a type 0 and 1) // as defined in section A3.4 enum Opcode { kNoOperand = -1, AND = 0, // Logical AND EOR = 1, // Logical Exclusive OR SUB = 2, // Subtract RSB = 3, // Reverse Subtract ADD = 4, // Add ADC = 5, // Add with Carry SBC = 6, // Subtract with Carry RSC = 7, // Reverse Subtract with Carry TST = 8, // Test TEQ = 9, // Test Equivalence CMP = 10, // Compare CMN = 11, // Compare Negated ORR = 12, // Logical (inclusive) OR MOV = 13, // Move BIC = 14, // Bit Clear MVN = 15, // Move Not kMaxOperand = 16 }; // Shifter types for Data-processing operands as defined in section A5.1.2. 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 }; // 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 { kConditionShift = 28, kConditionBits = 4, kTypeShift = 25, kTypeBits = 3, kLinkShift = 24, kLinkBits = 1, kUShift = 23, kUBits = 1, kOpcodeShift = 21, kOpcodeBits = 4, kSShift = 20, kSBits = 1, kRnShift = 16, kRnBits = 4, kRdShift = 12, kRdBits = 4, kRsShift = 8, kRsBits = 4, kRmShift = 0, kRmBits = 4, // Immediate instruction fields encoding. kRotateShift = 8, kRotateBits = 4, kImmed8Shift = 0, kImmed8Bits = 8, // Shift instruction register fields encodings. kShiftImmShift = 7, kShiftRegisterShift = 8, kShiftImmBits = 5, kShiftShift = 5, kShiftBits = 2, // Load/store instruction offset field encoding. kOffset12Shift = 0, kOffset12Bits = 12, kOffset12Mask = 0x00000fff, // Mul instruction register field encodings. kMulRdShift = 16, kMulRdBits = 4, kMulRnShift = 12, kMulRnBits = 4, // Div instruction register field encodings. kDivRdShift = 16, kDivRdBits = 4, kDivRmShift = 8, kDivRmBits = 4, kDivRnShift = 0, kDivRnBits = 4, // ldrex/strex register field encodings. kLdExRnShift = 16, kLdExRtShift = 12, kStrExRnShift = 16, kStrExRdShift = 12, kStrExRtShift = 0, // MRC instruction offset field encoding. kCRmShift = 0, kCRmBits = 4, kOpc2Shift = 5, kOpc2Bits = 3, kCoprocShift = 8, kCoprocBits = 4, kCRnShift = 16, kCRnBits = 4, kOpc1Shift = 21, kOpc1Bits = 3, kBranchOffsetMask = 0x00ffffff }; enum ScaleFactor { TIMES_1 = 0, TIMES_2 = 1, TIMES_4 = 2, TIMES_8 = 3, TIMES_16 = 4, // Don't use (dart::)kWordSizeLog2, as this needs to work for crossword as // well. If this is included, we know the target is 32 bit. #if defined(TARGET_ARCH_IS_32_BIT) // Used for Smi-boxed indices. TIMES_HALF_WORD_SIZE = kInt32SizeLog2 - 1, // Used for unboxed indices. TIMES_WORD_SIZE = kInt32SizeLog2, #else #error "Unexpected word size" #endif #if !defined(DART_COMPRESSED_POINTERS) TIMES_COMPRESSED_WORD_SIZE = TIMES_WORD_SIZE, #else #error Cannot compress ARM32 #endif }; // 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 = // nop ((AL << kConditionShift) | (0x32 << 20) | (0xf << 12)); static const int32_t kBreakPointCode = 0xdeb0; // For breakpoint. static const int32_t kSimulatorBreakCode = 0xdeb2; // For breakpoint in sim. static const int32_t kSimulatorRedirectCode = 0xca11; // For redirection. // Breakpoint instruction filling assembler code buffers in debug mode. static const int32_t kBreakPointInstruction = // bkpt(0xdeb0) ((AL << kConditionShift) | (0x12 << 20) | (0xdeb << 8) | (0x7 << 4)); // Breakpoint instruction used by the simulator. // Should be distinct from kBreakPointInstruction and from a typical user // breakpoint inserted in generated code for debugging, e.g. bkpt(0). static const int32_t kSimulatorBreakpointInstruction = // svc #kBreakpointSvcCode ((AL << kConditionShift) | (0xf << 24) | kSimulatorBreakCode); // Runtime call redirection instruction used by the simulator. static const int32_t kSimulatorRedirectInstruction = ((AL << kConditionShift) | (0xf << 24) | kSimulatorRedirectCode); // Get the raw instruction bits. inline int32_t InstructionBits() const { return *reinterpret_cast(this); } // Set the raw instruction bits to value. inline void SetInstructionBits(int32_t value) { *reinterpret_cast(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); } // Accessors for the different named fields used in the ARM encoding. // The naming of these accessor corresponds to figure A3-1. // Generally applicable fields inline Condition ConditionField() const { return static_cast(Bits(kConditionShift, kConditionBits)); } inline int TypeField() const { return Bits(kTypeShift, kTypeBits); } inline Register RnField() const { return static_cast(Bits(kRnShift, kRnBits)); } inline Register RdField() const { return static_cast(Bits(kRdShift, kRdBits)); } // Fields used in Data processing instructions inline Opcode OpcodeField() const { return static_cast(Bits(kOpcodeShift, kOpcodeBits)); } inline int SField() const { return Bits(kSShift, kSBits); } // with register inline Register RmField() const { return static_cast(Bits(kRmShift, kRmBits)); } inline Shift ShiftField() const { return static_cast(Bits(kShiftShift, kShiftBits)); } inline int RegShiftField() const { return Bit(4); } inline Register RsField() const { return static_cast(Bits(kRsShift, kRsBits)); } inline int ShiftAmountField() const { return Bits(kShiftImmShift, kShiftImmBits); } // with immediate inline int RotateField() const { return Bits(kRotateShift, kRotateBits); } inline int Immed8Field() const { return Bits(kImmed8Shift, kImmed8Bits); } // Fields used in Load/Store instructions inline int PUField() const { return Bits(23, 2); } inline int BField() const { return Bit(22); } inline int WField() const { return Bit(21); } inline int LField() const { return Bit(20); } // with register uses same fields as Data processing instructions above // with immediate inline int Offset12Field() const { return Bits(kOffset12Shift, kOffset12Bits); } // multiple inline int RlistField() const { return Bits(0, 16); } // extra loads and stores inline int SignField() const { return Bit(6); } inline int HField() const { return Bit(5); } inline int ImmedHField() const { return Bits(8, 4); } inline int ImmedLField() const { return Bits(0, 4); } // Fields used in Branch instructions inline int LinkField() const { return Bits(kLinkShift, kLinkBits); } inline int32_t SImmed24Field() const { uint32_t bits = InstructionBits(); return static_cast(bits << 8) >> 8; } // Fields used in Supervisor Call instructions inline uint32_t SvcField() const { return Bits(0, 24); } // Field used in Breakpoint instruction inline uint16_t BkptField() const { return ((Bits(8, 12) << 4) | Bits(0, 4)); } // Field used in 16-bit immediate move instructions inline uint16_t MovwField() const { return ((Bits(16, 4) << 12) | Bits(0, 12)); } // Field used in VFP float immediate move instruction inline float ImmFloatField() const { uint32_t imm32 = (Bit(19) << 31) | (((1 << 5) - Bit(18)) << 25) | (Bits(16, 2) << 23) | (Bits(0, 4) << 19); return bit_cast(imm32); } // Field used in VFP double immediate move instruction inline double ImmDoubleField() const { uint64_t imm64 = (Bit(19) * (1LL << 63)) | (((1LL << 8) - Bit(18)) << 54) | (Bits(16, 2) * (1LL << 52)) | (Bits(0, 4) * (1LL << 48)); return bit_cast(imm64); } inline Register DivRdField() const { return static_cast(Bits(kDivRdShift, kDivRdBits)); } inline Register DivRmField() const { return static_cast(Bits(kDivRmShift, kDivRmBits)); } inline Register DivRnField() const { return static_cast(Bits(kDivRnShift, kDivRnBits)); } // Test for data processing instructions of type 0 or 1. // See "ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition", // section A5.1 "ARM instruction set encoding". inline bool IsDataProcessing() const { ASSERT(ConditionField() != kSpecialCondition); ASSERT(Bits(26, 2) == 0); // Type 0 or 1. return ((Bits(20, 5) & 0x19) != 0x10) && ((Bit(25) == 1) || // Data processing immediate. (Bit(4) == 0) || // Data processing register. (Bit(7) == 0)); // Data processing register-shifted register. } // Tests for special encodings of type 0 instructions (extra loads and stores, // as well as multiplications, synchronization primitives, and miscellaneous). // Can only be called for a type 0 or 1 instruction. inline bool IsMiscellaneous() const { ASSERT(Bits(26, 2) == 0); // Type 0 or 1. return ((Bit(25) == 0) && ((Bits(20, 5) & 0x19) == 0x10) && (Bit(7) == 0)); } inline bool IsMultiplyOrSyncPrimitive() const { ASSERT(Bits(26, 2) == 0); // Type 0 or 1. return ((Bit(25) == 0) && (Bits(4, 4) == 9)); } // Test for Supervisor Call instruction. inline bool IsSvc() const { return ((InstructionBits() & 0x0f000000) == 0x0f000000); } // Test for Breakpoint instruction. inline bool IsBkpt() const { return ((InstructionBits() & 0x0ff000f0) == 0x01200070); } // VFP register fields. inline SRegister SnField() const { return static_cast((Bits(kRnShift, kRnBits) << 1) + Bit(7)); } inline SRegister SdField() const { return static_cast((Bits(kRdShift, kRdBits) << 1) + Bit(22)); } inline SRegister SmField() const { return static_cast((Bits(kRmShift, kRmBits) << 1) + Bit(5)); } inline DRegister DnField() const { return static_cast(Bits(kRnShift, kRnBits) + (Bit(7) << 4)); } inline DRegister DdField() const { return static_cast(Bits(kRdShift, kRdBits) + (Bit(22) << 4)); } inline DRegister DmField() const { return static_cast(Bits(kRmShift, kRmBits) + (Bit(5) << 4)); } inline QRegister QnField() const { const intptr_t bits = Bits(kRnShift, kRnBits) + (Bit(7) << 4); return static_cast(bits >> 1); } inline QRegister QdField() const { const intptr_t bits = Bits(kRdShift, kRdBits) + (Bit(22) << 4); return static_cast(bits >> 1); } inline QRegister QmField() const { const intptr_t bits = Bits(kRmShift, kRmBits) + (Bit(5) << 4); return static_cast(bits >> 1); } inline bool IsDivision() const { ASSERT(ConditionField() != kSpecialCondition); ASSERT(TypeField() == 3); return ((Bit(4) == 1) && (Bits(5, 3) == 0) && (Bit(20) == 1) && (Bits(22, 3) == 4)); } inline bool IsRbit() const { ASSERT(ConditionField() != kSpecialCondition); ASSERT(TypeField() == 3); return ((Bits(4, 4) == 3) && (Bits(8, 4) == 15) && (Bits(16, 4) == 15) && (Bits(20, 8) == 111)); } // Test for VFP data processing or single transfer instructions of type 7. inline bool IsVFPDataProcessingOrSingleTransfer() const { ASSERT(ConditionField() != kSpecialCondition); ASSERT(TypeField() == 7); return ((Bit(24) == 0) && (Bits(9, 3) == 5)); // Bit(4) == 0: Data Processing // Bit(4) == 1: 8, 16, or 32-bit Transfer between ARM Core and VFP } // Test for VFP 64-bit transfer instructions of type 6. inline bool IsVFPDoubleTransfer() const { ASSERT(ConditionField() != kSpecialCondition); ASSERT(TypeField() == 6); return ((Bits(21, 4) == 2) && (Bits(9, 3) == 5) && ((Bits(4, 4) & 0xd) == 1)); } // Test for VFP load and store instructions of type 6. inline bool IsVFPLoadStore() const { ASSERT(ConditionField() != kSpecialCondition); ASSERT(TypeField() == 6); return ((Bits(20, 5) & 0x12) == 0x10) && (Bits(9, 3) == 5); } // Test for VFP multiple load and store instructions of type 6. inline bool IsVFPMultipleLoadStore() const { ASSERT(ConditionField() != kSpecialCondition); ASSERT(TypeField() == 6); int32_t puw = (PUField() << 1) | Bit(21); // don't care about D bit return (Bits(9, 3) == 5) && ((puw == 2) || (puw == 3) || (puw == 5)); } inline bool IsSIMDDataProcessing() const { ASSERT(ConditionField() == kSpecialCondition); return (Bits(25, 3) == 1); } inline bool IsSIMDLoadStore() const { ASSERT(ConditionField() == kSpecialCondition); return (Bits(24, 4) == 4) && (Bit(20) == 0); } // Special accessors that test for existence of a value. inline bool HasS() const { return SField() == 1; } inline bool HasB() const { return BField() == 1; } inline bool HasW() const { return WField() == 1; } inline bool HasL() const { return LField() == 1; } inline bool HasSign() const { return SignField() == 1; } inline bool HasH() const { return HField() == 1; } inline bool HasLink() const { return LinkField() == 1; } // 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(pc); } private: DISALLOW_ALLOCATION(); DISALLOW_IMPLICIT_CONSTRUCTORS(Instr); }; // Floating-point reciprocal estimate and step (see pages A2-85 and A2-86 of // ARM Architecture Reference Manual ARMv7-A edition). float ReciprocalEstimate(float op); float ReciprocalStep(float op1, float op2); // Floating-point reciprocal square root estimate and step (see pages A2-87 to // A2-90 of ARM Architecture Reference Manual ARMv7-A edition). float ReciprocalSqrtEstimate(float op); float ReciprocalSqrtStep(float op1, float op2); constexpr uword kBreakInstructionFiller = 0xE1200070; // bkpt #0 constexpr uword kDataMemoryBarrier = 0xf57ff050 | 0xb; // dmb ish struct LinkRegister { const int32_t code = LR; }; constexpr bool operator==(Register r, LinkRegister) { return r == LR; } constexpr bool operator!=(Register r, LinkRegister lr) { return !(r == lr); } #undef LR #define LINK_REGISTER (LinkRegister()) } // namespace dart #endif // RUNTIME_VM_CONSTANTS_ARM_H_