// 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 "platform/utils.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

#define R(reg) (static_cast<RegList>(1) << (reg))

// We support both VFPv3-D16 and VFPv3-D32 profiles, but currently only one at
// a time.
#if defined(DART_TARGET_OS_ANDROID) || defined(DART_TARGET_OS_LINUX)
#define VFPv3_D16
#elif defined(DART_TARGET_OS_MACOS_IOS) || defined(DART_TARGET_OS_WINDOWS)
#define VFPv3_D32
#else
#error Which VFP?
#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, Windows)
// 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), Windows and Android also differ in whether floating
// point arguments are passed in floating point registers. Linux and Windows
// use 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_REG
  R7 = 7,  // FP on iOS, DISPATCH_TABLE_REG on non-iOS (AOT only)
  R8 = 8,
  R9 = 9,
  R10 = 10,  // THR
  R11 = 11,  // FP on non-iOS, DISPATCH_TABLE_REG on iOS (AOT only)
  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(DART_TARGET_OS_MACOS) || defined(DART_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
  // Number of D registers that overlap S registers.
  // One D register overlaps two S registers, so regardless of the numbers of D
  // registers, there are only 32 S registers that are overlapped.
  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
  // Number of Q registers that overlap S registers.
  // One Q register overlaps four S registers, so regardless of the numbers of Q
  // registers, there are only 32 S registers that are overlapped.
  kNumberOfOverlappingQRegisters = 8,
};

static inline DRegister EvenDRegisterOf(QRegister q) {
  return static_cast<DRegister>(q * 2);
}

static inline DRegister OddDRegisterOf(QRegister q) {
  return static_cast<DRegister>((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 ever 32 S registers in any extension.
  ASSERT(d < D16);
#endif
  return static_cast<SRegister>(d * 2);
}

static inline SRegister OddSRegisterOf(DRegister d) {
#if defined(VFPv3_D32)
  ASSERT(d < D16);
#endif
  return static_cast<SRegister>((d * 2) + 1);
}

static inline QRegister QRegisterOf(DRegister d) {
  return static_cast<QRegister>(d / 2);
}
static inline QRegister QRegisterOf(SRegister s) {
  return static_cast<QRegister>(s / 4);
}
static inline DRegister DRegisterOf(SRegister s) {
  return static_cast<DRegister>(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 kFpuRegisterSize = 16;
typedef simd128_value_t fpu_register_t;
const int kNumberOfFpuRegisters = kNumberOfQRegisters;
const FpuRegister kNoFpuRegister = kNoQRegister;

extern const char* const cpu_reg_names[kNumberOfCpuRegisters];
extern const char* const cpu_reg_abi_names[kNumberOfCpuRegisters];
extern const char* const fpu_reg_names[kNumberOfFpuRegisters];
extern const char* const fpu_s_reg_names[kNumberOfSRegisters];
extern const char* const 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 IC_DATA_REG = R9;            // ICData/MegamorphicCache register.
const Register ARGS_DESC_REG = R4;
const Register CODE_REG = R6;
// Set when calling Dart functions in JIT mode, used by LazyCompileStub.
const Register FUNCTION_REG = R0;
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;

// Common ABI for shared slow path stubs.
struct SharedSlowPathStubABI {
  static constexpr Register kResultReg = R0;
};

// ABI for instantiation stubs.
struct InstantiationABI {
  static constexpr Register kUninstantiatedTypeArgumentsReg = R3;
  static constexpr Register kInstantiatorTypeArgumentsReg = R2;
  static constexpr Register kFunctionTypeArgumentsReg = R1;
  static constexpr Register kResultTypeArgumentsReg = R0;
  static constexpr Register kResultTypeReg = R0;
  static constexpr Register kScratchReg = R8;
};

// Registers in addition to those listed in InstantiationABI used inside the
// implementation of the InstantiateTypeArguments stubs.
struct InstantiateTAVInternalRegs {
  // The set of registers that must be pushed/popped when probing a hash-based
  // cache due to overlap with the registers in InstantiationABI.
  static constexpr intptr_t kSavedRegisters =
#if defined(DART_PRECOMPILER)
      (1 << DISPATCH_TABLE_REG) |
#endif
      (1 << InstantiationABI::kUninstantiatedTypeArgumentsReg);

  // Additional registers used to probe hash-based caches.
  static constexpr Register kEntryStartReg = R9;
  static constexpr Register kProbeMaskReg = R4;
  static constexpr Register kProbeDistanceReg = DISPATCH_TABLE_REG;
  static constexpr Register kCurrentEntryIndexReg =
      InstantiationABI::kUninstantiatedTypeArgumentsReg;
};

// Registers in addition to those listed in TypeTestABI used inside the
// implementation of type testing stubs that are _not_ preserved.
struct TTSInternalRegs {
  static constexpr Register kInstanceTypeArgumentsReg = R4;
  static constexpr Register kScratchReg = R9;
  static constexpr Register kSubTypeArgumentReg = R3;
  static constexpr Register kSuperTypeArgumentReg = R8;

  // Must be pushed/popped whenever generic type arguments are being checked as
  // they overlap with registers in TypeTestABI.
  static constexpr intptr_t kSavedTypeArgumentRegisters =
      (1 << kSubTypeArgumentReg) | (1 << kSuperTypeArgumentReg);

  static constexpr intptr_t kInternalRegisters =
      ((1 << kInstanceTypeArgumentsReg) | (1 << kScratchReg) |
       (1 << kSubTypeArgumentReg) | (1 << kSuperTypeArgumentReg)) &
      ~kSavedTypeArgumentRegisters;
};

// Registers in addition to those listed in TypeTestABI used inside the
// implementation of subtype test cache stubs that are _not_ preserved.
struct STCInternalRegs {
  static constexpr Register kInstanceCidOrSignatureReg = R9;

  static constexpr intptr_t kInternalRegisters =
      (1 << kInstanceCidOrSignatureReg);
};

// Calling convention when calling TypeTestingStub and SubtypeTestCacheStub.
struct TypeTestABI {
  static constexpr Register kInstanceReg = R0;
  static constexpr Register kDstTypeReg = R8;
  static constexpr Register kInstantiatorTypeArgumentsReg = R2;
  static constexpr Register kFunctionTypeArgumentsReg = R1;
  static constexpr Register kSubtypeTestCacheReg = R3;
  static constexpr Register kScratchReg = R4;

  // For calls to SubtypeNTestCacheStub. Must not be the same as any non-scratch
  // register above.
  static constexpr Register kSubtypeTestCacheResultReg = kScratchReg;
  // For calls to InstanceOfStub.
  static constexpr Register kInstanceOfResultReg = kInstanceReg;

  static constexpr intptr_t kPreservedAbiRegisters =
      (1 << kInstanceReg) | (1 << kDstTypeReg) |
      (1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg);

  static constexpr intptr_t kNonPreservedAbiRegisters =
      TTSInternalRegs::kInternalRegisters |
      STCInternalRegs::kInternalRegisters | (1 << kSubtypeTestCacheReg) |
      (1 << kScratchReg) | (1 << kSubtypeTestCacheResultReg) | (1 << CODE_REG);

  static constexpr intptr_t kAbiRegisters =
      kPreservedAbiRegisters | kNonPreservedAbiRegisters;
};

// Calling convention when calling AssertSubtypeStub.
struct AssertSubtypeABI {
  static constexpr Register kSubTypeReg = R0;
  static constexpr Register kSuperTypeReg = R8;
  static constexpr Register kInstantiatorTypeArgumentsReg = R2;
  static constexpr Register kFunctionTypeArgumentsReg = R1;
  static constexpr Register kDstNameReg = R3;

  static constexpr 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 constexpr Register kFieldReg = R2;
  static constexpr Register kResultReg = R0;
};

// Registers used inside the implementation of InitLateStaticFieldStub.
struct InitLateStaticFieldInternalRegs {
  static constexpr Register kAddressReg = R3;
  static constexpr Register kScratchReg = R4;
};

// ABI for InitInstanceFieldStub.
struct InitInstanceFieldABI {
  static constexpr Register kInstanceReg = R1;
  static constexpr Register kFieldReg = R2;
  static constexpr Register kResultReg = R0;
};

// Registers used inside the implementation of InitLateInstanceFieldStub.
struct InitLateInstanceFieldInternalRegs {
  static constexpr Register kAddressReg = R3;
  static constexpr Register kScratchReg = R4;
};

// ABI for LateInitializationError stubs.
struct LateInitializationErrorABI {
  static constexpr Register kFieldReg = R9;
};

// ABI for FieldAccessError stubs.
struct FieldAccessErrorABI {
  static constexpr Register kFieldReg = R9;
};

// ABI for ThrowStub.
struct ThrowABI {
  static constexpr Register kExceptionReg = R0;
};

// ABI for ReThrowStub.
struct ReThrowABI {
  static constexpr Register kExceptionReg = R0;
  static constexpr Register kStackTraceReg = R1;
};

// ABI for RangeErrorStub.
struct RangeErrorABI {
  static constexpr Register kLengthReg = R0;
  static constexpr Register kIndexReg = R1;
};

// ABI for AllocateObjectStub.
struct AllocateObjectABI {
  static constexpr Register kResultReg = R0;
  static constexpr Register kTypeArgumentsReg = R3;
  static constexpr Register kTagsReg = R2;
};

// ABI for AllocateClosureStub.
struct AllocateClosureABI {
  static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
  static constexpr Register kFunctionReg = R1;
  static constexpr Register kLengthAndFlagsReg = R2;
  static constexpr Register kContextReg = R3;
  static constexpr Register kScratchReg = R4;
};

// ABI for AllocateMintShared*Stub.
struct AllocateMintABI {
  static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
  static constexpr Register kTempReg = R1;
};

// ABI for Allocate{Mint,Double,Float32x4,Float64x2}Stub.
struct AllocateBoxABI {
  static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
  static constexpr Register kTempReg = R1;
};

// ABI for AllocateArrayStub.
struct AllocateArrayABI {
  static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
  static constexpr Register kLengthReg = R2;
  static constexpr Register kTypeArgumentsReg = R1;
};

// ABI for AllocateRecordStub.
struct AllocateRecordABI {
  static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
  static constexpr Register kShapeReg = R1;
  static constexpr Register kTemp1Reg = R2;
  static constexpr Register kTemp2Reg = R3;
};

// ABI for AllocateSmallRecordStub (AllocateRecord2, AllocateRecord2Named,
// AllocateRecord3, AllocateRecord3Named).
struct AllocateSmallRecordABI {
  static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
  static constexpr Register kShapeReg = R1;
  static constexpr Register kValue0Reg = R2;
  static constexpr Register kValue1Reg = R3;
  static constexpr Register kValue2Reg = R4;
  static constexpr Register kTempReg = R9;
};

// ABI for AllocateTypedDataArrayStub.
struct AllocateTypedDataArrayABI {
  static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
  static constexpr Register kLengthReg = R4;
};

// ABI for BoxDoubleStub.
struct BoxDoubleStubABI {
  static constexpr FpuRegister kValueReg = Q0;
  static constexpr Register kTempReg = R1;
  static constexpr Register kResultReg = R0;
};

// ABI for DoubleToIntegerStub.
struct DoubleToIntegerStubABI {
  static constexpr FpuRegister kInputReg = Q0;
  static constexpr Register kRecognizedKindReg = R0;
  static constexpr Register kResultReg = R0;
};

// ABI for CheckedStoreIntoSharedStub.
struct CheckedStoreIntoSharedStubABI {
  static constexpr Register kFieldReg = R1;
  static constexpr Register kValueReg = R2;
  static constexpr Register kResultReg = R0;
};

// ABI for EnsureDeeplyImmutableStub.
struct EnsureDeeplyImmutableStubABI {
  static constexpr Register kValueReg = R0;
  static constexpr Register kTempReg = R1;
};

// ABI for SuspendStub (AwaitStub, AwaitWithTypeCheckStub, YieldAsyncStarStub,
// SuspendSyncStarAtStartStub, SuspendSyncStarAtYieldStub).
struct SuspendStubABI {
  static constexpr Register kArgumentReg = R0;
  static constexpr Register kTypeArgsReg = R1;  // Can be the same as kTempReg
  static constexpr Register kTempReg = R1;
  static constexpr Register kFrameSizeReg = R2;
  static constexpr Register kSuspendStateReg = R3;
  static constexpr Register kFunctionDataReg = R4;
  static constexpr Register kSrcFrameReg = R8;
  static constexpr Register kDstFrameReg = R9;

  // Number of bytes to skip after
  // suspend stub return address in order to resume.
  static constexpr intptr_t kResumePcDistance = 0;
};

// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub,
// InitSyncStarStub).
struct InitSuspendableFunctionStubABI {
  static constexpr Register kTypeArgsReg = R0;
};

// ABI for ResumeStub
struct ResumeStubABI {
  static constexpr Register kSuspendStateReg = R2;
  static constexpr Register kTempReg = R0;
  // Registers for the frame copying (the 1st part).
  static constexpr Register kFrameSizeReg = R1;
  static constexpr Register kSrcFrameReg = R3;
  static constexpr Register kDstFrameReg = R4;
  // Registers for control transfer.
  // (the 2nd part, can reuse registers from the 1st part)
  static constexpr Register kResumePcReg = R1;
  // Can also reuse kSuspendStateReg but should not conflict with CODE_REG/PP.
  static constexpr Register kExceptionReg = R3;
  static constexpr Register kStackTraceReg = R4;
};

// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub,
// ReturnAsyncStarStub).
struct ReturnStubABI {
  static constexpr Register kSuspendStateReg = R2;
};

// ABI for AsyncExceptionHandlerStub.
struct AsyncExceptionHandlerStubABI {
  static constexpr Register kSuspendStateReg = R2;
};

// ABI for CloneSuspendStateStub.
struct CloneSuspendStateStubABI {
  static constexpr Register kSourceReg = R0;
  static constexpr Register kDestinationReg = R1;
  static constexpr Register kTempReg = R2;
  static constexpr Register kFrameSizeReg = R3;
  static constexpr Register kSrcFrameReg = R4;
  static constexpr Register kDstFrameReg = R8;
};

// ABI for FfiAsyncCallbackSendStub.
struct FfiAsyncCallbackSendStubABI {
  static constexpr Register kArgsReg = 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 constexpr 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;
const RegList kAllFpuRegistersList = (1 << kNumberOfFpuRegisters) - 1;

// C++ ABI call registers.
const RegList kAbiArgumentCpuRegs =
    (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3);
const RegList kAbiVolatileCpuRegs = kAbiArgumentCpuRegs | (1 << IP) | (1 << LR);
#if defined(DART_TARGET_OS_MACOS) || defined(DART_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 =
    Utils::CountOneBits32(kReservedCpuRegisters);
// CPU registers available to Dart allocator.
constexpr RegList kDartAvailableCpuRegs =
    kAllCpuRegistersList & ~kReservedCpuRegisters;
constexpr int kNumberOfDartAvailableCpuRegs =
    kNumberOfCpuRegisters - kNumberOfReservedCpuRegisters;
// No reason to prefer certain registers on ARM.
constexpr int kRegisterAllocationBias = 0;
const intptr_t kStoreBufferWrapperSize = 24;
// Registers available to Dart that are not preserved by runtime calls.
const RegList kDartVolatileCpuRegs =
    kDartAvailableCpuRegs & ~kAbiPreservedCpuRegs;
#if defined(DART_TARGET_OS_MACOS) || defined(DART_TARGET_OS_MACOS_IOS)
const int kDartVolatileCpuRegCount = 6;
#else
const int kDartVolatileCpuRegCount = 5;
#endif

const RegList kAbiVolatileFpuRegs = R(Q0) | R(Q1) | R(Q2) | R(Q3);

const RegList kFpuRegistersWithoutSOverlap =
    kAllFpuRegistersList &
    ~((1 << QRegister::kNumberOfOverlappingQRegisters) - 1);

class CallingConventions {
 public:
  static constexpr intptr_t kArgumentRegisters = kAbiArgumentCpuRegs;
  static const Register ArgumentRegisters[];
  static constexpr intptr_t kNumArgRegs = 4;
  static constexpr Register kPointerToReturnStructRegisterCall = R0;

  static constexpr intptr_t kFpuArgumentRegisters = 0;

  static const FpuRegister FpuArgumentRegisters[];
  static constexpr intptr_t kNumFpuArgRegs = 4;
  static const DRegister FpuDArgumentRegisters[];
  static constexpr intptr_t kNumDFpuArgRegs = 8;
  static const SRegister FpuSArgumentRegisters[];
  static constexpr 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 =
      kAlignedToWordSizeAndValueSize;
  static constexpr AlignmentStrategy kArgumentRegisterAlignmentVarArgs =
      kArgumentRegisterAlignment;

  // How stack arguments are aligned.
  static constexpr AlignmentStrategy kArgumentStackAlignment =
      kAlignedToWordSizeAndValueSize;
  static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
      kArgumentStackAlignment;

  // How fields in compounds are aligned.
#if defined(DART_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);
};

// Register based calling convention used for Dart functions.
//
// See |compiler::ComputeCallingConvention| for more details.
struct DartCallingConvention {
  static constexpr Register kCpuRegistersForArgs[] = {R1, R2, R3, R8};
  static constexpr FpuRegister kFpuRegistersForArgs[] = {Q0, Q1, Q2, Q3};
};

#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<Condition>(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,

  // ldrex/strex register field encodings.
  kLdrExRnShift = 16,
  kLdrExRtShift = 12,
  kStrExRnShift = 16,
  kStrExRdShift = 12,
  kStrExRtShift = 0,

  // Media operation field encodings.
  kMediaOp1Shift = 20,
  kMediaOp1Bits = 5,
  kMediaOp2Shift = 5,
  kMediaOp2Bits = 3,

  // udiv/sdiv instruction register field encodings.
  kDivRdShift = 16,
  kDivRdBits = 4,
  kDivRmShift = 8,
  kDivRmBits = 4,
  kDivRnShift = 0,
  kDivRnBits = 4,

  // sbfx/ubfx instruction register and immediate field encodings.
  kBitFieldExtractWidthShift = 16,
  kBitFieldExtractWidthBits = 5,
  kBitFieldExtractLSBShift = 7,
  kBitFieldExtractLSBBits = 5,
  kBitFieldExtractRnShift = 0,
  kBitFieldExtractRnBits = 4,

  // 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
  // Used for Smi-boxed indices.
  TIMES_COMPRESSED_HALF_WORD_SIZE = TIMES_COMPRESSED_WORD_SIZE - 1,
};

// 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 constexpr int32_t kNopInstruction =  // nop
      ((AL << kConditionShift) | (0x32 << 20) | (0xf << 12));

  static constexpr int32_t kBreakPointCode = 0xdeb0;  // For breakpoint.
  static constexpr int32_t kSimulatorBreakCode =
      0xdeb2;  // For breakpoint in sim.
  static constexpr int32_t kSimulatorRedirectCode = 0xca11;  // For redirection.

  // Breakpoint instruction filling assembler code buffers in debug mode.
  static constexpr 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 constexpr int32_t kSimulatorBreakpointInstruction =
      // svc #kBreakpointSvcCode
      ((AL << kConditionShift) | (0xf << 24) | kSimulatorBreakCode);

  // Runtime call redirection instruction used by the simulator.
  static constexpr int32_t kSimulatorRedirectInstruction =
      ((AL << kConditionShift) | (0xf << 24) | kSimulatorRedirectCode);

  // 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);
  }

  // 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<Condition>(Bits(kConditionShift, kConditionBits));
  }
  inline int TypeField() const { return Bits(kTypeShift, kTypeBits); }
  inline int SubtypeField() const { return Bit(4); }

  inline Register RnField() const {
    return static_cast<Register>(Bits(kRnShift, kRnBits));
  }
  inline Register RdField() const {
    return static_cast<Register>(Bits(kRdShift, kRdBits));
  }

  // Fields used in Data processing instructions
  inline Opcode OpcodeField() const {
    return static_cast<Opcode>(Bits(kOpcodeShift, kOpcodeBits));
  }
  inline int SField() const { return Bits(kSShift, kSBits); }
  // with register
  inline Register RmField() const {
    return static_cast<Register>(Bits(kRmShift, kRmBits));
  }
  inline Shift ShiftField() const {
    return static_cast<Shift>(Bits(kShiftShift, kShiftBits));
  }
  inline int RegShiftField() const { return Bit(4); }
  inline Register RsField() const {
    return static_cast<Register>(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<int32_t>(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<float, uint32_t>(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<double, uint64_t>(imm64);
  }

  // Shared fields used in media instructions.
  inline int MediaOp1Field() const {
    return static_cast<Register>(Bits(kMediaOp1Shift, kMediaOp1Bits));
  }
  inline int MediaOp2Field() const {
    return static_cast<Register>(Bits(kMediaOp2Shift, kMediaOp2Bits));
  }

  // Fields used in division instructions.
  inline bool IsDivUnsigned() const { return Bit(21) == 0b1; }
  inline Register DivRdField() const {
    return static_cast<Register>(Bits(kDivRdShift, kDivRdBits));
  }
  inline Register DivRmField() const {
    return static_cast<Register>(Bits(kDivRmShift, kDivRmBits));
  }
  inline Register DivRnField() const {
    return static_cast<Register>(Bits(kDivRnShift, kDivRnBits));
  }

  // Fields used in bit field extract instructions.
  inline bool IsBitFieldExtractSignExtended() const { return Bit(22) == 0; }
  inline uint8_t BitFieldExtractWidthField() const {
    return Bits(kBitFieldExtractWidthShift, kBitFieldExtractWidthBits);
  }
  inline uint8_t BitFieldExtractLSBField() const {
    return Bits(kBitFieldExtractLSBShift, kBitFieldExtractLSBBits);
  }
  inline Register BitFieldExtractRnField() const {
    return static_cast<Register>(
        Bits(kBitFieldExtractRnShift, kBitFieldExtractRnBits));
  }

  // 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<SRegister>((Bits(kRnShift, kRnBits) << 1) + Bit(7));
  }
  inline SRegister SdField() const {
    return static_cast<SRegister>((Bits(kRdShift, kRdBits) << 1) + Bit(22));
  }
  inline SRegister SmField() const {
    return static_cast<SRegister>((Bits(kRmShift, kRmBits) << 1) + Bit(5));
  }
  inline DRegister DnField() const {
    return static_cast<DRegister>(Bits(kRnShift, kRnBits) + (Bit(7) << 4));
  }
  inline DRegister DdField() const {
    return static_cast<DRegister>(Bits(kRdShift, kRdBits) + (Bit(22) << 4));
  }
  inline DRegister DmField() const {
    return static_cast<DRegister>(Bits(kRmShift, kRmBits) + (Bit(5) << 4));
  }
  inline QRegister QnField() const {
    const intptr_t bits = Bits(kRnShift, kRnBits) + (Bit(7) << 4);
    return static_cast<QRegister>(bits >> 1);
  }
  inline QRegister QdField() const {
    const intptr_t bits = Bits(kRdShift, kRdBits) + (Bit(22) << 4);
    return static_cast<QRegister>(bits >> 1);
  }
  inline QRegister QmField() const {
    const intptr_t bits = Bits(kRmShift, kRmBits) + (Bit(5) << 4);
    return static_cast<QRegister>(bits >> 1);
  }

  // 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);
  }

  // Tests for media instructions of type 3.
  inline bool IsMedia() const {
    ASSERT_EQUAL(TypeField(), 3);
    return SubtypeField() == 1;
  }

  inline bool IsDivision() const {
    ASSERT(ConditionField() != kSpecialCondition);
    ASSERT(IsMedia());
    // B21 determines whether the division is signed or unsigned.
    return (((MediaOp1Field() & 0b11101) == 0b10001) &&
            (MediaOp2Field() == 0b000));
  }

  inline bool IsRbit() const {
    ASSERT(ConditionField() != kSpecialCondition);
    ASSERT(IsMedia());
    // B19-B16 and B11-B8 are always set for rbit.
    return ((MediaOp1Field() == 0b01111) && (MediaOp2Field() == 0b001) &&
            (Bits(8, 4) == 0b1111) && (Bits(16, 4) == 0b1111));
  }

  inline bool IsBitFieldExtract() const {
    ASSERT(ConditionField() != kSpecialCondition);
    ASSERT(IsMedia());
    // B22 determines whether extracted value is sign extended or not, and
    // op bits B20 and B7 are part of the width and LSB fields, respectively.
    return ((MediaOp1Field() & 0b11010) == 0b11010) &&
           ((MediaOp2Field() & 0b011) == 0b10);
  }

  // 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<Instr*>(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 kDMB_ISH = 0xf57ff05b;                 // dmb ish
constexpr uword kDMB_ISHST = 0xf57ff05a;               // dmb ishst

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);
}

inline Register ConcreteRegister(LinkRegister) {
  return LR;
}

#undef LR

#define LINK_REGISTER (LinkRegister())

// Prioritize code size over performance.
const intptr_t kPreferredLoopAlignment = 1;

}  // namespace dart

#endif  // RUNTIME_VM_CONSTANTS_ARM_H_
