// 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.
// 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. constunsigned kPageSize = 4 * KBytes; constunsigned kPageSizeLog2 = 12;
// The classes of immediate branch ranges, in order of increasing range. // Note that CondBranchType and CompareBranchType have the same range. enum ImmBranchRangeType {
TestBranchRangeType, // tbz/tbnz: imm14 = +/- 32KB.
CondBranchRangeType, // b.cond/cbz/cbnz: imm19 = +/- 1MB.
UncondBranchRangeType, // b/bl: imm26 = +/- 128MB.
UnknownBranchRangeType,
// Number of 'short-range' branch range types. // We don't consider unconditional branches 'short-range'.
NumShortBranchRangeTypes = UncondBranchRangeType
};
// 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 ExtractSignedBitfield32(width - 1, 0, offset);
}
// Check if offset can be encoded as a RAW offset in a branch_type // instruction. The offset must be encodeable directly as the immediate field // in the instruction, it is not scaled by kInstructionSize first. staticbool IsValidImmPCOffset(ImmBranchType branch_type, int64_t offset);
// Get the range type corresponding to a branch type. static ImmBranchRangeType ImmBranchTypeToRange(ImmBranchType);
// Get the maximum realizable forward PC offset (in bytes) for an immediate // branch of the given range type. // This is the largest positive multiple of kInstructionSize, offset, such // that: // // IsValidImmPCOffset(xxx, offset / kInstructionSize) // // returns true for the same branch type. static int32_t ImmBranchMaxForwardOffset(ImmBranchRangeType range_type);
// Get the minimuum realizable backward PC offset (in bytes) for an immediate // branch of the given range type. // This is the smallest (i.e., largest in magnitude) negative multiple of // kInstructionSize, offset, such that: // // IsValidImmPCOffset(xxx, offset / kInstructionSize) // // returns true for the same branch type. static int32_t ImmBranchMinBackwardOffset(ImmBranchRangeType range_type);
// 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;
}
// 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]. staticconstint kLoadLiteralImmBitwidth = 19; staticconstint 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);
// Skip any constant pools with artificial guards at this point. // Return either |this| or the first instruction after the pool. const Instruction* skipPool() const;
// 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);
// Substitute %s in the input string with the placeholder string for each // register, ie. "'B", "'H", etc. constchar* SubstitutePlaceholders(constchar* string) { return Substitute(string, kPlaceholder, kPlaceholder, kPlaceholder);
}
// Substitute %s in the input string with a new string based on the // substitution mode. constchar* Substitute(constchar* 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. constchar* Mnemonic(constchar* mnemonic) { if ((instrbits_ & NEON_Q) != 0) {
snprintf(mne_buffer_, sizeof(mne_buffer_), "%s2", mnemonic); return mne_buffer_;
} return mnemonic;
}
// The integer format map uses three bits (Q, size<1:0>) to encode the // "standard" set of NEON integer vector formats. staticconst NEONFormatMap* IntegerFormatMap() { staticconst NEONFormatMap map = {
{23, 22, 30},
{NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_UNDEF, NF_2D}
}; return ↦
}
// 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. staticconst NEONFormatMap* LongIntegerFormatMap() { staticconst NEONFormatMap map = {
{23, 22}, {NF_8H, NF_4S, NF_2D}
}; return ↦
}
// The FP format map uses two bits (Q, size<0>) to encode the NEON FP vector // formats: NF_2S, NF_4S, NF_2D. staticconst 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. staticconst NEONFormatMap map = {
{22, 30}, {NF_2S, NF_4S, NF_UNDEF, NF_2D}
}; return ↦
}
// The load/store format map uses three bits (Q, 11, 10) to encode the // set of NEON vector formats. staticconst NEONFormatMap* LoadStoreFormatMap() { staticconst NEONFormatMap map = {
{11, 10, 30},
{NF_8B, NF_16B, NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}
}; return ↦
}
// The logical format map uses one bit (Q) to encode the NEON vector format: // NF_8B, NF_16B. staticconst NEONFormatMap* LogicalFormatMap() { staticconst NEONFormatMap map = {
{30}, {NF_8B, NF_16B}
}; return ↦
}
// 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. staticconst NEONFormatMap* TriangularFormatMap() { staticconst 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 ↦
}
// The scalar format map uses two bits (size<1:0>) to encode the NEON scalar // formats: NF_B, NF_H, NF_S, NF_D. staticconst NEONFormatMap* ScalarFormatMap() { staticconst NEONFormatMap map = {
{23, 22}, {NF_B, NF_H, NF_S, NF_D}
}; return ↦
}
// The long scalar format map uses two bits (size<1:0>) to encode the longer // NEON scalar formats: NF_H, NF_S, NF_D. staticconst NEONFormatMap* LongScalarFormatMap() { staticconst NEONFormatMap map = {
{23, 22}, {NF_H, NF_S, NF_D}
}; return ↦
}
// The FP scalar format map assumes one bit (size<0>) is used to encode the // NEON FP scalar formats: NF_S, NF_D. staticconst NEONFormatMap* FPScalarFormatMap() { staticconst NEONFormatMap map = {
{22}, {NF_S, NF_D}
}; return ↦
}
// 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. staticconst NEONFormatMap* TriangularScalarFormatMap() { staticconst 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 ↦
}
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. constchar* 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)];
}
// 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;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.