mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 19:49:43 +00: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:
parent
87c3d48615
commit
d4eba98df4
@ -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
|
||||
|
@ -151,21 +151,21 @@ class CPURegister {
|
||||
return Aliases(other) && (size_ == other.size_);
|
||||
}
|
||||
|
||||
inline bool IsZero() const {
|
||||
bool IsZero() const {
|
||||
VIXL_ASSERT(IsValid());
|
||||
return IsRegister() && (code_ == kZeroRegCode);
|
||||
}
|
||||
|
||||
inline bool IsSP() const {
|
||||
bool IsSP() const {
|
||||
VIXL_ASSERT(IsValid());
|
||||
return IsRegister() && (code_ == kSPRegInternalCode);
|
||||
}
|
||||
|
||||
inline bool IsRegister() const {
|
||||
bool IsRegister() const {
|
||||
return type_ == kRegister;
|
||||
}
|
||||
|
||||
inline bool IsFPRegister() const {
|
||||
bool IsFPRegister() const {
|
||||
return type_ == kFPRegister;
|
||||
}
|
||||
|
||||
@ -179,7 +179,7 @@ class CPURegister {
|
||||
const FPRegister& S() const;
|
||||
const FPRegister& D() const;
|
||||
|
||||
inline bool IsSameSizeAndType(const CPURegister& other) const {
|
||||
bool IsSameSizeAndType(const CPURegister& other) const {
|
||||
return (size_ == other.size_) && (type_ == other.type_);
|
||||
}
|
||||
|
||||
@ -198,7 +198,7 @@ class CPURegister {
|
||||
class Register : public CPURegister {
|
||||
public:
|
||||
Register() : CPURegister() {}
|
||||
inline explicit Register(const CPURegister& other)
|
||||
explicit Register(const CPURegister& other)
|
||||
: CPURegister(other.code(), other.size(), other.type()) {
|
||||
VIXL_ASSERT(IsValidRegister());
|
||||
}
|
||||
@ -213,10 +213,6 @@ class Register : public CPURegister {
|
||||
static const Register& WRegFromCode(unsigned code);
|
||||
static const Register& XRegFromCode(unsigned code);
|
||||
|
||||
// V8 compatibility.
|
||||
static const int kNumRegisters = kNumberOfRegisters;
|
||||
static const int kNumAllocatableRegisters = kNumberOfRegisters - 1;
|
||||
|
||||
private:
|
||||
static const Register wregisters[];
|
||||
static const Register xregisters[];
|
||||
@ -225,12 +221,12 @@ class Register : public CPURegister {
|
||||
|
||||
class FPRegister : public CPURegister {
|
||||
public:
|
||||
inline FPRegister() : CPURegister() {}
|
||||
inline explicit FPRegister(const CPURegister& other)
|
||||
FPRegister() : CPURegister() {}
|
||||
explicit FPRegister(const CPURegister& other)
|
||||
: CPURegister(other.code(), other.size(), other.type()) {
|
||||
VIXL_ASSERT(IsValidFPRegister());
|
||||
}
|
||||
inline FPRegister(unsigned code, unsigned size)
|
||||
FPRegister(unsigned code, unsigned size)
|
||||
: CPURegister(code, size, kFPRegister) {}
|
||||
|
||||
bool IsValid() const {
|
||||
@ -241,10 +237,6 @@ class FPRegister : public CPURegister {
|
||||
static const FPRegister& SRegFromCode(unsigned code);
|
||||
static const FPRegister& DRegFromCode(unsigned code);
|
||||
|
||||
// V8 compatibility.
|
||||
static const int kNumRegisters = kNumberOfFPRegisters;
|
||||
static const int kNumAllocatableRegisters = kNumberOfFPRegisters - 1;
|
||||
|
||||
private:
|
||||
static const FPRegister sregisters[];
|
||||
static const FPRegister dregisters[];
|
||||
@ -312,23 +304,23 @@ bool AreSameSizeAndType(const CPURegister& reg1,
|
||||
// Lists of registers.
|
||||
class CPURegList {
|
||||
public:
|
||||
inline explicit CPURegList(CPURegister reg1,
|
||||
CPURegister reg2 = NoCPUReg,
|
||||
CPURegister reg3 = NoCPUReg,
|
||||
CPURegister reg4 = NoCPUReg)
|
||||
explicit CPURegList(CPURegister reg1,
|
||||
CPURegister reg2 = NoCPUReg,
|
||||
CPURegister reg3 = NoCPUReg,
|
||||
CPURegister reg4 = NoCPUReg)
|
||||
: list_(reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit()),
|
||||
size_(reg1.size()), type_(reg1.type()) {
|
||||
VIXL_ASSERT(AreSameSizeAndType(reg1, reg2, reg3, reg4));
|
||||
VIXL_ASSERT(IsValid());
|
||||
}
|
||||
|
||||
inline CPURegList(CPURegister::RegisterType type, unsigned size, RegList list)
|
||||
CPURegList(CPURegister::RegisterType type, unsigned size, RegList list)
|
||||
: list_(list), size_(size), type_(type) {
|
||||
VIXL_ASSERT(IsValid());
|
||||
}
|
||||
|
||||
inline CPURegList(CPURegister::RegisterType type, unsigned size,
|
||||
unsigned first_reg, unsigned last_reg)
|
||||
CPURegList(CPURegister::RegisterType type, unsigned size,
|
||||
unsigned first_reg, unsigned last_reg)
|
||||
: size_(size), type_(type) {
|
||||
VIXL_ASSERT(((type == CPURegister::kRegister) &&
|
||||
(last_reg < kNumberOfRegisters)) ||
|
||||
@ -340,7 +332,7 @@ class CPURegList {
|
||||
VIXL_ASSERT(IsValid());
|
||||
}
|
||||
|
||||
inline CPURegister::RegisterType type() const {
|
||||
CPURegister::RegisterType type() const {
|
||||
VIXL_ASSERT(IsValid());
|
||||
return type_;
|
||||
}
|
||||
@ -366,13 +358,13 @@ class CPURegList {
|
||||
}
|
||||
|
||||
// Variants of Combine and Remove which take a single register.
|
||||
inline void Combine(const CPURegister& other) {
|
||||
void Combine(const CPURegister& other) {
|
||||
VIXL_ASSERT(other.type() == type_);
|
||||
VIXL_ASSERT(other.size() == size_);
|
||||
Combine(other.code());
|
||||
}
|
||||
|
||||
inline void Remove(const CPURegister& other) {
|
||||
void Remove(const CPURegister& other) {
|
||||
VIXL_ASSERT(other.type() == type_);
|
||||
VIXL_ASSERT(other.size() == size_);
|
||||
Remove(other.code());
|
||||
@ -380,24 +372,51 @@ class CPURegList {
|
||||
|
||||
// Variants of Combine and Remove which take a single register by its code;
|
||||
// the type and size of the register is inferred from this list.
|
||||
inline void Combine(int code) {
|
||||
void Combine(int code) {
|
||||
VIXL_ASSERT(IsValid());
|
||||
VIXL_ASSERT(CPURegister(code, size_, type_).IsValid());
|
||||
list_ |= (UINT64_C(1) << code);
|
||||
}
|
||||
|
||||
inline void Remove(int code) {
|
||||
void Remove(int code) {
|
||||
VIXL_ASSERT(IsValid());
|
||||
VIXL_ASSERT(CPURegister(code, size_, type_).IsValid());
|
||||
list_ &= ~(UINT64_C(1) << code);
|
||||
}
|
||||
|
||||
inline RegList list() const {
|
||||
static CPURegList Union(const CPURegList& list_1, const CPURegList& list_2) {
|
||||
VIXL_ASSERT(list_1.type_ == list_2.type_);
|
||||
VIXL_ASSERT(list_1.size_ == list_2.size_);
|
||||
return CPURegList(list_1.type_, list_1.size_, list_1.list_ | list_2.list_);
|
||||
}
|
||||
static CPURegList Union(const CPURegList& list_1,
|
||||
const CPURegList& list_2,
|
||||
const CPURegList& list_3);
|
||||
static CPURegList Union(const CPURegList& list_1,
|
||||
const CPURegList& list_2,
|
||||
const CPURegList& list_3,
|
||||
const CPURegList& list_4);
|
||||
|
||||
static CPURegList Intersection(const CPURegList& list_1,
|
||||
const CPURegList& list_2) {
|
||||
VIXL_ASSERT(list_1.type_ == list_2.type_);
|
||||
VIXL_ASSERT(list_1.size_ == list_2.size_);
|
||||
return CPURegList(list_1.type_, list_1.size_, list_1.list_ & list_2.list_);
|
||||
}
|
||||
static CPURegList Intersection(const CPURegList& list_1,
|
||||
const CPURegList& list_2,
|
||||
const CPURegList& list_3);
|
||||
static CPURegList Intersection(const CPURegList& list_1,
|
||||
const CPURegList& list_2,
|
||||
const CPURegList& list_3,
|
||||
const CPURegList& list_4);
|
||||
|
||||
RegList list() const {
|
||||
VIXL_ASSERT(IsValid());
|
||||
return list_;
|
||||
}
|
||||
|
||||
inline void set_list(RegList new_list) {
|
||||
void set_list(RegList new_list) {
|
||||
VIXL_ASSERT(IsValid());
|
||||
list_ = new_list;
|
||||
}
|
||||
@ -417,38 +436,38 @@ class CPURegList {
|
||||
static CPURegList GetCallerSaved(unsigned size = kXRegSize);
|
||||
static CPURegList GetCallerSavedFP(unsigned size = kDRegSize);
|
||||
|
||||
inline bool IsEmpty() const {
|
||||
bool IsEmpty() const {
|
||||
VIXL_ASSERT(IsValid());
|
||||
return list_ == 0;
|
||||
}
|
||||
|
||||
inline bool IncludesAliasOf(const CPURegister& other) const {
|
||||
bool IncludesAliasOf(const CPURegister& other) const {
|
||||
VIXL_ASSERT(IsValid());
|
||||
return (type_ == other.type()) && ((other.Bit() & list_) != 0);
|
||||
}
|
||||
|
||||
inline bool IncludesAliasOf(int code) const {
|
||||
bool IncludesAliasOf(int code) const {
|
||||
VIXL_ASSERT(IsValid());
|
||||
return ((code & list_) != 0);
|
||||
}
|
||||
|
||||
inline int Count() const {
|
||||
int Count() const {
|
||||
VIXL_ASSERT(IsValid());
|
||||
return CountSetBits(list_, kRegListSizeInBits);
|
||||
}
|
||||
|
||||
inline unsigned RegisterSizeInBits() const {
|
||||
unsigned RegisterSizeInBits() const {
|
||||
VIXL_ASSERT(IsValid());
|
||||
return size_;
|
||||
}
|
||||
|
||||
inline unsigned RegisterSizeInBytes() const {
|
||||
unsigned RegisterSizeInBytes() const {
|
||||
int size_in_bits = RegisterSizeInBits();
|
||||
VIXL_ASSERT((size_in_bits % 8) == 0);
|
||||
return size_in_bits / 8;
|
||||
}
|
||||
|
||||
inline unsigned TotalSizeInBytes() const {
|
||||
unsigned TotalSizeInBytes() const {
|
||||
VIXL_ASSERT(IsValid());
|
||||
return RegisterSizeInBytes() * Count();
|
||||
}
|
||||
@ -587,8 +606,10 @@ class Label {
|
||||
VIXL_ASSERT(!IsLinked() || IsBound());
|
||||
}
|
||||
|
||||
inline bool IsBound() const { return location_ >= 0; }
|
||||
inline bool IsLinked() const { return !links_.empty(); }
|
||||
bool IsBound() const { return location_ >= 0; }
|
||||
bool IsLinked() const { return !links_.empty(); }
|
||||
|
||||
ptrdiff_t location() const { return location_; }
|
||||
|
||||
private:
|
||||
// The list of linked instructions is stored in a stack-like structure. We
|
||||
@ -647,22 +668,20 @@ class Label {
|
||||
std::stack<ptrdiff_t> * links_extended_;
|
||||
};
|
||||
|
||||
inline ptrdiff_t location() const { return location_; }
|
||||
|
||||
inline void Bind(ptrdiff_t location) {
|
||||
void Bind(ptrdiff_t location) {
|
||||
// Labels can only be bound once.
|
||||
VIXL_ASSERT(!IsBound());
|
||||
location_ = location;
|
||||
}
|
||||
|
||||
inline void AddLink(ptrdiff_t instruction) {
|
||||
void AddLink(ptrdiff_t instruction) {
|
||||
// If a label is bound, the assembler already has the information it needs
|
||||
// to write the instruction, so there is no need to add it to links_.
|
||||
VIXL_ASSERT(!IsBound());
|
||||
links_.push(instruction);
|
||||
}
|
||||
|
||||
inline ptrdiff_t GetAndRemoveNextLink() {
|
||||
ptrdiff_t GetAndRemoveNextLink() {
|
||||
VIXL_ASSERT(IsLinked());
|
||||
ptrdiff_t link = links_.top();
|
||||
links_.pop();
|
||||
@ -845,14 +864,14 @@ class Assembler {
|
||||
|
||||
// Return the address of an offset in the buffer.
|
||||
template <typename T>
|
||||
inline T GetOffsetAddress(ptrdiff_t offset) {
|
||||
T GetOffsetAddress(ptrdiff_t offset) {
|
||||
VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
|
||||
return buffer_->GetOffsetAddress<T>(offset);
|
||||
}
|
||||
|
||||
// Return the address of a bound label.
|
||||
template <typename T>
|
||||
inline T GetLabelAddress(const Label * label) {
|
||||
T GetLabelAddress(const Label * label) {
|
||||
VIXL_ASSERT(label->IsBound());
|
||||
VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
|
||||
return GetOffsetAddress<T>(label->location());
|
||||
@ -860,14 +879,14 @@ class Assembler {
|
||||
|
||||
// Return the address of the cursor.
|
||||
template <typename T>
|
||||
inline T GetCursorAddress() {
|
||||
T GetCursorAddress() {
|
||||
VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
|
||||
return GetOffsetAddress<T>(CursorOffset());
|
||||
}
|
||||
|
||||
// Return the address of the start of the buffer.
|
||||
template <typename T>
|
||||
inline T GetStartAddress() {
|
||||
T GetStartAddress() {
|
||||
VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
|
||||
return GetOffsetAddress<T>(0);
|
||||
}
|
||||
@ -1074,20 +1093,20 @@ class Assembler {
|
||||
|
||||
// Bfm aliases.
|
||||
// Bitfield insert.
|
||||
inline void bfi(const Register& rd,
|
||||
const Register& rn,
|
||||
unsigned lsb,
|
||||
unsigned width) {
|
||||
void bfi(const Register& rd,
|
||||
const Register& rn,
|
||||
unsigned lsb,
|
||||
unsigned width) {
|
||||
VIXL_ASSERT(width >= 1);
|
||||
VIXL_ASSERT(lsb + width <= rn.size());
|
||||
bfm(rd, rn, (rd.size() - lsb) & (rd.size() - 1), width - 1);
|
||||
}
|
||||
|
||||
// Bitfield extract and insert low.
|
||||
inline void bfxil(const Register& rd,
|
||||
const Register& rn,
|
||||
unsigned lsb,
|
||||
unsigned width) {
|
||||
void bfxil(const Register& rd,
|
||||
const Register& rn,
|
||||
unsigned lsb,
|
||||
unsigned width) {
|
||||
VIXL_ASSERT(width >= 1);
|
||||
VIXL_ASSERT(lsb + width <= rn.size());
|
||||
bfm(rd, rn, lsb, lsb + width - 1);
|
||||
@ -1095,92 +1114,92 @@ class Assembler {
|
||||
|
||||
// Sbfm aliases.
|
||||
// Arithmetic shift right.
|
||||
inline void asr(const Register& rd, const Register& rn, unsigned shift) {
|
||||
void asr(const Register& rd, const Register& rn, unsigned shift) {
|
||||
VIXL_ASSERT(shift < rd.size());
|
||||
sbfm(rd, rn, shift, rd.size() - 1);
|
||||
}
|
||||
|
||||
// Signed bitfield insert with zero at right.
|
||||
inline void sbfiz(const Register& rd,
|
||||
const Register& rn,
|
||||
unsigned lsb,
|
||||
unsigned width) {
|
||||
void sbfiz(const Register& rd,
|
||||
const Register& rn,
|
||||
unsigned lsb,
|
||||
unsigned width) {
|
||||
VIXL_ASSERT(width >= 1);
|
||||
VIXL_ASSERT(lsb + width <= rn.size());
|
||||
sbfm(rd, rn, (rd.size() - lsb) & (rd.size() - 1), width - 1);
|
||||
}
|
||||
|
||||
// Signed bitfield extract.
|
||||
inline void sbfx(const Register& rd,
|
||||
const Register& rn,
|
||||
unsigned lsb,
|
||||
unsigned width) {
|
||||
void sbfx(const Register& rd,
|
||||
const Register& rn,
|
||||
unsigned lsb,
|
||||
unsigned width) {
|
||||
VIXL_ASSERT(width >= 1);
|
||||
VIXL_ASSERT(lsb + width <= rn.size());
|
||||
sbfm(rd, rn, lsb, lsb + width - 1);
|
||||
}
|
||||
|
||||
// Signed extend byte.
|
||||
inline void sxtb(const Register& rd, const Register& rn) {
|
||||
void sxtb(const Register& rd, const Register& rn) {
|
||||
sbfm(rd, rn, 0, 7);
|
||||
}
|
||||
|
||||
// Signed extend halfword.
|
||||
inline void sxth(const Register& rd, const Register& rn) {
|
||||
void sxth(const Register& rd, const Register& rn) {
|
||||
sbfm(rd, rn, 0, 15);
|
||||
}
|
||||
|
||||
// Signed extend word.
|
||||
inline void sxtw(const Register& rd, const Register& rn) {
|
||||
void sxtw(const Register& rd, const Register& rn) {
|
||||
sbfm(rd, rn, 0, 31);
|
||||
}
|
||||
|
||||
// Ubfm aliases.
|
||||
// Logical shift left.
|
||||
inline void lsl(const Register& rd, const Register& rn, unsigned shift) {
|
||||
void lsl(const Register& rd, const Register& rn, unsigned shift) {
|
||||
unsigned reg_size = rd.size();
|
||||
VIXL_ASSERT(shift < reg_size);
|
||||
ubfm(rd, rn, (reg_size - shift) % reg_size, reg_size - shift - 1);
|
||||
}
|
||||
|
||||
// Logical shift right.
|
||||
inline void lsr(const Register& rd, const Register& rn, unsigned shift) {
|
||||
void lsr(const Register& rd, const Register& rn, unsigned shift) {
|
||||
VIXL_ASSERT(shift < rd.size());
|
||||
ubfm(rd, rn, shift, rd.size() - 1);
|
||||
}
|
||||
|
||||
// Unsigned bitfield insert with zero at right.
|
||||
inline void ubfiz(const Register& rd,
|
||||
const Register& rn,
|
||||
unsigned lsb,
|
||||
unsigned width) {
|
||||
void ubfiz(const Register& rd,
|
||||
const Register& rn,
|
||||
unsigned lsb,
|
||||
unsigned width) {
|
||||
VIXL_ASSERT(width >= 1);
|
||||
VIXL_ASSERT(lsb + width <= rn.size());
|
||||
ubfm(rd, rn, (rd.size() - lsb) & (rd.size() - 1), width - 1);
|
||||
}
|
||||
|
||||
// Unsigned bitfield extract.
|
||||
inline void ubfx(const Register& rd,
|
||||
const Register& rn,
|
||||
unsigned lsb,
|
||||
unsigned width) {
|
||||
void ubfx(const Register& rd,
|
||||
const Register& rn,
|
||||
unsigned lsb,
|
||||
unsigned width) {
|
||||
VIXL_ASSERT(width >= 1);
|
||||
VIXL_ASSERT(lsb + width <= rn.size());
|
||||
ubfm(rd, rn, lsb, lsb + width - 1);
|
||||
}
|
||||
|
||||
// Unsigned extend byte.
|
||||
inline void uxtb(const Register& rd, const Register& rn) {
|
||||
void uxtb(const Register& rd, const Register& rn) {
|
||||
ubfm(rd, rn, 0, 7);
|
||||
}
|
||||
|
||||
// Unsigned extend halfword.
|
||||
inline void uxth(const Register& rd, const Register& rn) {
|
||||
void uxth(const Register& rd, const Register& rn) {
|
||||
ubfm(rd, rn, 0, 15);
|
||||
}
|
||||
|
||||
// Unsigned extend word.
|
||||
inline void uxtw(const Register& rd, const Register& rn) {
|
||||
void uxtw(const Register& rd, const Register& rn) {
|
||||
ubfm(rd, rn, 0, 31);
|
||||
}
|
||||
|
||||
@ -1230,7 +1249,7 @@ class Assembler {
|
||||
void cneg(const Register& rd, const Register& rn, Condition cond);
|
||||
|
||||
// Rotate right.
|
||||
inline void ror(const Register& rd, const Register& rs, unsigned shift) {
|
||||
void ror(const Register& rd, const Register& rs, unsigned shift) {
|
||||
extr(rd, rs, rs, shift);
|
||||
}
|
||||
|
||||
@ -1495,6 +1514,19 @@ class Assembler {
|
||||
// Load-acquire register.
|
||||
void ldar(const Register& rt, const MemOperand& src);
|
||||
|
||||
// Prefetch memory.
|
||||
void prfm(PrefetchOperation op, const MemOperand& addr,
|
||||
LoadStoreScalingOption option = PreferScaledOffset);
|
||||
|
||||
// Prefetch memory (with unscaled offset).
|
||||
void prfum(PrefetchOperation op, const MemOperand& addr,
|
||||
LoadStoreScalingOption option = PreferUnscaledOffset);
|
||||
|
||||
// Prefetch memory in the literal pool.
|
||||
void prfm(PrefetchOperation op, RawLiteral* literal);
|
||||
|
||||
// Prefetch from pc + imm19 << 2.
|
||||
void prfm(PrefetchOperation op, int imm19);
|
||||
|
||||
// Move instructions. The default shift of -1 indicates that the move
|
||||
// instruction will calculate an appropriate 16-bit immediate and left shift
|
||||
@ -1638,12 +1670,21 @@ class Assembler {
|
||||
// FP round to integer (nearest with ties to away).
|
||||
void frinta(const FPRegister& fd, const FPRegister& fn);
|
||||
|
||||
// FP round to integer (implicit rounding).
|
||||
void frinti(const FPRegister& fd, const FPRegister& fn);
|
||||
|
||||
// FP round to integer (toward minus infinity).
|
||||
void frintm(const FPRegister& fd, const FPRegister& fn);
|
||||
|
||||
// FP round to integer (nearest with ties to even).
|
||||
void frintn(const FPRegister& fd, const FPRegister& fn);
|
||||
|
||||
// FP round to integer (toward plus infinity).
|
||||
void frintp(const FPRegister& fd, const FPRegister& fn);
|
||||
|
||||
// FP round to integer (exact, implicit rounding).
|
||||
void frintx(const FPRegister& fd, const FPRegister& fn);
|
||||
|
||||
// FP round to integer (towards zero).
|
||||
void frintz(const FPRegister& fd, const FPRegister& fn);
|
||||
|
||||
@ -1705,16 +1746,16 @@ class Assembler {
|
||||
|
||||
// Emit generic instructions.
|
||||
// Emit raw instructions into the instruction stream.
|
||||
inline void dci(Instr raw_inst) { Emit(raw_inst); }
|
||||
void dci(Instr raw_inst) { Emit(raw_inst); }
|
||||
|
||||
// Emit 32 bits of data into the instruction stream.
|
||||
inline void dc32(uint32_t data) {
|
||||
void dc32(uint32_t data) {
|
||||
VIXL_ASSERT(buffer_monitor_ > 0);
|
||||
buffer_->Emit32(data);
|
||||
}
|
||||
|
||||
// Emit 64 bits of data into the instruction stream.
|
||||
inline void dc64(uint64_t data) {
|
||||
void dc64(uint64_t data) {
|
||||
VIXL_ASSERT(buffer_monitor_ > 0);
|
||||
buffer_->Emit64(data);
|
||||
}
|
||||
@ -1849,14 +1890,14 @@ class Assembler {
|
||||
}
|
||||
}
|
||||
|
||||
static inline Instr ImmS(unsigned imms, unsigned reg_size) {
|
||||
static Instr ImmS(unsigned imms, unsigned reg_size) {
|
||||
VIXL_ASSERT(((reg_size == kXRegSize) && is_uint6(imms)) ||
|
||||
((reg_size == kWRegSize) && is_uint5(imms)));
|
||||
USE(reg_size);
|
||||
return imms << ImmS_offset;
|
||||
}
|
||||
|
||||
static inline Instr ImmR(unsigned immr, unsigned reg_size) {
|
||||
static Instr ImmR(unsigned immr, unsigned reg_size) {
|
||||
VIXL_ASSERT(((reg_size == kXRegSize) && is_uint6(immr)) ||
|
||||
((reg_size == kWRegSize) && is_uint5(immr)));
|
||||
USE(reg_size);
|
||||
@ -1864,7 +1905,7 @@ class Assembler {
|
||||
return immr << ImmR_offset;
|
||||
}
|
||||
|
||||
static inline Instr ImmSetBits(unsigned imms, unsigned reg_size) {
|
||||
static Instr ImmSetBits(unsigned imms, unsigned reg_size) {
|
||||
VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize));
|
||||
VIXL_ASSERT(is_uint6(imms));
|
||||
VIXL_ASSERT((reg_size == kXRegSize) || is_uint6(imms + 3));
|
||||
@ -1872,7 +1913,7 @@ class Assembler {
|
||||
return imms << ImmSetBits_offset;
|
||||
}
|
||||
|
||||
static inline Instr ImmRotate(unsigned immr, unsigned reg_size) {
|
||||
static Instr ImmRotate(unsigned immr, unsigned reg_size) {
|
||||
VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize));
|
||||
VIXL_ASSERT(((reg_size == kXRegSize) && is_uint6(immr)) ||
|
||||
((reg_size == kWRegSize) && is_uint5(immr)));
|
||||
@ -1880,12 +1921,12 @@ class Assembler {
|
||||
return immr << ImmRotate_offset;
|
||||
}
|
||||
|
||||
static inline Instr ImmLLiteral(int imm19) {
|
||||
static Instr ImmLLiteral(int imm19) {
|
||||
VIXL_ASSERT(is_int19(imm19));
|
||||
return truncate_to_int19(imm19) << ImmLLiteral_offset;
|
||||
}
|
||||
|
||||
static inline Instr BitN(unsigned bitn, unsigned reg_size) {
|
||||
static Instr BitN(unsigned bitn, unsigned reg_size) {
|
||||
VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize));
|
||||
VIXL_ASSERT((reg_size == kXRegSize) || (bitn == 0));
|
||||
USE(reg_size);
|
||||
@ -1943,6 +1984,11 @@ class Assembler {
|
||||
return shift_amount << ImmShiftLS_offset;
|
||||
}
|
||||
|
||||
static Instr ImmPrefetchOperation(int imm5) {
|
||||
VIXL_ASSERT(is_uint5(imm5));
|
||||
return imm5 << ImmPrefetchOperation_offset;
|
||||
}
|
||||
|
||||
static Instr ImmException(int imm16) {
|
||||
VIXL_ASSERT(is_uint16(imm16));
|
||||
return imm16 << ImmException_offset;
|
||||
@ -2003,12 +2049,32 @@ class Assembler {
|
||||
return scale << FPScale_offset;
|
||||
}
|
||||
|
||||
// Immediate field checking helpers.
|
||||
static bool IsImmAddSub(int64_t immediate);
|
||||
static bool IsImmConditionalCompare(int64_t immediate);
|
||||
static bool IsImmFP32(float imm);
|
||||
static bool IsImmFP64(double imm);
|
||||
static bool IsImmLogical(uint64_t value,
|
||||
unsigned width,
|
||||
unsigned* n = NULL,
|
||||
unsigned* imm_s = NULL,
|
||||
unsigned* imm_r = NULL);
|
||||
static bool IsImmLSPair(int64_t offset, LSDataSize size);
|
||||
static bool IsImmLSScaled(int64_t offset, LSDataSize size);
|
||||
static bool IsImmLSUnscaled(int64_t offset);
|
||||
static bool IsImmMovn(uint64_t imm, unsigned reg_size);
|
||||
static bool IsImmMovz(uint64_t imm, unsigned reg_size);
|
||||
|
||||
// Size of the code generated since label to the current position.
|
||||
size_t SizeOfCodeGeneratedSince(Label* label) const {
|
||||
VIXL_ASSERT(label->IsBound());
|
||||
return buffer_->OffsetFrom(label->location());
|
||||
}
|
||||
|
||||
size_t SizeOfCodeGenerated() const {
|
||||
return buffer_->CursorOffset();
|
||||
}
|
||||
|
||||
size_t BufferCapacity() const { return buffer_->capacity(); }
|
||||
|
||||
size_t RemainingBufferSpace() const { return buffer_->RemainingBytes(); }
|
||||
@ -2025,7 +2091,7 @@ class Assembler {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef VIXL_DEBUG
|
||||
void AcquireBuffer() {
|
||||
VIXL_ASSERT(buffer_monitor_ >= 0);
|
||||
buffer_monitor_++;
|
||||
@ -2037,16 +2103,16 @@ class Assembler {
|
||||
}
|
||||
#endif
|
||||
|
||||
inline PositionIndependentCodeOption pic() {
|
||||
PositionIndependentCodeOption pic() const {
|
||||
return pic_;
|
||||
}
|
||||
|
||||
inline bool AllowPageOffsetDependentCode() {
|
||||
bool AllowPageOffsetDependentCode() const {
|
||||
return (pic() == PageOffsetDependentCode) ||
|
||||
(pic() == PositionDependentCode);
|
||||
}
|
||||
|
||||
static inline const Register& AppropriateZeroRegFor(const CPURegister& reg) {
|
||||
static const Register& AppropriateZeroRegFor(const CPURegister& reg) {
|
||||
return reg.Is64Bits() ? xzr : wzr;
|
||||
}
|
||||
|
||||
@ -2056,14 +2122,15 @@ class Assembler {
|
||||
const MemOperand& addr,
|
||||
LoadStoreOp op,
|
||||
LoadStoreScalingOption option = PreferScaledOffset);
|
||||
static bool IsImmLSUnscaled(int64_t offset);
|
||||
static bool IsImmLSScaled(int64_t offset, LSDataSize size);
|
||||
|
||||
void LoadStorePair(const CPURegister& rt,
|
||||
const CPURegister& rt2,
|
||||
const MemOperand& addr,
|
||||
LoadStorePairOp op);
|
||||
static bool IsImmLSPair(int64_t offset, LSDataSize size);
|
||||
|
||||
void Prefetch(PrefetchOperation op,
|
||||
const MemOperand& addr,
|
||||
LoadStoreScalingOption option = PreferScaledOffset);
|
||||
|
||||
// TODO(all): The third parameter should be passed by reference but gcc 4.8.2
|
||||
// reports a bogus uninitialised warning then.
|
||||
@ -2077,18 +2144,12 @@ class Assembler {
|
||||
unsigned imm_s,
|
||||
unsigned imm_r,
|
||||
LogicalOp op);
|
||||
static bool IsImmLogical(uint64_t value,
|
||||
unsigned width,
|
||||
unsigned* n = NULL,
|
||||
unsigned* imm_s = NULL,
|
||||
unsigned* imm_r = NULL);
|
||||
|
||||
void ConditionalCompare(const Register& rn,
|
||||
const Operand& operand,
|
||||
StatusFlags nzcv,
|
||||
Condition cond,
|
||||
ConditionalCompareOp op);
|
||||
static bool IsImmConditionalCompare(int64_t immediate);
|
||||
|
||||
void AddSubWithCarry(const Register& rd,
|
||||
const Register& rn,
|
||||
@ -2096,8 +2157,6 @@ class Assembler {
|
||||
FlagsUpdate S,
|
||||
AddSubWithCarryOp op);
|
||||
|
||||
static bool IsImmFP32(float imm);
|
||||
static bool IsImmFP64(double imm);
|
||||
|
||||
// Functions for emulating operands not directly supported by the instruction
|
||||
// set.
|
||||
@ -2115,7 +2174,6 @@ class Assembler {
|
||||
const Operand& operand,
|
||||
FlagsUpdate S,
|
||||
AddSubOp op);
|
||||
static bool IsImmAddSub(int64_t immediate);
|
||||
|
||||
// Find an appropriate LoadStoreOp or LoadStorePairOp for the specified
|
||||
// registers. Only simple loads are supported; sign- and zero-extension (such
|
||||
@ -2180,6 +2238,12 @@ class Assembler {
|
||||
const FPRegister& fa,
|
||||
FPDataProcessing3SourceOp op);
|
||||
|
||||
// Encode the specified MemOperand for the specified access size and scaling
|
||||
// preference.
|
||||
Instr LoadStoreMemOperand(const MemOperand& addr,
|
||||
LSDataSize size,
|
||||
LoadStoreScalingOption option);
|
||||
|
||||
// Link the current (not-yet-emitted) instruction to the specified label, then
|
||||
// return an offset to be encoded in the instruction. If the label is not yet
|
||||
// bound, an offset of 0 is returned.
|
||||
@ -2205,7 +2269,7 @@ class Assembler {
|
||||
CodeBuffer* buffer_;
|
||||
PositionIndependentCodeOption pic_;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef VIXL_DEBUG
|
||||
int64_t buffer_monitor_;
|
||||
#endif
|
||||
};
|
||||
@ -2239,7 +2303,7 @@ class CodeBufferCheckScope {
|
||||
AssertPolicy assert_policy = kMaximumSize)
|
||||
: assm_(assm) {
|
||||
if (check_policy == kCheck) assm->EnsureSpaceFor(size);
|
||||
#ifdef DEBUG
|
||||
#ifdef VIXL_DEBUG
|
||||
assm->bind(&start_);
|
||||
size_ = size;
|
||||
assert_policy_ = assert_policy;
|
||||
@ -2251,7 +2315,7 @@ class CodeBufferCheckScope {
|
||||
|
||||
// This is a shortcut for CodeBufferCheckScope(assm, 0, kNoCheck, kNoAssert).
|
||||
explicit CodeBufferCheckScope(Assembler* assm) : assm_(assm) {
|
||||
#ifdef DEBUG
|
||||
#ifdef VIXL_DEBUG
|
||||
size_ = 0;
|
||||
assert_policy_ = kNoAssert;
|
||||
assm->AcquireBuffer();
|
||||
@ -2259,7 +2323,7 @@ class CodeBufferCheckScope {
|
||||
}
|
||||
|
||||
~CodeBufferCheckScope() {
|
||||
#ifdef DEBUG
|
||||
#ifdef VIXL_DEBUG
|
||||
assm_->ReleaseBuffer();
|
||||
switch (assert_policy_) {
|
||||
case kNoAssert: break;
|
||||
@ -2277,7 +2341,7 @@ class CodeBufferCheckScope {
|
||||
|
||||
protected:
|
||||
Assembler* assm_;
|
||||
#ifdef DEBUG
|
||||
#ifdef VIXL_DEBUG
|
||||
Label start_;
|
||||
size_t size_;
|
||||
AssertPolicy assert_policy_;
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user