mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
disas/libvixl: Update to upstream VIXL 1.7
Update our copy of libvixl to upstream's 1.7 release.
This includes upstream's fix for the issue we had a local
patch for in commit 94cc44a9e.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1422274779-13359-2-git-send-email-peter.maydell@linaro.org
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
The code in this directory is a subset of libvixl:
|
||||
https://github.com/armvixl/vixl
|
||||
(specifically, it is the set of files needed for disassembly only,
|
||||
taken from libvixl 1.6).
|
||||
taken from libvixl 1.7).
|
||||
Bugfixes should preferably be sent upstream initially.
|
||||
|
||||
The disassembler does not currently support the entire A64 instruction
|
||||
|
||||
+177
-113
File diff suppressed because it is too large
Load Diff
@@ -31,12 +31,6 @@ namespace vixl {
|
||||
|
||||
const unsigned kNumberOfRegisters = 32;
|
||||
const unsigned kNumberOfFPRegisters = 32;
|
||||
// Callee saved registers are x21-x30(lr).
|
||||
const int kNumberOfCalleeSavedRegisters = 10;
|
||||
const int kFirstCalleeSavedRegisterIndex = 21;
|
||||
// Callee saved FP registers are d8-d15.
|
||||
const int kNumberOfCalleeSavedFPRegisters = 8;
|
||||
const int kFirstCalleeSavedFPRegisterIndex = 8;
|
||||
|
||||
#define REGISTER_CODE_LIST(R) \
|
||||
R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \
|
||||
@@ -53,7 +47,6 @@ V_(Ra, 14, 10, Bits) /* Third source register. */ \
|
||||
V_(Rt, 4, 0, Bits) /* Load/store register. */ \
|
||||
V_(Rt2, 14, 10, Bits) /* Load/store second register. */ \
|
||||
V_(Rs, 20, 16, Bits) /* Exclusive access status. */ \
|
||||
V_(PrefetchMode, 4, 0, Bits) \
|
||||
\
|
||||
/* Common bits */ \
|
||||
V_(SixtyFourBits, 31, 31, Bits) \
|
||||
@@ -109,6 +102,10 @@ V_(ImmLSUnsigned, 21, 10, Bits) \
|
||||
V_(ImmLSPair, 21, 15, SignedBits) \
|
||||
V_(SizeLS, 31, 30, Bits) \
|
||||
V_(ImmShiftLS, 12, 12, Bits) \
|
||||
V_(ImmPrefetchOperation, 4, 0, Bits) \
|
||||
V_(PrefetchHint, 4, 3, Bits) \
|
||||
V_(PrefetchTarget, 2, 1, Bits) \
|
||||
V_(PrefetchStream, 0, 0, Bits) \
|
||||
\
|
||||
/* Other immediates */ \
|
||||
V_(ImmUncondBranch, 25, 0, SignedBits) \
|
||||
@@ -269,6 +266,29 @@ enum BarrierType {
|
||||
BarrierAll = 3
|
||||
};
|
||||
|
||||
enum PrefetchOperation {
|
||||
PLDL1KEEP = 0x00,
|
||||
PLDL1STRM = 0x01,
|
||||
PLDL2KEEP = 0x02,
|
||||
PLDL2STRM = 0x03,
|
||||
PLDL3KEEP = 0x04,
|
||||
PLDL3STRM = 0x05,
|
||||
|
||||
PLIL1KEEP = 0x08,
|
||||
PLIL1STRM = 0x09,
|
||||
PLIL2KEEP = 0x0a,
|
||||
PLIL2STRM = 0x0b,
|
||||
PLIL3KEEP = 0x0c,
|
||||
PLIL3STRM = 0x0d,
|
||||
|
||||
PSTL1KEEP = 0x10,
|
||||
PSTL1STRM = 0x11,
|
||||
PSTL2KEEP = 0x12,
|
||||
PSTL2STRM = 0x13,
|
||||
PSTL3KEEP = 0x14,
|
||||
PSTL3STRM = 0x15
|
||||
};
|
||||
|
||||
// System/special register names.
|
||||
// This information is not encoded as one field but as the concatenation of
|
||||
// multiple fields (Op0<0>, Op1, Crn, Crm, Op2).
|
||||
@@ -605,6 +625,12 @@ enum LoadStoreAnyOp {
|
||||
LoadStoreAnyFixed = 0x08000000
|
||||
};
|
||||
|
||||
// Any load pair or store pair.
|
||||
enum LoadStorePairAnyOp {
|
||||
LoadStorePairAnyFMask = 0x3a000000,
|
||||
LoadStorePairAnyFixed = 0x28000000
|
||||
};
|
||||
|
||||
#define LOAD_STORE_PAIR_OP_LIST(V) \
|
||||
V(STP, w, 0x00000000), \
|
||||
V(LDP, w, 0x00400000), \
|
||||
@@ -703,17 +729,6 @@ enum LoadLiteralOp {
|
||||
V(LD, R, d, 0xC4400000)
|
||||
|
||||
|
||||
// Load/store unscaled offset.
|
||||
enum LoadStoreUnscaledOffsetOp {
|
||||
LoadStoreUnscaledOffsetFixed = 0x38000000,
|
||||
LoadStoreUnscaledOffsetFMask = 0x3B200C00,
|
||||
LoadStoreUnscaledOffsetMask = 0xFFE00C00,
|
||||
#define LOAD_STORE_UNSCALED(A, B, C, D) \
|
||||
A##U##B##_##C = LoadStoreUnscaledOffsetFixed | D
|
||||
LOAD_STORE_OP_LIST(LOAD_STORE_UNSCALED)
|
||||
#undef LOAD_STORE_UNSCALED
|
||||
};
|
||||
|
||||
// Load/store (post, pre, offset and unsigned.)
|
||||
enum LoadStoreOp {
|
||||
LoadStoreOpMask = 0xC4C00000,
|
||||
@@ -724,6 +739,18 @@ enum LoadStoreOp {
|
||||
PRFM = 0xC0800000
|
||||
};
|
||||
|
||||
// Load/store unscaled offset.
|
||||
enum LoadStoreUnscaledOffsetOp {
|
||||
LoadStoreUnscaledOffsetFixed = 0x38000000,
|
||||
LoadStoreUnscaledOffsetFMask = 0x3B200C00,
|
||||
LoadStoreUnscaledOffsetMask = 0xFFE00C00,
|
||||
PRFUM = LoadStoreUnscaledOffsetFixed | PRFM,
|
||||
#define LOAD_STORE_UNSCALED(A, B, C, D) \
|
||||
A##U##B##_##C = LoadStoreUnscaledOffsetFixed | D
|
||||
LOAD_STORE_OP_LIST(LOAD_STORE_UNSCALED)
|
||||
#undef LOAD_STORE_UNSCALED
|
||||
};
|
||||
|
||||
// Load/store post index.
|
||||
enum LoadStorePostIndex {
|
||||
LoadStorePostIndexFixed = 0x38000400,
|
||||
|
||||
@@ -108,7 +108,7 @@ class DecoderVisitor {
|
||||
}
|
||||
|
||||
private:
|
||||
VisitorConstness constness_;
|
||||
const VisitorConstness constness_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+118
-20
@@ -34,6 +34,7 @@ Disassembler::Disassembler() {
|
||||
buffer_ = reinterpret_cast<char*>(malloc(buffer_size_));
|
||||
buffer_pos_ = 0;
|
||||
own_buffer_ = true;
|
||||
code_address_offset_ = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +43,7 @@ Disassembler::Disassembler(char* text_buffer, int buffer_size) {
|
||||
buffer_ = text_buffer;
|
||||
buffer_pos_ = 0;
|
||||
own_buffer_ = false;
|
||||
code_address_offset_ = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -739,9 +741,25 @@ void Disassembler::VisitMoveWideImmediate(const Instruction* instr) {
|
||||
// shift calculation.
|
||||
switch (instr->Mask(MoveWideImmediateMask)) {
|
||||
case MOVN_w:
|
||||
case MOVN_x: mnemonic = "movn"; break;
|
||||
case MOVN_x:
|
||||
if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0)) {
|
||||
if ((instr->SixtyFourBits() == 0) && (instr->ImmMoveWide() == 0xffff)) {
|
||||
mnemonic = "movn";
|
||||
} else {
|
||||
mnemonic = "mov";
|
||||
form = "'Rd, 'IMoveNeg";
|
||||
}
|
||||
} else {
|
||||
mnemonic = "movn";
|
||||
}
|
||||
break;
|
||||
case MOVZ_w:
|
||||
case MOVZ_x: mnemonic = "movz"; break;
|
||||
case MOVZ_x:
|
||||
if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0))
|
||||
mnemonic = "mov";
|
||||
else
|
||||
mnemonic = "movz";
|
||||
break;
|
||||
case MOVK_w:
|
||||
case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
@@ -806,7 +824,7 @@ void Disassembler::VisitLoadStoreUnsignedOffset(const Instruction* instr) {
|
||||
case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break;
|
||||
LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
|
||||
#undef LS_UNSIGNEDOFFSET
|
||||
case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xn'ILU]";
|
||||
case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xns'ILU]";
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -833,6 +851,7 @@ void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction* instr) {
|
||||
const char *form_x = "'Xt, ['Xns'ILS]";
|
||||
const char *form_s = "'St, ['Xns'ILS]";
|
||||
const char *form_d = "'Dt, ['Xns'ILS]";
|
||||
const char *form_prefetch = "'PrefOp, ['Xns'ILS]";
|
||||
|
||||
switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
|
||||
case STURB_w: mnemonic = "sturb"; break;
|
||||
@@ -852,6 +871,7 @@ void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction* instr) {
|
||||
case LDURSH_x: form = form_x; // Fall through.
|
||||
case LDURSH_w: mnemonic = "ldursh"; break;
|
||||
case LDURSW_x: mnemonic = "ldursw"; form = form_x; break;
|
||||
case PRFUM: mnemonic = "prfum"; form = form_prefetch; break;
|
||||
default: form = "(LoadStoreUnscaledOffset)";
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
@@ -872,6 +892,11 @@ void Disassembler::VisitLoadLiteral(const Instruction* instr) {
|
||||
form = "'Xt, 'ILLiteral 'LValue";
|
||||
break;
|
||||
}
|
||||
case PRFM_lit: {
|
||||
mnemonic = "prfm";
|
||||
form = "'PrefOp, 'ILLiteral 'LValue";
|
||||
break;
|
||||
}
|
||||
default: mnemonic = "unimplemented";
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
@@ -1344,7 +1369,7 @@ void Disassembler::AppendPCRelativeOffsetToOutput(const Instruction* instr,
|
||||
void Disassembler::AppendAddressToOutput(const Instruction* instr,
|
||||
const void* addr) {
|
||||
USE(instr);
|
||||
AppendToOutput("(addr %p)", addr);
|
||||
AppendToOutput("(addr 0x%" PRIxPTR ")", reinterpret_cast<uintptr_t>(addr));
|
||||
}
|
||||
|
||||
|
||||
@@ -1360,6 +1385,40 @@ void Disassembler::AppendDataAddressToOutput(const Instruction* instr,
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::AppendCodeRelativeAddressToOutput(const Instruction* instr,
|
||||
const void* addr) {
|
||||
USE(instr);
|
||||
int64_t rel_addr = CodeRelativeAddress(addr);
|
||||
if (rel_addr >= 0) {
|
||||
AppendToOutput("(addr 0x%" PRIx64 ")", rel_addr);
|
||||
} else {
|
||||
AppendToOutput("(addr -0x%" PRIx64 ")", -rel_addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::AppendCodeRelativeCodeAddressToOutput(
|
||||
const Instruction* instr, const void* addr) {
|
||||
AppendCodeRelativeAddressToOutput(instr, addr);
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::AppendCodeRelativeDataAddressToOutput(
|
||||
const Instruction* instr, const void* addr) {
|
||||
AppendCodeRelativeAddressToOutput(instr, addr);
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::MapCodeAddress(int64_t base_address,
|
||||
const Instruction* instr_address) {
|
||||
set_code_address_offset(
|
||||
base_address - reinterpret_cast<intptr_t>(instr_address));
|
||||
}
|
||||
int64_t Disassembler::CodeRelativeAddress(const void* addr) {
|
||||
return reinterpret_cast<intptr_t>(addr) + code_address_offset();
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::Format(const Instruction* instr, const char* mnemonic,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(mnemonic != NULL);
|
||||
@@ -1486,16 +1545,20 @@ int Disassembler::SubstituteImmediateField(const Instruction* instr,
|
||||
VIXL_ASSERT(format[0] == 'I');
|
||||
|
||||
switch (format[1]) {
|
||||
case 'M': { // IMoveImm or IMoveLSL.
|
||||
if (format[5] == 'I') {
|
||||
uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
|
||||
AppendToOutput("#0x%" PRIx64, imm);
|
||||
} else {
|
||||
VIXL_ASSERT(format[5] == 'L');
|
||||
case 'M': { // IMoveImm, IMoveNeg or IMoveLSL.
|
||||
if (format[5] == 'L') {
|
||||
AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
|
||||
if (instr->ShiftMoveWide() > 0) {
|
||||
AppendToOutput(", lsl #%" PRId64, 16 * instr->ShiftMoveWide());
|
||||
}
|
||||
} else {
|
||||
VIXL_ASSERT((format[5] == 'I') || (format[5] == 'N'));
|
||||
uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
|
||||
if (format[5] == 'N')
|
||||
imm = ~imm;
|
||||
if (!instr->SixtyFourBits())
|
||||
imm &= UINT64_C(0xffffffff);
|
||||
AppendToOutput("#0x%" PRIx64, imm);
|
||||
}
|
||||
return 8;
|
||||
}
|
||||
@@ -1634,14 +1697,31 @@ int Disassembler::SubstituteLiteralField(const Instruction* instr,
|
||||
VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);
|
||||
USE(format);
|
||||
|
||||
const void * address = instr->LiteralAddress<const void *>();
|
||||
switch (instr->Mask(LoadLiteralMask)) {
|
||||
case LDR_w_lit:
|
||||
case LDR_x_lit:
|
||||
case LDRSW_x_lit:
|
||||
case LDR_s_lit:
|
||||
case LDR_d_lit:
|
||||
AppendDataAddressToOutput(instr, instr->LiteralAddress());
|
||||
AppendCodeRelativeDataAddressToOutput(instr, address);
|
||||
break;
|
||||
case PRFM_lit: {
|
||||
// Use the prefetch hint to decide how to print the address.
|
||||
switch (instr->PrefetchHint()) {
|
||||
case 0x0: // PLD: prefetch for load.
|
||||
case 0x2: // PST: prepare for store.
|
||||
AppendCodeRelativeDataAddressToOutput(instr, address);
|
||||
break;
|
||||
case 0x1: // PLI: preload instructions.
|
||||
AppendCodeRelativeCodeAddressToOutput(instr, address);
|
||||
break;
|
||||
case 0x3: // Unallocated hint.
|
||||
AppendCodeRelativeAddressToOutput(instr, address);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
VIXL_UNREACHABLE();
|
||||
}
|
||||
@@ -1701,17 +1781,22 @@ int Disassembler::SubstitutePCRelAddressField(const Instruction* instr,
|
||||
(strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`.
|
||||
|
||||
int64_t offset = instr->ImmPCRel();
|
||||
const Instruction * base = instr;
|
||||
|
||||
// Compute the target address based on the effective address (after applying
|
||||
// code_address_offset). This is required for correct behaviour of adrp.
|
||||
const Instruction* base = instr + code_address_offset();
|
||||
if (format[9] == 'P') {
|
||||
offset *= kPageSize;
|
||||
base = AlignDown(base, kPageSize);
|
||||
}
|
||||
// Strip code_address_offset before printing, so we can use the
|
||||
// semantically-correct AppendCodeRelativeAddressToOutput.
|
||||
const void* target =
|
||||
reinterpret_cast<const void*>(base + offset - code_address_offset());
|
||||
|
||||
const void* target = reinterpret_cast<const void*>(base + offset);
|
||||
AppendPCRelativeOffsetToOutput(instr, offset);
|
||||
AppendToOutput(" ");
|
||||
AppendAddressToOutput(instr, target);
|
||||
AppendCodeRelativeAddressToOutput(instr, target);
|
||||
return 13;
|
||||
}
|
||||
|
||||
@@ -1738,7 +1823,7 @@ int Disassembler::SubstituteBranchTargetField(const Instruction* instr,
|
||||
|
||||
AppendPCRelativeOffsetToOutput(instr, offset);
|
||||
AppendToOutput(" ");
|
||||
AppendCodeAddressToOutput(instr, target_address);
|
||||
AppendCodeRelativeCodeAddressToOutput(instr, target_address);
|
||||
|
||||
return 8;
|
||||
}
|
||||
@@ -1805,13 +1890,26 @@ int Disassembler::SubstitutePrefetchField(const Instruction* instr,
|
||||
VIXL_ASSERT(format[0] == 'P');
|
||||
USE(format);
|
||||
|
||||
int prefetch_mode = instr->PrefetchMode();
|
||||
static const char* hints[] = {"ld", "li", "st"};
|
||||
static const char* stream_options[] = {"keep", "strm"};
|
||||
|
||||
const char* ls = (prefetch_mode & 0x10) ? "st" : "ld";
|
||||
int level = (prefetch_mode >> 1) + 1;
|
||||
const char* ks = (prefetch_mode & 1) ? "strm" : "keep";
|
||||
unsigned hint = instr->PrefetchHint();
|
||||
unsigned target = instr->PrefetchTarget() + 1;
|
||||
unsigned stream = instr->PrefetchStream();
|
||||
|
||||
AppendToOutput("p%sl%d%s", ls, level, ks);
|
||||
if ((hint >= (sizeof(hints) / sizeof(hints[0]))) || (target > 3)) {
|
||||
// Unallocated prefetch operations.
|
||||
int prefetch_mode = instr->ImmPrefetchOperation();
|
||||
AppendToOutput("#0b%c%c%c%c%c",
|
||||
(prefetch_mode & (1 << 4)) ? '1' : '0',
|
||||
(prefetch_mode & (1 << 3)) ? '1' : '0',
|
||||
(prefetch_mode & (1 << 2)) ? '1' : '0',
|
||||
(prefetch_mode & (1 << 1)) ? '1' : '0',
|
||||
(prefetch_mode & (1 << 0)) ? '1' : '0');
|
||||
} else {
|
||||
VIXL_ASSERT(stream < (sizeof(stream_options) / sizeof(stream_options[0])));
|
||||
AppendToOutput("p%sl%d%s", hints[hint], target, stream_options[stream]);
|
||||
}
|
||||
return 6;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class Disassembler: public DecoderVisitor {
|
||||
char* GetOutput();
|
||||
|
||||
// Declare all Visitor functions.
|
||||
#define DECLARE(A) void Visit##A(const Instruction* instr);
|
||||
#define DECLARE(A) virtual void Visit##A(const Instruction* instr);
|
||||
VISITOR_LIST(DECLARE)
|
||||
#undef DECLARE
|
||||
|
||||
@@ -65,23 +65,45 @@ class Disassembler: public DecoderVisitor {
|
||||
|
||||
// Prints an address, in the general case. It can be code or data. This is
|
||||
// used for example to print the target address of an ADR instruction.
|
||||
virtual void AppendAddressToOutput(const Instruction* instr,
|
||||
const void* addr);
|
||||
virtual void AppendCodeRelativeAddressToOutput(const Instruction* instr,
|
||||
const void* addr);
|
||||
|
||||
// Prints the address of some code.
|
||||
// This is used for example to print the target address of a branch to an
|
||||
// immediate offset.
|
||||
// A sub-class can for example override this method to lookup the address and
|
||||
// print an appropriate name.
|
||||
virtual void AppendCodeAddressToOutput(const Instruction* instr,
|
||||
const void* addr);
|
||||
virtual void AppendCodeRelativeCodeAddressToOutput(const Instruction* instr,
|
||||
const void* addr);
|
||||
|
||||
// Prints the address of some data.
|
||||
// This is used for example to print the source address of a load literal
|
||||
// instruction.
|
||||
virtual void AppendCodeRelativeDataAddressToOutput(const Instruction* instr,
|
||||
const void* addr);
|
||||
|
||||
// Same as the above, but for addresses that are not relative to the code
|
||||
// buffer. They are currently not used by VIXL.
|
||||
virtual void AppendAddressToOutput(const Instruction* instr,
|
||||
const void* addr);
|
||||
virtual void AppendCodeAddressToOutput(const Instruction* instr,
|
||||
const void* addr);
|
||||
virtual void AppendDataAddressToOutput(const Instruction* instr,
|
||||
const void* addr);
|
||||
|
||||
public:
|
||||
// Get/Set the offset that should be added to code addresses when printing
|
||||
// code-relative addresses in the AppendCodeRelative<Type>AddressToOutput()
|
||||
// helpers.
|
||||
// Below is an example of how a branch immediate instruction in memory at
|
||||
// address 0xb010200 would disassemble with different offsets.
|
||||
// Base address | Disassembly
|
||||
// 0x0 | 0xb010200: b #+0xcc (addr 0xb0102cc)
|
||||
// 0x10000 | 0xb000200: b #+0xcc (addr 0xb0002cc)
|
||||
// 0xb010200 | 0x0: b #+0xcc (addr 0xcc)
|
||||
void MapCodeAddress(int64_t base_address, const Instruction* instr_address);
|
||||
int64_t CodeRelativeAddress(const void* instr);
|
||||
|
||||
private:
|
||||
void Format(
|
||||
const Instruction* instr, const char* mnemonic, const char* format);
|
||||
@@ -101,32 +123,40 @@ class Disassembler: public DecoderVisitor {
|
||||
int SubstitutePrefetchField(const Instruction* instr, const char* format);
|
||||
int SubstituteBarrierField(const Instruction* instr, const char* format);
|
||||
|
||||
inline bool RdIsZROrSP(const Instruction* instr) const {
|
||||
bool RdIsZROrSP(const Instruction* instr) const {
|
||||
return (instr->Rd() == kZeroRegCode);
|
||||
}
|
||||
|
||||
inline bool RnIsZROrSP(const Instruction* instr) const {
|
||||
bool RnIsZROrSP(const Instruction* instr) const {
|
||||
return (instr->Rn() == kZeroRegCode);
|
||||
}
|
||||
|
||||
inline bool RmIsZROrSP(const Instruction* instr) const {
|
||||
bool RmIsZROrSP(const Instruction* instr) const {
|
||||
return (instr->Rm() == kZeroRegCode);
|
||||
}
|
||||
|
||||
inline bool RaIsZROrSP(const Instruction* instr) const {
|
||||
bool RaIsZROrSP(const Instruction* instr) const {
|
||||
return (instr->Ra() == kZeroRegCode);
|
||||
}
|
||||
|
||||
bool IsMovzMovnImm(unsigned reg_size, uint64_t value);
|
||||
|
||||
int64_t code_address_offset() const { return code_address_offset_; }
|
||||
|
||||
protected:
|
||||
void ResetOutput();
|
||||
void AppendToOutput(const char* string, ...) PRINTF_CHECK(2, 3);
|
||||
|
||||
void set_code_address_offset(int64_t code_address_offset) {
|
||||
code_address_offset_ = code_address_offset;
|
||||
}
|
||||
|
||||
char* buffer_;
|
||||
uint32_t buffer_pos_;
|
||||
uint32_t buffer_size_;
|
||||
bool own_buffer_;
|
||||
|
||||
int64_t code_address_offset_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -30,6 +30,20 @@
|
||||
namespace vixl {
|
||||
|
||||
|
||||
// Floating-point infinity values.
|
||||
const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000);
|
||||
const float kFP32NegativeInfinity = rawbits_to_float(0xff800000);
|
||||
const double kFP64PositiveInfinity =
|
||||
rawbits_to_double(UINT64_C(0x7ff0000000000000));
|
||||
const double kFP64NegativeInfinity =
|
||||
rawbits_to_double(UINT64_C(0xfff0000000000000));
|
||||
|
||||
|
||||
// The default NaN values (for FPCR.DN=1).
|
||||
const double kFP64DefaultNaN = rawbits_to_double(UINT64_C(0x7ff8000000000000));
|
||||
const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000);
|
||||
|
||||
|
||||
static uint64_t RotateRight(uint64_t value,
|
||||
unsigned int rotate,
|
||||
unsigned int width) {
|
||||
@@ -54,6 +68,55 @@ static uint64_t RepeatBitsAcrossReg(unsigned reg_size,
|
||||
}
|
||||
|
||||
|
||||
bool Instruction::IsLoad() const {
|
||||
if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) {
|
||||
return Mask(LoadStorePairLBit) != 0;
|
||||
} else {
|
||||
LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreOpMask));
|
||||
switch (op) {
|
||||
case LDRB_w:
|
||||
case LDRH_w:
|
||||
case LDR_w:
|
||||
case LDR_x:
|
||||
case LDRSB_w:
|
||||
case LDRSB_x:
|
||||
case LDRSH_w:
|
||||
case LDRSH_x:
|
||||
case LDRSW_x:
|
||||
case LDR_s:
|
||||
case LDR_d: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Instruction::IsStore() const {
|
||||
if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) {
|
||||
return Mask(LoadStorePairLBit) == 0;
|
||||
} else {
|
||||
LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreOpMask));
|
||||
switch (op) {
|
||||
case STRB_w:
|
||||
case STRH_w:
|
||||
case STR_w:
|
||||
case STR_x:
|
||||
case STR_s:
|
||||
case STR_d: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Logical immediates can't encode zero, so a return value of zero is used to
|
||||
// indicate a failure case. Specifically, where the constraints on imm_s are
|
||||
// not met.
|
||||
|
||||
@@ -96,6 +96,17 @@ const unsigned kDoubleExponentBits = 11;
|
||||
const unsigned kFloatMantissaBits = 23;
|
||||
const unsigned kFloatExponentBits = 8;
|
||||
|
||||
// Floating-point infinity values.
|
||||
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 double kFP64DefaultNaN;
|
||||
extern const float kFP32DefaultNaN;
|
||||
|
||||
|
||||
enum LSDataSize {
|
||||
LSByte = 0,
|
||||
LSHalfword = 1,
|
||||
@@ -140,33 +151,33 @@ enum Reg31Mode {
|
||||
|
||||
class Instruction {
|
||||
public:
|
||||
inline Instr InstructionBits() const {
|
||||
Instr InstructionBits() const {
|
||||
return *(reinterpret_cast<const Instr*>(this));
|
||||
}
|
||||
|
||||
inline void SetInstructionBits(Instr new_instr) {
|
||||
void SetInstructionBits(Instr new_instr) {
|
||||
*(reinterpret_cast<Instr*>(this)) = new_instr;
|
||||
}
|
||||
|
||||
inline int Bit(int pos) const {
|
||||
int Bit(int pos) const {
|
||||
return (InstructionBits() >> pos) & 1;
|
||||
}
|
||||
|
||||
inline uint32_t Bits(int msb, int lsb) const {
|
||||
uint32_t Bits(int msb, int lsb) const {
|
||||
return unsigned_bitextract_32(msb, lsb, InstructionBits());
|
||||
}
|
||||
|
||||
inline int32_t SignedBits(int msb, int lsb) const {
|
||||
int32_t SignedBits(int msb, int lsb) const {
|
||||
int32_t bits = *(reinterpret_cast<const int32_t*>(this));
|
||||
return signed_bitextract_32(msb, lsb, bits);
|
||||
}
|
||||
|
||||
inline Instr Mask(uint32_t mask) const {
|
||||
Instr Mask(uint32_t mask) const {
|
||||
return InstructionBits() & mask;
|
||||
}
|
||||
|
||||
#define DEFINE_GETTER(Name, HighBit, LowBit, Func) \
|
||||
inline int64_t Name() const { return Func(HighBit, LowBit); }
|
||||
int64_t Name() const { return Func(HighBit, LowBit); }
|
||||
INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)
|
||||
#undef DEFINE_GETTER
|
||||
|
||||
@@ -182,56 +193,64 @@ class Instruction {
|
||||
float ImmFP32() const;
|
||||
double ImmFP64() const;
|
||||
|
||||
inline LSDataSize SizeLSPair() const {
|
||||
LSDataSize SizeLSPair() const {
|
||||
return CalcLSPairDataSize(
|
||||
static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
|
||||
}
|
||||
|
||||
// Helpers.
|
||||
inline bool IsCondBranchImm() const {
|
||||
bool IsCondBranchImm() const {
|
||||
return Mask(ConditionalBranchFMask) == ConditionalBranchFixed;
|
||||
}
|
||||
|
||||
inline bool IsUncondBranchImm() const {
|
||||
bool IsUncondBranchImm() const {
|
||||
return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed;
|
||||
}
|
||||
|
||||
inline bool IsCompareBranch() const {
|
||||
bool IsCompareBranch() const {
|
||||
return Mask(CompareBranchFMask) == CompareBranchFixed;
|
||||
}
|
||||
|
||||
inline bool IsTestBranch() const {
|
||||
bool IsTestBranch() const {
|
||||
return Mask(TestBranchFMask) == TestBranchFixed;
|
||||
}
|
||||
|
||||
inline bool IsPCRelAddressing() const {
|
||||
bool IsPCRelAddressing() const {
|
||||
return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
|
||||
}
|
||||
|
||||
inline bool IsLogicalImmediate() const {
|
||||
bool IsLogicalImmediate() const {
|
||||
return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
|
||||
}
|
||||
|
||||
inline bool IsAddSubImmediate() const {
|
||||
bool IsAddSubImmediate() const {
|
||||
return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
|
||||
}
|
||||
|
||||
inline bool IsAddSubExtended() const {
|
||||
bool IsAddSubExtended() const {
|
||||
return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
|
||||
}
|
||||
|
||||
inline bool IsLoadOrStore() const {
|
||||
bool IsLoadOrStore() const {
|
||||
return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed;
|
||||
}
|
||||
|
||||
inline bool IsMovn() const {
|
||||
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);
|
||||
}
|
||||
|
||||
// Indicate whether Rd can be the stack pointer or the zero register. This
|
||||
// does not check that the instruction actually has an Rd field.
|
||||
inline Reg31Mode RdMode() const {
|
||||
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.
|
||||
@@ -260,7 +279,7 @@ class Instruction {
|
||||
|
||||
// Indicate whether Rn can be the stack pointer or the zero register. This
|
||||
// does not check that the instruction actually has an Rn field.
|
||||
inline Reg31Mode RnMode() const {
|
||||
Reg31Mode RnMode() const {
|
||||
// The following instructions use sp or wsp as Rn:
|
||||
// All loads and stores.
|
||||
// Add/sub (immediate).
|
||||
@@ -272,7 +291,7 @@ class Instruction {
|
||||
return Reg31IsZeroRegister;
|
||||
}
|
||||
|
||||
inline ImmBranchType BranchType() const {
|
||||
ImmBranchType BranchType() const {
|
||||
if (IsCondBranchImm()) {
|
||||
return CondBranchType;
|
||||
} else if (IsUncondBranchImm()) {
|
||||
@@ -296,55 +315,66 @@ class Instruction {
|
||||
// Patch a literal load instruction to load from 'source'.
|
||||
void SetImmLLiteral(const Instruction* source);
|
||||
|
||||
inline uint8_t* LiteralAddress() const {
|
||||
int offset = ImmLLiteral() << kLiteralEntrySizeLog2;
|
||||
const uint8_t* address = reinterpret_cast<const uint8_t*>(this) + offset;
|
||||
// Note that the result is safely mutable only if the backing buffer is
|
||||
// safely mutable.
|
||||
return const_cast<uint8_t*>(address);
|
||||
// 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<uintptr_t>(this);
|
||||
ptrdiff_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;
|
||||
}
|
||||
|
||||
inline uint32_t Literal32() const {
|
||||
uint32_t Literal32() const {
|
||||
uint32_t literal;
|
||||
memcpy(&literal, LiteralAddress(), sizeof(literal));
|
||||
|
||||
memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal));
|
||||
return literal;
|
||||
}
|
||||
|
||||
inline uint64_t Literal64() const {
|
||||
uint64_t Literal64() const {
|
||||
uint64_t literal;
|
||||
memcpy(&literal, LiteralAddress(), sizeof(literal));
|
||||
|
||||
memcpy(&literal, LiteralAddress<const void*>(), sizeof(literal));
|
||||
return literal;
|
||||
}
|
||||
|
||||
inline float LiteralFP32() const {
|
||||
float LiteralFP32() const {
|
||||
return rawbits_to_float(Literal32());
|
||||
}
|
||||
|
||||
inline double LiteralFP64() const {
|
||||
double LiteralFP64() const {
|
||||
return rawbits_to_double(Literal64());
|
||||
}
|
||||
|
||||
inline const Instruction* NextInstruction() const {
|
||||
const Instruction* NextInstruction() const {
|
||||
return this + kInstructionSize;
|
||||
}
|
||||
|
||||
inline const Instruction* InstructionAtOffset(int64_t offset) const {
|
||||
const Instruction* InstructionAtOffset(int64_t offset) const {
|
||||
VIXL_ASSERT(IsWordAligned(this + offset));
|
||||
return this + offset;
|
||||
}
|
||||
|
||||
template<typename T> static inline Instruction* Cast(T src) {
|
||||
template<typename T> static Instruction* Cast(T src) {
|
||||
return reinterpret_cast<Instruction*>(src);
|
||||
}
|
||||
|
||||
template<typename T> static inline const Instruction* CastConst(T src) {
|
||||
template<typename T> static const Instruction* CastConst(T src) {
|
||||
return reinterpret_cast<const Instruction*>(src);
|
||||
}
|
||||
|
||||
private:
|
||||
inline int ImmBranch() const;
|
||||
int ImmBranch() const;
|
||||
|
||||
void SetPCRelImmTarget(const Instruction* target);
|
||||
void SetBranchImmTarget(const Instruction* target);
|
||||
|
||||
@@ -58,7 +58,7 @@ const int KBytes = 1024;
|
||||
const int MBytes = 1024 * KBytes;
|
||||
|
||||
#define VIXL_ABORT() printf("in %s, line %i", __FILE__, __LINE__); abort()
|
||||
#ifdef DEBUG
|
||||
#ifdef VIXL_DEBUG
|
||||
#define VIXL_ASSERT(condition) assert(condition)
|
||||
#define VIXL_CHECK(condition) VIXL_ASSERT(condition)
|
||||
#define VIXL_UNIMPLEMENTED() printf("UNIMPLEMENTED\t"); VIXL_ABORT()
|
||||
|
||||
@@ -135,4 +135,17 @@ bool IsPowerOf2(int64_t value) {
|
||||
return (value != 0) && ((value & (value - 1)) == 0);
|
||||
}
|
||||
|
||||
|
||||
unsigned CountClearHalfWords(uint64_t imm, unsigned reg_size) {
|
||||
VIXL_ASSERT((reg_size % 8) == 0);
|
||||
int count = 0;
|
||||
for (unsigned i = 0; i < (reg_size / 16); i++) {
|
||||
if ((imm & 0xffff) == 0) {
|
||||
count++;
|
||||
}
|
||||
imm >>= 16;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
} // namespace vixl
|
||||
|
||||
@@ -166,6 +166,8 @@ int CountSetBits(uint64_t value, int width);
|
||||
uint64_t LowestSetBit(uint64_t value);
|
||||
bool IsPowerOf2(int64_t value);
|
||||
|
||||
unsigned CountClearHalfWords(uint64_t imm, unsigned reg_size);
|
||||
|
||||
// Pointer alignment
|
||||
// TODO: rename/refactor to make it specific to instructions.
|
||||
template<typename T>
|
||||
@@ -174,14 +176,14 @@ bool IsWordAligned(T pointer) {
|
||||
return ((intptr_t)(pointer) & 3) == 0;
|
||||
}
|
||||
|
||||
// Increment a pointer until it has the specified alignment.
|
||||
// Increment a pointer (up to 64 bits) until it has the specified alignment.
|
||||
template<class T>
|
||||
T AlignUp(T pointer, size_t alignment) {
|
||||
// Use C-style casts to get static_cast behaviour for integral types (T), and
|
||||
// reinterpret_cast behaviour for other types.
|
||||
|
||||
uintptr_t pointer_raw = (uintptr_t)pointer;
|
||||
VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(pointer_raw));
|
||||
uint64_t pointer_raw = (uint64_t)pointer;
|
||||
VIXL_STATIC_ASSERT(sizeof(pointer) <= sizeof(pointer_raw));
|
||||
|
||||
size_t align_step = (alignment - pointer_raw) % alignment;
|
||||
VIXL_ASSERT((pointer_raw + align_step) % alignment == 0);
|
||||
@@ -189,14 +191,14 @@ T AlignUp(T pointer, size_t alignment) {
|
||||
return (T)(pointer_raw + align_step);
|
||||
}
|
||||
|
||||
// Decrement a pointer until it has the specified alignment.
|
||||
// Decrement a pointer (up to 64 bits) until it has the specified alignment.
|
||||
template<class T>
|
||||
T AlignDown(T pointer, size_t alignment) {
|
||||
// Use C-style casts to get static_cast behaviour for integral types (T), and
|
||||
// reinterpret_cast behaviour for other types.
|
||||
|
||||
uintptr_t pointer_raw = (uintptr_t)pointer;
|
||||
VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(pointer_raw));
|
||||
uint64_t pointer_raw = (uint64_t)pointer;
|
||||
VIXL_STATIC_ASSERT(sizeof(pointer) <= sizeof(pointer_raw));
|
||||
|
||||
size_t align_step = pointer_raw % alignment;
|
||||
VIXL_ASSERT((pointer_raw - align_step) % alignment == 0);
|
||||
|
||||
Reference in New Issue
Block a user