summaryrefslogtreecommitdiff
path: root/disas/libvixl/vixl/a64/instructions-a64.h
diff options
context:
space:
mode:
Diffstat (limited to 'disas/libvixl/vixl/a64/instructions-a64.h')
-rw-r--r--disas/libvixl/vixl/a64/instructions-a64.h757
1 files changed, 0 insertions, 757 deletions
diff --git a/disas/libvixl/vixl/a64/instructions-a64.h b/disas/libvixl/vixl/a64/instructions-a64.h
deleted file mode 100644
index 7e0dbae36a..0000000000
--- a/disas/libvixl/vixl/a64/instructions-a64.h
+++ /dev/null
@@ -1,757 +0,0 @@
-// Copyright 2015, ARM Limited
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of ARM Limited nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
-// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef VIXL_A64_INSTRUCTIONS_A64_H_
-#define VIXL_A64_INSTRUCTIONS_A64_H_
-
-#include "vixl/globals.h"
-#include "vixl/utils.h"
-#include "vixl/a64/constants-a64.h"
-
-namespace vixl {
-// ISA constants. --------------------------------------------------------------
-
-typedef uint32_t Instr;
-const unsigned kInstructionSize = 4;
-const unsigned kInstructionSizeLog2 = 2;
-const unsigned kLiteralEntrySize = 4;
-const unsigned kLiteralEntrySizeLog2 = 2;
-const unsigned kMaxLoadLiteralRange = 1 * MBytes;
-
-// This is the nominal page size (as used by the adrp instruction); the actual
-// size of the memory pages allocated by the kernel is likely to differ.
-const unsigned kPageSize = 4 * KBytes;
-const unsigned kPageSizeLog2 = 12;
-
-const unsigned kBRegSize = 8;
-const unsigned kBRegSizeLog2 = 3;
-const unsigned kBRegSizeInBytes = kBRegSize / 8;
-const unsigned kBRegSizeInBytesLog2 = kBRegSizeLog2 - 3;
-const unsigned kHRegSize = 16;
-const unsigned kHRegSizeLog2 = 4;
-const unsigned kHRegSizeInBytes = kHRegSize / 8;
-const unsigned kHRegSizeInBytesLog2 = kHRegSizeLog2 - 3;
-const unsigned kWRegSize = 32;
-const unsigned kWRegSizeLog2 = 5;
-const unsigned kWRegSizeInBytes = kWRegSize / 8;
-const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3;
-const unsigned kXRegSize = 64;
-const unsigned kXRegSizeLog2 = 6;
-const unsigned kXRegSizeInBytes = kXRegSize / 8;
-const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3;
-const unsigned kSRegSize = 32;
-const unsigned kSRegSizeLog2 = 5;
-const unsigned kSRegSizeInBytes = kSRegSize / 8;
-const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3;
-const unsigned kDRegSize = 64;
-const unsigned kDRegSizeLog2 = 6;
-const unsigned kDRegSizeInBytes = kDRegSize / 8;
-const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3;
-const unsigned kQRegSize = 128;
-const unsigned kQRegSizeLog2 = 7;
-const unsigned kQRegSizeInBytes = kQRegSize / 8;
-const unsigned kQRegSizeInBytesLog2 = kQRegSizeLog2 - 3;
-const uint64_t kWRegMask = UINT64_C(0xffffffff);
-const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff);
-const uint64_t kSRegMask = UINT64_C(0xffffffff);
-const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff);
-const uint64_t kSSignMask = UINT64_C(0x80000000);
-const uint64_t kDSignMask = UINT64_C(0x8000000000000000);
-const uint64_t kWSignMask = UINT64_C(0x80000000);
-const uint64_t kXSignMask = UINT64_C(0x8000000000000000);
-const uint64_t kByteMask = UINT64_C(0xff);
-const uint64_t kHalfWordMask = UINT64_C(0xffff);
-const uint64_t kWordMask = UINT64_C(0xffffffff);
-const uint64_t kXMaxUInt = UINT64_C(0xffffffffffffffff);
-const uint64_t kWMaxUInt = UINT64_C(0xffffffff);
-const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff);
-const int64_t kXMinInt = INT64_C(0x8000000000000000);
-const int32_t kWMaxInt = INT32_C(0x7fffffff);
-const int32_t kWMinInt = INT32_C(0x80000000);
-const unsigned kLinkRegCode = 30;
-const unsigned kZeroRegCode = 31;
-const unsigned kSPRegInternalCode = 63;
-const unsigned kRegCodeMask = 0x1f;
-
-const unsigned kAddressTagOffset = 56;
-const unsigned kAddressTagWidth = 8;
-const uint64_t kAddressTagMask =
- ((UINT64_C(1) << kAddressTagWidth) - 1) << kAddressTagOffset;
-VIXL_STATIC_ASSERT(kAddressTagMask == UINT64_C(0xff00000000000000));
-
-// AArch64 floating-point specifics. These match IEEE-754.
-const unsigned kDoubleMantissaBits = 52;
-const unsigned kDoubleExponentBits = 11;
-const unsigned kFloatMantissaBits = 23;
-const unsigned kFloatExponentBits = 8;
-const unsigned kFloat16MantissaBits = 10;
-const unsigned kFloat16ExponentBits = 5;
-
-// Floating-point infinity values.
-extern const float16 kFP16PositiveInfinity;
-extern const float16 kFP16NegativeInfinity;
-extern const float kFP32PositiveInfinity;
-extern const float kFP32NegativeInfinity;
-extern const double kFP64PositiveInfinity;
-extern const double kFP64NegativeInfinity;
-
-// The default NaN values (for FPCR.DN=1).
-extern const float16 kFP16DefaultNaN;
-extern const float kFP32DefaultNaN;
-extern const double kFP64DefaultNaN;
-
-unsigned CalcLSDataSize(LoadStoreOp op);
-unsigned CalcLSPairDataSize(LoadStorePairOp op);
-
-enum ImmBranchType {
- UnknownBranchType = 0,
- CondBranchType = 1,
- UncondBranchType = 2,
- CompareBranchType = 3,
- TestBranchType = 4
-};
-
-enum AddrMode {
- Offset,
- PreIndex,
- PostIndex
-};
-
-enum FPRounding {
- // The first four values are encodable directly by FPCR<RMode>.
- FPTieEven = 0x0,
- FPPositiveInfinity = 0x1,
- FPNegativeInfinity = 0x2,
- FPZero = 0x3,
-
- // The final rounding modes are only available when explicitly specified by
- // the instruction (such as with fcvta). It cannot be set in FPCR.
- FPTieAway,
- FPRoundOdd
-};
-
-enum Reg31Mode {
- Reg31IsStackPointer,
- Reg31IsZeroRegister
-};
-
-// Instructions. ---------------------------------------------------------------
-
-class Instruction {
- public:
- Instr InstructionBits() const {
- return *(reinterpret_cast<const Instr*>(this));
- }
-
- void SetInstructionBits(Instr new_instr) {
- *(reinterpret_cast<Instr*>(this)) = new_instr;
- }
-
- int Bit(int pos) const {
- return (InstructionBits() >> pos) & 1;
- }
-
- uint32_t Bits(int msb, int lsb) const {
- return unsigned_bitextract_32(msb, lsb, InstructionBits());
- }
-
- int32_t SignedBits(int msb, int lsb) const {
- int32_t bits = *(reinterpret_cast<const int32_t*>(this));
- return signed_bitextract_32(msb, lsb, bits);
- }
-
- Instr Mask(uint32_t mask) const {
- return InstructionBits() & mask;
- }
-
- #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \
- int32_t Name() const { return Func(HighBit, LowBit); }
- INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)
- #undef DEFINE_GETTER
-
- // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST),
- // formed from ImmPCRelLo and ImmPCRelHi.
- int ImmPCRel() const {
- int offset =
- static_cast<int>((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo());
- int width = ImmPCRelLo_width + ImmPCRelHi_width;
- return signed_bitextract_32(width - 1, 0, offset);
- }
-
- uint64_t ImmLogical() const;
- unsigned ImmNEONabcdefgh() const;
- float ImmFP32() const;
- double ImmFP64() const;
- float ImmNEONFP32() const;
- double ImmNEONFP64() const;
-
- unsigned SizeLS() const {
- return CalcLSDataSize(static_cast<LoadStoreOp>(Mask(LoadStoreMask)));
- }
-
- unsigned SizeLSPair() const {
- return CalcLSPairDataSize(
- static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
- }
-
- int NEONLSIndex(int access_size_shift) const {
- int64_t q = NEONQ();
- int64_t s = NEONS();
- int64_t size = NEONLSSize();
- int64_t index = (q << 3) | (s << 2) | size;
- return static_cast<int>(index >> access_size_shift);
- }
-
- // Helpers.
- bool IsCondBranchImm() const {
- return Mask(ConditionalBranchFMask) == ConditionalBranchFixed;
- }
-
- bool IsUncondBranchImm() const {
- return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed;
- }
-
- bool IsCompareBranch() const {
- return Mask(CompareBranchFMask) == CompareBranchFixed;
- }
-
- bool IsTestBranch() const {
- return Mask(TestBranchFMask) == TestBranchFixed;
- }
-
- bool IsImmBranch() const {
- return BranchType() != UnknownBranchType;
- }
-
- bool IsPCRelAddressing() const {
- return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
- }
-
- bool IsLogicalImmediate() const {
- return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
- }
-
- bool IsAddSubImmediate() const {
- return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
- }
-
- bool IsAddSubExtended() const {
- return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
- }
-
- bool IsLoadOrStore() const {
- return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed;
- }
-
- bool IsLoad() const;
- bool IsStore() const;
-
- bool IsLoadLiteral() const {
- // This includes PRFM_lit.
- return Mask(LoadLiteralFMask) == LoadLiteralFixed;
- }
-
- bool IsMovn() const {
- return (Mask(MoveWideImmediateMask) == MOVN_x) ||
- (Mask(MoveWideImmediateMask) == MOVN_w);
- }
-
- static int ImmBranchRangeBitwidth(ImmBranchType branch_type);
- static int32_t ImmBranchForwardRange(ImmBranchType branch_type);
- static bool IsValidImmPCOffset(ImmBranchType branch_type, int64_t offset);
-
- // Indicate whether Rd can be the stack pointer or the zero register. This
- // does not check that the instruction actually has an Rd field.
- Reg31Mode RdMode() const {
- // The following instructions use sp or wsp 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 zero register.
- if (IsAddSubImmediate() || IsAddSubExtended()) {
- if (Mask(AddSubSetFlagsBit)) {
- return Reg31IsZeroRegister;
- } else {
- return Reg31IsStackPointer;
- }
- }
- if (IsLogicalImmediate()) {
- // Of the logical (immediate) instructions, only ANDS (and its aliases)
- // can set the flags. The others can all write into sp.
- // Note that some logical operations are not available to
- // immediate-operand instructions, so we have to combine two masks here.
- if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) {
- return Reg31IsZeroRegister;
- } else {
- return Reg31IsStackPointer;
- }
- }
- return Reg31IsZeroRegister;
- }
-
- // Indicate whether Rn can be the stack pointer or the zero register. This
- // does not check that the instruction actually has an Rn field.
- Reg31Mode RnMode() const {
- // The following instructions use sp or wsp as Rn:
- // All loads and stores.
- // Add/sub (immediate).
- // Add/sub (extended).
- // Otherwise, r31 is the zero register.
- if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) {
- return Reg31IsStackPointer;
- }
- return Reg31IsZeroRegister;
- }
-
- ImmBranchType BranchType() const {
- if (IsCondBranchImm()) {
- return CondBranchType;
- } else if (IsUncondBranchImm()) {
- return UncondBranchType;
- } else if (IsCompareBranch()) {
- return CompareBranchType;
- } else if (IsTestBranch()) {
- return TestBranchType;
- } else {
- return UnknownBranchType;
- }
- }
-
- // Find the target of this instruction. 'this' may be a branch or a
- // PC-relative addressing instruction.
- const Instruction* ImmPCOffsetTarget() const;
-
- // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
- // a PC-relative addressing instruction.
- void SetImmPCOffsetTarget(const Instruction* target);
- // Patch a literal load instruction to load from 'source'.
- void SetImmLLiteral(const Instruction* source);
-
- // The range of a load literal instruction, expressed as 'instr +- range'.
- // The range is actually the 'positive' range; the branch instruction can
- // target [instr - range - kInstructionSize, instr + range].
- static const int kLoadLiteralImmBitwidth = 19;
- static const int kLoadLiteralRange =
- (1 << kLoadLiteralImmBitwidth) / 2 - kInstructionSize;
-
- // Calculate the address of a literal referred to by a load-literal
- // instruction, and return it as the specified type.
- //
- // The literal itself is safely mutable only if the backing buffer is safely
- // mutable.
- template <typename T>
- T LiteralAddress() const {
- uint64_t base_raw = reinterpret_cast<uint64_t>(this);
- int64_t offset = ImmLLiteral() << kLiteralEntrySizeLog2;
- uint64_t address_raw = base_raw + offset;
-
- // Cast the address using a C-style cast. A reinterpret_cast would be
- // appropriate, but it can't cast one integral type to another.
- T address = (T)(address_raw);
-
- // Assert that the address can be represented by the specified type.
- VIXL_ASSERT((uint64_t)(address) == address_raw);
-
- return address;
- }
-
- uint32_t Literal32() const {
- uint32_t literal;
- memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal));
- return literal;
- }
-
- uint64_t Literal64() const {
- uint64_t literal;
- memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal));
- return literal;
- }
-
- float LiteralFP32() const {
- return rawbits_to_float(Literal32());
- }
-
- double LiteralFP64() const {
- return rawbits_to_double(Literal64());
- }
-
- const Instruction* NextInstruction() const {
- return this + kInstructionSize;
- }
-
- const Instruction* InstructionAtOffset(int64_t offset) const {
- VIXL_ASSERT(IsWordAligned(this + offset));
- return this + offset;
- }
-
- template<typename T> static Instruction* Cast(T src) {
- return reinterpret_cast<Instruction*>(src);
- }
-
- template<typename T> static const Instruction* CastConst(T src) {
- return reinterpret_cast<const Instruction*>(src);
- }
-
- private:
- int ImmBranch() const;
-
- static float Imm8ToFP32(uint32_t imm8);
- static double Imm8ToFP64(uint32_t imm8);
-
- void SetPCRelImmTarget(const Instruction* target);
- void SetBranchImmTarget(const Instruction* target);
-};
-
-
-// Functions for handling NEON vector format information.
-enum VectorFormat {
- kFormatUndefined = 0xffffffff,
- kFormat8B = NEON_8B,
- kFormat16B = NEON_16B,
- kFormat4H = NEON_4H,
- kFormat8H = NEON_8H,
- kFormat2S = NEON_2S,
- kFormat4S = NEON_4S,
- kFormat1D = NEON_1D,
- kFormat2D = NEON_2D,
-
- // Scalar formats. We add the scalar bit to distinguish between scalar and
- // vector enumerations; the bit is always set in the encoding of scalar ops
- // and always clear for vector ops. Although kFormatD and kFormat1D appear
- // to be the same, their meaning is subtly different. The first is a scalar
- // operation, the second a vector operation that only affects one lane.
- kFormatB = NEON_B | NEONScalar,
- kFormatH = NEON_H | NEONScalar,
- kFormatS = NEON_S | NEONScalar,
- kFormatD = NEON_D | NEONScalar
-};
-
-VectorFormat VectorFormatHalfWidth(const VectorFormat vform);
-VectorFormat VectorFormatDoubleWidth(const VectorFormat vform);
-VectorFormat VectorFormatDoubleLanes(const VectorFormat vform);
-VectorFormat VectorFormatHalfLanes(const VectorFormat vform);
-VectorFormat ScalarFormatFromLaneSize(int lanesize);
-VectorFormat VectorFormatHalfWidthDoubleLanes(const VectorFormat vform);
-VectorFormat VectorFormatFillQ(const VectorFormat vform);
-unsigned RegisterSizeInBitsFromFormat(VectorFormat vform);
-unsigned RegisterSizeInBytesFromFormat(VectorFormat vform);
-// TODO: Make the return types of these functions consistent.
-unsigned LaneSizeInBitsFromFormat(VectorFormat vform);
-int LaneSizeInBytesFromFormat(VectorFormat vform);
-int LaneSizeInBytesLog2FromFormat(VectorFormat vform);
-int LaneCountFromFormat(VectorFormat vform);
-int MaxLaneCountFromFormat(VectorFormat vform);
-bool IsVectorFormat(VectorFormat vform);
-int64_t MaxIntFromFormat(VectorFormat vform);
-int64_t MinIntFromFormat(VectorFormat vform);
-uint64_t MaxUintFromFormat(VectorFormat vform);
-
-
-enum NEONFormat {
- NF_UNDEF = 0,
- NF_8B = 1,
- NF_16B = 2,
- NF_4H = 3,
- NF_8H = 4,
- NF_2S = 5,
- NF_4S = 6,
- NF_1D = 7,
- NF_2D = 8,
- NF_B = 9,
- NF_H = 10,
- NF_S = 11,
- NF_D = 12
-};
-
-static const unsigned kNEONFormatMaxBits = 6;
-
-struct NEONFormatMap {
- // The bit positions in the instruction to consider.
- uint8_t bits[kNEONFormatMaxBits];
-
- // Mapping from concatenated bits to format.
- NEONFormat map[1 << kNEONFormatMaxBits];
-};
-
-class NEONFormatDecoder {
- public:
- enum SubstitutionMode {
- kPlaceholder,
- kFormat
- };
-
- // Construct a format decoder with increasingly specific format maps for each
- // subsitution. If no format map is specified, the default is the integer
- // format map.
- explicit NEONFormatDecoder(const Instruction* instr) {
- instrbits_ = instr->InstructionBits();
- SetFormatMaps(IntegerFormatMap());
- }
- NEONFormatDecoder(const Instruction* instr,
- const NEONFormatMap* format) {
- instrbits_ = instr->InstructionBits();
- SetFormatMaps(format);
- }
- NEONFormatDecoder(const Instruction* instr,
- const NEONFormatMap* format0,
- const NEONFormatMap* format1) {
- instrbits_ = instr->InstructionBits();
- SetFormatMaps(format0, format1);
- }
- NEONFormatDecoder(const Instruction* instr,
- const NEONFormatMap* format0,
- const NEONFormatMap* format1,
- const NEONFormatMap* format2) {
- instrbits_ = instr->InstructionBits();
- SetFormatMaps(format0, format1, format2);
- }
-
- // Set the format mapping for all or individual substitutions.
- void SetFormatMaps(const NEONFormatMap* format0,
- const NEONFormatMap* format1 = NULL,
- const NEONFormatMap* format2 = NULL) {
- VIXL_ASSERT(format0 != NULL);
- formats_[0] = format0;
- formats_[1] = (format1 == NULL) ? formats_[0] : format1;
- formats_[2] = (format2 == NULL) ? formats_[1] : format2;
- }
- void SetFormatMap(unsigned index, const NEONFormatMap* format) {
- VIXL_ASSERT(index <= (sizeof(formats_) / sizeof(formats_[0])));
- VIXL_ASSERT(format != NULL);
- formats_[index] = format;
- }
-
- // Substitute %s in the input string with the placeholder string for each
- // register, ie. "'B", "'H", etc.
- const char* SubstitutePlaceholders(const char* string) {
- return Substitute(string, kPlaceholder, kPlaceholder, kPlaceholder);
- }
-
- // Substitute %s in the input string with a new string based on the
- // substitution mode.
- const char* Substitute(const char* string,
- SubstitutionMode mode0 = kFormat,
- SubstitutionMode mode1 = kFormat,
- SubstitutionMode mode2 = kFormat) {
- snprintf(form_buffer_, sizeof(form_buffer_), string,
- GetSubstitute(0, mode0),
- GetSubstitute(1, mode1),
- GetSubstitute(2, mode2));
- return form_buffer_;
- }
-
- // Append a "2" to a mnemonic string based of the state of the Q bit.
- const char* Mnemonic(const char* mnemonic) {
- if ((instrbits_ & NEON_Q) != 0) {
- snprintf(mne_buffer_, sizeof(mne_buffer_), "%s2", mnemonic);
- return mne_buffer_;
- }
- return mnemonic;
- }
-
- VectorFormat GetVectorFormat(int format_index = 0) {
- return GetVectorFormat(formats_[format_index]);
- }
-
- VectorFormat GetVectorFormat(const NEONFormatMap* format_map) {
- static const VectorFormat vform[] = {
- kFormatUndefined,
- kFormat8B, kFormat16B, kFormat4H, kFormat8H,
- kFormat2S, kFormat4S, kFormat1D, kFormat2D,
- kFormatB, kFormatH, kFormatS, kFormatD
- };
- VIXL_ASSERT(GetNEONFormat(format_map) < (sizeof(vform) / sizeof(vform[0])));
- return vform[GetNEONFormat(format_map)];
- }
-
- // Built in mappings for common cases.
-
- // The integer format map uses three bits (Q, size<1:0>) to encode the
- // "standard" set of NEON integer vector formats.
- static const NEONFormatMap* IntegerFormatMap() {
- static const NEONFormatMap map = {
- {23, 22, 30},
- {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_UNDEF, NF_2D}
- };
- return &map;
- }
-
- // The long integer format map uses two bits (size<1:0>) to encode the
- // long set of NEON integer vector formats. These are used in narrow, wide
- // and long operations.
- static const NEONFormatMap* LongIntegerFormatMap() {
- static const NEONFormatMap map = {
- {23, 22}, {NF_8H, NF_4S, NF_2D}
- };
- return &map;
- }
-
- // The FP format map uses two bits (Q, size<0>) to encode the NEON FP vector
- // formats: NF_2S, NF_4S, NF_2D.
- static const NEONFormatMap* FPFormatMap() {
- // The FP format map assumes two bits (Q, size<0>) are used to encode the
- // NEON FP vector formats: NF_2S, NF_4S, NF_2D.
- static const NEONFormatMap map = {
- {22, 30}, {NF_2S, NF_4S, NF_UNDEF, NF_2D}
- };
- return &map;
- }
-
- // The load/store format map uses three bits (Q, 11, 10) to encode the
- // set of NEON vector formats.
- static const NEONFormatMap* LoadStoreFormatMap() {
- static const NEONFormatMap map = {
- {11, 10, 30},
- {NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}
- };
- return &map;
- }
-
- // The logical format map uses one bit (Q) to encode the NEON vector format:
- // NF_8B, NF_16B.
- static const NEONFormatMap* LogicalFormatMap() {
- static const NEONFormatMap map = {
- {30}, {NF_8B, NF_16B}
- };
- return &map;
- }
-
- // The triangular format map uses between two and five bits to encode the NEON
- // vector format:
- // xxx10->8B, xxx11->16B, xx100->4H, xx101->8H
- // x1000->2S, x1001->4S, 10001->2D, all others undefined.
- static const NEONFormatMap* TriangularFormatMap() {
- static const NEONFormatMap map = {
- {19, 18, 17, 16, 30},
- {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_2S,
- NF_4S, NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_UNDEF, NF_2D,
- NF_8B, NF_16B, NF_4H, NF_8H, NF_8B, NF_16B, NF_2S, NF_4S, NF_8B, NF_16B,
- NF_4H, NF_8H, NF_8B, NF_16B}
- };
- return &map;
- }
-
- // The scalar format map uses two bits (size<1:0>) to encode the NEON scalar
- // formats: NF_B, NF_H, NF_S, NF_D.
- static const NEONFormatMap* ScalarFormatMap() {
- static const NEONFormatMap map = {
- {23, 22}, {NF_B, NF_H, NF_S, NF_D}
- };
- return &map;
- }
-
- // The long scalar format map uses two bits (size<1:0>) to encode the longer
- // NEON scalar formats: NF_H, NF_S, NF_D.
- static const NEONFormatMap* LongScalarFormatMap() {
- static const NEONFormatMap map = {
- {23, 22}, {NF_H, NF_S, NF_D}
- };
- return &map;
- }
-
- // The FP scalar format map assumes one bit (size<0>) is used to encode the
- // NEON FP scalar formats: NF_S, NF_D.
- static const NEONFormatMap* FPScalarFormatMap() {
- static const NEONFormatMap map = {
- {22}, {NF_S, NF_D}
- };
- return &map;
- }
-
- // The triangular scalar format map uses between one and four bits to encode
- // the NEON FP scalar formats:
- // xxx1->B, xx10->H, x100->S, 1000->D, all others undefined.
- static const NEONFormatMap* TriangularScalarFormatMap() {
- static const NEONFormatMap map = {
- {19, 18, 17, 16},
- {NF_UNDEF, NF_B, NF_H, NF_B, NF_S, NF_B, NF_H, NF_B,
- NF_D, NF_B, NF_H, NF_B, NF_S, NF_B, NF_H, NF_B}
- };
- return &map;
- }
-
- private:
- // Get a pointer to a string that represents the format or placeholder for
- // the specified substitution index, based on the format map and instruction.
- const char* GetSubstitute(int index, SubstitutionMode mode) {
- if (mode == kFormat) {
- return NEONFormatAsString(GetNEONFormat(formats_[index]));
- }
- VIXL_ASSERT(mode == kPlaceholder);
- return NEONFormatAsPlaceholder(GetNEONFormat(formats_[index]));
- }
-
- // Get the NEONFormat enumerated value for bits obtained from the
- // instruction based on the specified format mapping.
- NEONFormat GetNEONFormat(const NEONFormatMap* format_map) {
- return format_map->map[PickBits(format_map->bits)];
- }
-
- // Convert a NEONFormat into a string.
- static const char* NEONFormatAsString(NEONFormat format) {
- static const char* formats[] = {
- "undefined",
- "8b", "16b", "4h", "8h", "2s", "4s", "1d", "2d",
- "b", "h", "s", "d"
- };
- VIXL_ASSERT(format < (sizeof(formats) / sizeof(formats[0])));
- return formats[format];
- }
-
- // Convert a NEONFormat into a register placeholder string.
- static const char* NEONFormatAsPlaceholder(NEONFormat format) {
- VIXL_ASSERT((format == NF_B) || (format == NF_H) ||
- (format == NF_S) || (format == NF_D) ||
- (format == NF_UNDEF));
- static const char* formats[] = {
- "undefined",
- "undefined", "undefined", "undefined", "undefined",
- "undefined", "undefined", "undefined", "undefined",
- "'B", "'H", "'S", "'D"
- };
- return formats[format];
- }
-
- // Select bits from instrbits_ defined by the bits array, concatenate them,
- // and return the value.
- uint8_t PickBits(const uint8_t bits[]) {
- uint8_t result = 0;
- for (unsigned b = 0; b < kNEONFormatMaxBits; b++) {
- if (bits[b] == 0) break;
- result <<= 1;
- result |= ((instrbits_ & (1 << bits[b])) == 0) ? 0 : 1;
- }
- return result;
- }
-
- Instr instrbits_;
- const NEONFormatMap* formats_[3];
- char form_buffer_[64];
- char mne_buffer_[16];
-};
-} // namespace vixl
-
-#endif // VIXL_A64_INSTRUCTIONS_A64_H_