summaryrefslogtreecommitdiff
path: root/disas/libvixl
diff options
context:
space:
mode:
Diffstat (limited to 'disas/libvixl')
-rw-r--r--disas/libvixl/README2
-rw-r--r--disas/libvixl/a64/assembler-a64.h710
-rw-r--r--disas/libvixl/a64/constants-a64.h68
-rw-r--r--disas/libvixl/a64/cpu-a64.h27
-rw-r--r--disas/libvixl/a64/decoder-a64.cc49
-rw-r--r--disas/libvixl/a64/decoder-a64.h103
-rw-r--r--disas/libvixl/a64/disasm-a64.cc333
-rw-r--r--disas/libvixl/a64/disasm-a64.h86
-rw-r--r--disas/libvixl/a64/instructions-a64.cc45
-rw-r--r--disas/libvixl/a64/instructions-a64.h74
-rw-r--r--disas/libvixl/code-buffer.h113
-rw-r--r--disas/libvixl/platform.h8
-rw-r--r--disas/libvixl/utils.cc11
-rw-r--r--disas/libvixl/utils.h35
14 files changed, 1244 insertions, 420 deletions
diff --git a/disas/libvixl/README b/disas/libvixl/README
index a0ecac3dd..cba31b458 100644
--- a/disas/libvixl/README
+++ b/disas/libvixl/README
@@ -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.4).
+taken from libvixl 1.6).
Bugfixes should preferably be sent upstream initially.
The disassembler does not currently support the entire A64 instruction
diff --git a/disas/libvixl/a64/assembler-a64.h b/disas/libvixl/a64/assembler-a64.h
index 1e2947b28..16a704b7d 100644
--- a/disas/libvixl/a64/assembler-a64.h
+++ b/disas/libvixl/a64/assembler-a64.h
@@ -28,9 +28,11 @@
#define VIXL_A64_ASSEMBLER_A64_H_
#include <list>
+#include <stack>
#include "globals.h"
#include "utils.h"
+#include "code-buffer.h"
#include "a64/instructions-a64.h"
namespace vixl {
@@ -167,6 +169,11 @@ class CPURegister {
return type_ == kFPRegister;
}
+ bool IsW() const { return IsValidRegister() && Is32Bits(); }
+ bool IsX() const { return IsValidRegister() && Is64Bits(); }
+ bool IsS() const { return IsValidFPRegister() && Is32Bits(); }
+ bool IsD() const { return IsValidFPRegister() && Is64Bits(); }
+
const Register& W() const;
const Register& X() const;
const FPRegister& S() const;
@@ -190,12 +197,12 @@ class CPURegister {
class Register : public CPURegister {
public:
- explicit Register() : CPURegister() {}
+ Register() : CPURegister() {}
inline explicit Register(const CPURegister& other)
: CPURegister(other.code(), other.size(), other.type()) {
VIXL_ASSERT(IsValidRegister());
}
- explicit Register(unsigned code, unsigned size)
+ Register(unsigned code, unsigned size)
: CPURegister(code, size, kRegister) {}
bool IsValid() const {
@@ -535,7 +542,7 @@ class Operand {
class MemOperand {
public:
explicit MemOperand(Register base,
- ptrdiff_t offset = 0,
+ int64_t offset = 0,
AddrMode addrmode = Offset);
explicit MemOperand(Register base,
Register regoffset,
@@ -551,7 +558,7 @@ class MemOperand {
const Register& base() const { return base_; }
const Register& regoffset() const { return regoffset_; }
- ptrdiff_t offset() const { return offset_; }
+ int64_t offset() const { return offset_; }
AddrMode addrmode() const { return addrmode_; }
Shift shift() const { return shift_; }
Extend extend() const { return extend_; }
@@ -564,7 +571,7 @@ class MemOperand {
private:
Register base_;
Register regoffset_;
- ptrdiff_t offset_;
+ int64_t offset_;
AddrMode addrmode_;
Shift shift_;
Extend extend_;
@@ -574,71 +581,233 @@ class MemOperand {
class Label {
public:
- Label() : is_bound_(false), link_(NULL), target_(NULL) {}
+ Label() : location_(kLocationUnbound) {}
~Label() {
// If the label has been linked to, it needs to be bound to a target.
VIXL_ASSERT(!IsLinked() || IsBound());
}
- inline Instruction* link() const { return link_; }
- inline Instruction* target() const { return target_; }
+ inline bool IsBound() const { return location_ >= 0; }
+ inline bool IsLinked() const { return !links_.empty(); }
- inline bool IsBound() const { return is_bound_; }
- inline bool IsLinked() const { return link_ != NULL; }
+ private:
+ // The list of linked instructions is stored in a stack-like structure. We
+ // don't use std::stack directly because it's slow for the common case where
+ // only one or two instructions refer to a label, and labels themselves are
+ // short-lived. This class behaves like std::stack, but the first few links
+ // are preallocated (configured by kPreallocatedLinks).
+ //
+ // If more than N links are required, this falls back to std::stack.
+ class LinksStack {
+ public:
+ LinksStack() : size_(0), links_extended_(NULL) {}
+ ~LinksStack() {
+ delete links_extended_;
+ }
- inline void set_link(Instruction* new_link) { link_ = new_link; }
+ size_t size() const {
+ return size_;
+ }
- static const int kEndOfChain = 0;
+ bool empty() const {
+ return size_ == 0;
+ }
- private:
- // Indicates if the label has been bound, ie its location is fixed.
- bool is_bound_;
- // Branches instructions branching to this label form a chained list, with
- // their offset indicating where the next instruction is located.
- // link_ points to the latest branch instruction generated branching to this
- // branch.
- // If link_ is not NULL, the label has been linked to.
- Instruction* link_;
+ void push(ptrdiff_t value) {
+ if (size_ < kPreallocatedLinks) {
+ links_[size_] = value;
+ } else {
+ if (links_extended_ == NULL) {
+ links_extended_ = new std::stack<ptrdiff_t>();
+ }
+ VIXL_ASSERT(size_ == (links_extended_->size() + kPreallocatedLinks));
+ links_extended_->push(value);
+ }
+ size_++;
+ }
+
+ ptrdiff_t top() const {
+ return (size_ <= kPreallocatedLinks) ? links_[size_ - 1]
+ : links_extended_->top();
+ }
+
+ void pop() {
+ size_--;
+ if (size_ >= kPreallocatedLinks) {
+ links_extended_->pop();
+ VIXL_ASSERT(size_ == (links_extended_->size() + kPreallocatedLinks));
+ }
+ }
+
+ private:
+ static const size_t kPreallocatedLinks = 4;
+
+ size_t size_;
+ ptrdiff_t links_[kPreallocatedLinks];
+ std::stack<ptrdiff_t> * links_extended_;
+ };
+
+ inline ptrdiff_t location() const { return location_; }
+
+ inline void Bind(ptrdiff_t location) {
+ // Labels can only be bound once.
+ VIXL_ASSERT(!IsBound());
+ location_ = location;
+ }
+
+ inline 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() {
+ VIXL_ASSERT(IsLinked());
+ ptrdiff_t link = links_.top();
+ links_.pop();
+ return link;
+ }
+
+ // The offsets of the instructions that have linked to this label.
+ LinksStack links_;
// The label location.
- Instruction* target_;
+ ptrdiff_t location_;
+
+ static const ptrdiff_t kLocationUnbound = -1;
+
+ // It is not safe to copy labels, so disable the copy constructor by declaring
+ // it private (without an implementation).
+ Label(const Label&);
+ // The Assembler class is responsible for binding and linking labels, since
+ // the stored offsets need to be consistent with the Assembler's buffer.
friend class Assembler;
};
-// TODO: Obtain better values for these, based on real-world data.
-const int kLiteralPoolCheckInterval = 4 * KBytes;
-const int kRecommendedLiteralPoolRange = 2 * kLiteralPoolCheckInterval;
+// A literal is a 32-bit or 64-bit piece of data stored in the instruction
+// stream and loaded through a pc relative load. The same literal can be
+// referred to by multiple instructions but a literal can only reside at one
+// place in memory. A literal can be used by a load before or after being
+// placed in memory.
+//
+// Internally an offset of 0 is associated with a literal which has been
+// neither used nor placed. Then two possibilities arise:
+// 1) the label is placed, the offset (stored as offset + 1) is used to
+// resolve any subsequent load using the label.
+// 2) the label is not placed and offset is the offset of the last load using
+// the literal (stored as -offset -1). If multiple loads refer to this
+// literal then the last load holds the offset of the preceding load and
+// all loads form a chain. Once the offset is placed all the loads in the
+// chain are resolved and future loads fall back to possibility 1.
+class RawLiteral {
+ public:
+ RawLiteral() : size_(0), offset_(0), raw_value_(0) {}
+
+ size_t size() {
+ VIXL_STATIC_ASSERT(kDRegSizeInBytes == kXRegSizeInBytes);
+ VIXL_STATIC_ASSERT(kSRegSizeInBytes == kWRegSizeInBytes);
+ VIXL_ASSERT((size_ == kXRegSizeInBytes) || (size_ == kWRegSizeInBytes));
+ return size_;
+ }
+ uint64_t raw_value64() {
+ VIXL_ASSERT(size_ == kXRegSizeInBytes);
+ return raw_value_;
+ }
+ uint32_t raw_value32() {
+ VIXL_ASSERT(size_ == kWRegSizeInBytes);
+ VIXL_ASSERT(is_uint32(raw_value_) || is_int32(raw_value_));
+ return static_cast<uint32_t>(raw_value_);
+ }
+ bool IsUsed() { return offset_ < 0; }
+ bool IsPlaced() { return offset_ > 0; }
+
+ protected:
+ ptrdiff_t offset() {
+ VIXL_ASSERT(IsPlaced());
+ return offset_ - 1;
+ }
+ void set_offset(ptrdiff_t offset) {
+ VIXL_ASSERT(offset >= 0);
+ VIXL_ASSERT(IsWordAligned(offset));
+ VIXL_ASSERT(!IsPlaced());
+ offset_ = offset + 1;
+ }
+ ptrdiff_t last_use() {
+ VIXL_ASSERT(IsUsed());
+ return -offset_ - 1;
+ }
+ void set_last_use(ptrdiff_t offset) {
+ VIXL_ASSERT(offset >= 0);
+ VIXL_ASSERT(IsWordAligned(offset));
+ VIXL_ASSERT(!IsPlaced());
+ offset_ = -offset - 1;
+ }
+ size_t size_;
+ ptrdiff_t offset_;
+ uint64_t raw_value_;
-// Control whether a branch over the literal pool should also be emitted. This
-// is needed if the literal pool has to be emitted in the middle of the JITted
-// code.
-enum LiteralPoolEmitOption {
- JumpRequired,
- NoJumpRequired
+ friend class Assembler;
};
-// Literal pool entry.
-class Literal {
+template <typename T>
+class Literal : public RawLiteral {
public:
- Literal(Instruction* pc, uint64_t imm, unsigned size)
- : pc_(pc), value_(imm), size_(size) {}
+ explicit Literal(T value) {
+ size_ = sizeof(value);
+ memcpy(&raw_value_, &value, sizeof(value));
+ }
+};
- private:
- Instruction* pc_;
- int64_t value_;
- unsigned size_;
- friend class Assembler;
+// Control whether or not position-independent code should be emitted.
+enum PositionIndependentCodeOption {
+ // All code generated will be position-independent; all branches and
+ // references to labels generated with the Label class will use PC-relative
+ // addressing.
+ PositionIndependentCode,
+
+ // Allow VIXL to generate code that refers to absolute addresses. With this
+ // option, it will not be possible to copy the code buffer and run it from a
+ // different address; code must be generated in its final location.
+ PositionDependentCode,
+
+ // Allow VIXL to assume that the bottom 12 bits of the address will be
+ // constant, but that the top 48 bits may change. This allows `adrp` to
+ // function in systems which copy code between pages, but otherwise maintain
+ // 4KB page alignment.
+ PageOffsetDependentCode
+};
+
+
+// Control how scaled- and unscaled-offset loads and stores are generated.
+enum LoadStoreScalingOption {
+ // Prefer scaled-immediate-offset instructions, but emit unscaled-offset,
+ // register-offset, pre-index or post-index instructions if necessary.
+ PreferScaledOffset,
+
+ // Prefer unscaled-immediate-offset instructions, but emit scaled-offset,
+ // register-offset, pre-index or post-index instructions if necessary.
+ PreferUnscaledOffset,
+
+ // Require scaled-immediate-offset instructions.
+ RequireScaledOffset,
+
+ // Require unscaled-immediate-offset instructions.
+ RequireUnscaledOffset
};
// Assembler.
class Assembler {
public:
- Assembler(byte* buffer, unsigned buffer_size);
+ Assembler(size_t capacity,
+ PositionIndependentCodeOption pic = PositionIndependentCode);
+ Assembler(byte* buffer, size_t capacity,
+ PositionIndependentCodeOption pic = PositionIndependentCode);
// The destructor asserts that one of the following is true:
// * The Assembler object has not been used.
@@ -650,9 +819,6 @@ class Assembler {
// Start generating code from the beginning of the buffer, discarding any code
// and data that has already been emitted into the buffer.
- //
- // In order to avoid any accidental transfer of state, Reset ASSERTs that the
- // constant pool is not blocked.
void Reset();
// Finalize a code buffer of generated instructions. This function must be
@@ -662,12 +828,49 @@ class Assembler {
// Label.
// Bind a label to the current PC.
void bind(Label* label);
- int UpdateAndGetByteOffsetTo(Label* label);
- inline int UpdateAndGetInstructionOffsetTo(Label* label) {
- VIXL_ASSERT(Label::kEndOfChain == 0);
- return UpdateAndGetByteOffsetTo(label) >> kInstructionSizeLog2;
+
+ // Bind a label to a specified offset from the start of the buffer.
+ void BindToOffset(Label* label, ptrdiff_t offset);
+
+ // Place a literal at the current PC.
+ void place(RawLiteral* literal);
+
+ ptrdiff_t CursorOffset() const {
+ return buffer_->CursorOffset();
+ }
+
+ ptrdiff_t BufferEndOffset() const {
+ return static_cast<ptrdiff_t>(buffer_->capacity());
+ }
+
+ // Return the address of an offset in the buffer.
+ template <typename T>
+ inline 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) {
+ VIXL_ASSERT(label->IsBound());
+ VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
+ return GetOffsetAddress<T>(label->location());
+ }
+
+ // Return the address of the cursor.
+ template <typename T>
+ inline 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() {
+ VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
+ return GetOffsetAddress<T>(0);
+ }
// Instruction set functions.
@@ -733,6 +936,12 @@ class Assembler {
// Calculate the address of a PC offset.
void adr(const Register& rd, int imm21);
+ // Calculate the page address of a label.
+ void adrp(const Register& rd, Label* label);
+
+ // Calculate the page address of a PC offset.
+ void adrp(const Register& rd, int imm21);
+
// Data Processing instructions.
// Add.
void add(const Register& rd,
@@ -1112,31 +1321,76 @@ class Assembler {
// Memory instructions.
// Load integer or FP register.
- void ldr(const CPURegister& rt, const MemOperand& src);
+ void ldr(const CPURegister& rt, const MemOperand& src,
+ LoadStoreScalingOption option = PreferScaledOffset);
// Store integer or FP register.
- void str(const CPURegister& rt, const MemOperand& dst);
+ void str(const CPURegister& rt, const MemOperand& dst,
+ LoadStoreScalingOption option = PreferScaledOffset);
// Load word with sign extension.
- void ldrsw(const Register& rt, const MemOperand& src);
+ void ldrsw(const Register& rt, const MemOperand& src,
+ LoadStoreScalingOption option = PreferScaledOffset);
// Load byte.
- void ldrb(const Register& rt, const MemOperand& src);
+ void ldrb(const Register& rt, const MemOperand& src,
+ LoadStoreScalingOption option = PreferScaledOffset);
// Store byte.
- void strb(const Register& rt, const MemOperand& dst);
+ void strb(const Register& rt, const MemOperand& dst,
+ LoadStoreScalingOption option = PreferScaledOffset);
// Load byte with sign extension.
- void ldrsb(const Register& rt, const MemOperand& src);
+ void ldrsb(const Register& rt, const MemOperand& src,
+ LoadStoreScalingOption option = PreferScaledOffset);
// Load half-word.
- void ldrh(const Register& rt, const MemOperand& src);
+ void ldrh(const Register& rt, const MemOperand& src,
+ LoadStoreScalingOption option = PreferScaledOffset);
// Store half-word.
- void strh(const Register& rt, const MemOperand& dst);
+ void strh(const Register& rt, const MemOperand& dst,
+ LoadStoreScalingOption option = PreferScaledOffset);
// Load half-word with sign extension.
- void ldrsh(const Register& rt, const MemOperand& src);
+ void ldrsh(const Register& rt, const MemOperand& src,
+ LoadStoreScalingOption option = PreferScaledOffset);
+
+ // Load integer or FP register (with unscaled offset).
+ void ldur(const CPURegister& rt, const MemOperand& src,
+ LoadStoreScalingOption option = PreferUnscaledOffset);
+
+ // Store integer or FP register (with unscaled offset).
+ void stur(const CPURegister& rt, const MemOperand& src,
+ LoadStoreScalingOption option = PreferUnscaledOffset);
+
+ // Load word with sign extension.
+ void ldursw(const Register& rt, const MemOperand& src,
+ LoadStoreScalingOption option = PreferUnscaledOffset);
+
+ // Load byte (with unscaled offset).
+ void ldurb(const Register& rt, const MemOperand& src,
+ LoadStoreScalingOption option = PreferUnscaledOffset);
+
+ // Store byte (with unscaled offset).
+ void sturb(const Register& rt, const MemOperand& dst,
+ LoadStoreScalingOption option = PreferUnscaledOffset);
+
+ // Load byte with sign extension (and unscaled offset).
+ void ldursb(const Register& rt, const MemOperand& src,
+ LoadStoreScalingOption option = PreferUnscaledOffset);
+
+ // Load half-word (with unscaled offset).
+ void ldurh(const Register& rt, const MemOperand& src,
+ LoadStoreScalingOption option = PreferUnscaledOffset);
+
+ // Store half-word (with unscaled offset).
+ void sturh(const Register& rt, const MemOperand& dst,
+ LoadStoreScalingOption option = PreferUnscaledOffset);
+
+ // Load half-word with sign extension (and unscaled offset).
+ void ldursh(const Register& rt, const MemOperand& src,
+ LoadStoreScalingOption option = PreferUnscaledOffset);
// Load integer or FP register pair.
void ldp(const CPURegister& rt, const CPURegister& rt2,
@@ -1157,14 +1411,90 @@ class Assembler {
void stnp(const CPURegister& rt, const CPURegister& rt2,
const MemOperand& dst);
- // Load literal to register.
- void ldr(const Register& rt, uint64_t imm);
+ // Load integer or FP register from literal pool.
+ void ldr(const CPURegister& rt, RawLiteral* literal);
+
+ // Load word with sign extension from literal pool.
+ void ldrsw(const Register& rt, RawLiteral* literal);
- // Load double precision floating point literal to FP register.
- void ldr(const FPRegister& ft, double imm);
+ // Load integer or FP register from pc + imm19 << 2.
+ void ldr(const CPURegister& rt, int imm19);
+
+ // Load word with sign extension from pc + imm19 << 2.
+ void ldrsw(const Register& rt, int imm19);
+
+ // Store exclusive byte.
+ void stxrb(const Register& rs, const Register& rt, const MemOperand& dst);
+
+ // Store exclusive half-word.
+ void stxrh(const Register& rs, const Register& rt, const MemOperand& dst);
+
+ // Store exclusive register.
+ void stxr(const Register& rs, const Register& rt, const MemOperand& dst);
+
+ // Load exclusive byte.
+ void ldxrb(const Register& rt, const MemOperand& src);
+
+ // Load exclusive half-word.
+ void ldxrh(const Register& rt, const MemOperand& src);
+
+ // Load exclusive register.
+ void ldxr(const Register& rt, const MemOperand& src);
+
+ // Store exclusive register pair.
+ void stxp(const Register& rs,
+ const Register& rt,
+ const Register& rt2,
+ const MemOperand& dst);
+
+ // Load exclusive register pair.
+ void ldxp(const Register& rt, const Register& rt2, const MemOperand& src);
+
+ // Store-release exclusive byte.
+ void stlxrb(const Register& rs, const Register& rt, const MemOperand& dst);
+
+ // Store-release exclusive half-word.
+ void stlxrh(const Register& rs, const Register& rt, const MemOperand& dst);
+
+ // Store-release exclusive register.
+ void stlxr(const Register& rs, const Register& rt, const MemOperand& dst);
+
+ // Load-acquire exclusive byte.
+ void ldaxrb(const Register& rt, const MemOperand& src);
+
+ // Load-acquire exclusive half-word.
+ void ldaxrh(const Register& rt, const MemOperand& src);
+
+ // Load-acquire exclusive register.
+ void ldaxr(const Register& rt, const MemOperand& src);
+
+ // Store-release exclusive register pair.
+ void stlxp(const Register& rs,
+ const Register& rt,
+ const Register& rt2,
+ const MemOperand& dst);
+
+ // Load-acquire exclusive register pair.
+ void ldaxp(const Register& rt, const Register& rt2, const MemOperand& src);
+
+ // Store-release byte.
+ void stlrb(const Register& rt, const MemOperand& dst);
+
+ // Store-release half-word.
+ void stlrh(const Register& rt, const MemOperand& dst);
+
+ // Store-release register.
+ void stlr(const Register& rt, const MemOperand& dst);
+
+ // Load-acquire byte.
+ void ldarb(const Register& rt, const MemOperand& src);
+
+ // Load-acquire half-word.
+ void ldarh(const Register& rt, const MemOperand& src);
+
+ // Load-acquire register.
+ void ldar(const Register& rt, const MemOperand& src);
- // Load single precision floating point literal to FP register.
- void ldr(const FPRegister& ft, float imm);
// Move instructions. The default shift of -1 indicates that the move
// instruction will calculate an appropriate 16-bit immediate and left shift
@@ -1214,6 +1544,9 @@ class Assembler {
// System hint.
void hint(SystemHint code);
+ // Clear exclusive monitor.
+ void clrex(int imm4 = 0xf);
+
// Data memory barrier.
void dmb(BarrierDomain domain, BarrierType type);
@@ -1375,25 +1708,26 @@ class Assembler {
inline void dci(Instr raw_inst) { Emit(raw_inst); }
// Emit 32 bits of data into the instruction stream.
- inline void dc32(uint32_t data) { EmitData(&data, sizeof(data)); }
+ inline 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) { EmitData(&data, sizeof(data)); }
+ inline void dc64(uint64_t data) {
+ VIXL_ASSERT(buffer_monitor_ > 0);
+ buffer_->Emit64(data);
+ }
// Copy a string into the instruction stream, including the terminating NULL
- // character. The instruction pointer (pc_) is then aligned correctly for
+ // character. The instruction pointer is then aligned correctly for
// subsequent instructions.
- void EmitStringData(const char * string) {
+ void EmitString(const char * string) {
VIXL_ASSERT(string != NULL);
+ VIXL_ASSERT(buffer_monitor_ > 0);
- size_t len = strlen(string) + 1;
- EmitData(string, len);
-
- // Pad with NULL characters until pc_ is aligned.
- const char pad[] = {'\0', '\0', '\0', '\0'};
- VIXL_STATIC_ASSERT(sizeof(pad) == kInstructionSize);
- Instruction* next_pc = AlignUp(pc_, kInstructionSize);
- EmitData(&pad, next_pc - pc_);
+ buffer_->EmitString(string);
+ buffer_->Align();
}
// Code generation helpers.
@@ -1429,6 +1763,11 @@ class Assembler {
return rt2.code() << Rt2_offset;
}
+ static Instr Rs(CPURegister rs) {
+ VIXL_ASSERT(rs.code() != kSPRegInternalCode);
+ return rs.code() << Rs_offset;
+ }
+
// These encoding functions allow the stack pointer to be encoded, and
// disallow the zero register.
static Instr RdSP(Register rd) {
@@ -1619,6 +1958,11 @@ class Assembler {
return imm7 << ImmHint_offset;
}
+ static Instr CRm(int imm4) {
+ VIXL_ASSERT(is_uint4(imm4));
+ return imm4 << CRm_offset;
+ }
+
static Instr ImmBarrierDomain(int imm2) {
VIXL_ASSERT(is_uint2(imm2));
return imm2 << ImmBarrierDomain_offset;
@@ -1659,55 +2003,73 @@ class Assembler {
return scale << FPScale_offset;
}
- // Size of the code generated in bytes
- uint64_t SizeOfCodeGenerated() const {
- VIXL_ASSERT((pc_ >= buffer_) && (pc_ < (buffer_ + buffer_size_)));
- return pc_ - buffer_;
- }
-
// Size of the code generated since label to the current position.
- uint64_t SizeOfCodeGeneratedSince(Label* label) const {
+ size_t SizeOfCodeGeneratedSince(Label* label) const {
VIXL_ASSERT(label->IsBound());
- VIXL_ASSERT((pc_ >= label->target()) && (pc_ < (buffer_ + buffer_size_)));
- return pc_ - label->target();
+ return buffer_->OffsetFrom(label->location());
}
+ size_t BufferCapacity() const { return buffer_->capacity(); }
- inline void BlockLiteralPool() {
- literal_pool_monitor_++;
- }
+ size_t RemainingBufferSpace() const { return buffer_->RemainingBytes(); }
- inline void ReleaseLiteralPool() {
- if (--literal_pool_monitor_ == 0) {
- // Has the literal pool been blocked for too long?
- VIXL_ASSERT(literals_.empty() ||
- (pc_ < (literals_.back()->pc_ + kMaxLoadLiteralRange)));
+ void EnsureSpaceFor(size_t amount) {
+ if (buffer_->RemainingBytes() < amount) {
+ size_t capacity = buffer_->capacity();
+ size_t size = buffer_->CursorOffset();
+ do {
+ // TODO(all): refine.
+ capacity *= 2;
+ } while ((capacity - size) < amount);
+ buffer_->Grow(capacity);
}
}
- inline bool IsLiteralPoolBlocked() {
- return literal_pool_monitor_ != 0;
+#ifdef DEBUG
+ void AcquireBuffer() {
+ VIXL_ASSERT(buffer_monitor_ >= 0);
+ buffer_monitor_++;
}
- void CheckLiteralPool(LiteralPoolEmitOption option = JumpRequired);
- void EmitLiteralPool(LiteralPoolEmitOption option = NoJumpRequired);
- size_t LiteralPoolSize();
+ void ReleaseBuffer() {
+ buffer_monitor_--;
+ VIXL_ASSERT(buffer_monitor_ >= 0);
+ }
+#endif
- protected:
- inline const Register& AppropriateZeroRegFor(const CPURegister& reg) const {
+ inline PositionIndependentCodeOption pic() {
+ return pic_;
+ }
+
+ inline bool AllowPageOffsetDependentCode() {
+ return (pic() == PageOffsetDependentCode) ||
+ (pic() == PositionDependentCode);
+ }
+
+ static inline const Register& AppropriateZeroRegFor(const CPURegister& reg) {
return reg.Is64Bits() ? xzr : wzr;
}
+ protected:
void LoadStore(const CPURegister& rt,
const MemOperand& addr,
- LoadStoreOp op);
- static bool IsImmLSUnscaled(ptrdiff_t offset);
- static bool IsImmLSScaled(ptrdiff_t offset, LSDataSize size);
+ 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);
+ // TODO(all): The third parameter should be passed by reference but gcc 4.8.2
+ // reports a bogus uninitialised warning then.
void Logical(const Register& rd,
const Register& rn,
- const Operand& operand,
+ const Operand operand,
LogicalOp op);
void LogicalImmediate(const Register& rd,
const Register& rn,
@@ -1717,9 +2079,9 @@ class Assembler {
LogicalOp op);
static bool IsImmLogical(uint64_t value,
unsigned width,
- unsigned* n,
- unsigned* imm_s,
- unsigned* imm_r);
+ unsigned* n = NULL,
+ unsigned* imm_s = NULL,
+ unsigned* imm_r = NULL);
void ConditionalCompare(const Register& rn,
const Operand& operand,
@@ -1768,6 +2130,7 @@ class Assembler {
const CPURegister& rt, const CPURegister& rt2);
static LoadStorePairNonTemporalOp StorePairNonTemporalOpFor(
const CPURegister& rt, const CPURegister& rt2);
+ static LoadLiteralOp LoadLiteralOpFor(const CPURegister& rt);
private:
@@ -1786,10 +2149,6 @@ class Assembler {
const Operand& operand,
FlagsUpdate S,
Instr op);
- void LoadStorePair(const CPURegister& rt,
- const CPURegister& rt2,
- const MemOperand& addr,
- LoadStorePairOp op);
void LoadStorePairNonTemporal(const CPURegister& rt,
const CPURegister& rt2,
const MemOperand& addr,
@@ -1821,75 +2180,110 @@ class Assembler {
const FPRegister& fa,
FPDataProcessing3SourceOp op);
- void RecordLiteral(int64_t imm, unsigned size);
+ // 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.
+ ptrdiff_t LinkAndGetByteOffsetTo(Label * label);
+ ptrdiff_t LinkAndGetInstructionOffsetTo(Label * label);
+ ptrdiff_t LinkAndGetPageOffsetTo(Label * label);
- // Emit the instruction at pc_.
- void Emit(Instr instruction) {
- VIXL_STATIC_ASSERT(sizeof(*pc_) == 1);
- VIXL_STATIC_ASSERT(sizeof(instruction) == kInstructionSize);
- VIXL_ASSERT((pc_ + sizeof(instruction)) <= (buffer_ + buffer_size_));
+ // A common implementation for the LinkAndGet<Type>OffsetTo helpers.
+ template <int element_shift>
+ ptrdiff_t LinkAndGetOffsetTo(Label* label);
-#ifdef DEBUG
- finalized_ = false;
-#endif
+ // Literal load offset are in words (32-bit).
+ ptrdiff_t LinkAndGetWordOffsetTo(RawLiteral* literal);
- memcpy(pc_, &instruction, sizeof(instruction));
- pc_ += sizeof(instruction);
- CheckBufferSpace();
+ // Emit the instruction in buffer_.
+ void Emit(Instr instruction) {
+ VIXL_STATIC_ASSERT(sizeof(instruction) == kInstructionSize);
+ VIXL_ASSERT(buffer_monitor_ > 0);
+ buffer_->Emit32(instruction);
}
- // Emit data inline in the instruction stream.
- void EmitData(void const * data, unsigned size) {
- VIXL_STATIC_ASSERT(sizeof(*pc_) == 1);
- VIXL_ASSERT((pc_ + size) <= (buffer_ + buffer_size_));
+ // Buffer where the code is emitted.
+ CodeBuffer* buffer_;
+ PositionIndependentCodeOption pic_;
#ifdef DEBUG
- finalized_ = false;
+ int64_t buffer_monitor_;
#endif
+};
- // TODO: Record this 'instruction' as data, so that it can be disassembled
- // correctly.
- memcpy(pc_, data, size);
- pc_ += size;
- CheckBufferSpace();
- }
-
- inline void CheckBufferSpace() {
- VIXL_ASSERT(pc_ < (buffer_ + buffer_size_));
- if (pc_ > next_literal_pool_check_) {
- CheckLiteralPool();
- }
- }
- // The buffer into which code and relocation info are generated.
- Instruction* buffer_;
- // Buffer size, in bytes.
- unsigned buffer_size_;
- Instruction* pc_;
- std::list<Literal*> literals_;
- Instruction* next_literal_pool_check_;
- unsigned literal_pool_monitor_;
+// All Assembler emits MUST acquire/release the underlying code buffer. The
+// helper scope below will do so and optionally ensure the buffer is big enough
+// to receive the emit. It is possible to request the scope not to perform any
+// checks (kNoCheck) if for example it is known in advance the buffer size is
+// adequate or there is some other size checking mechanism in place.
+class CodeBufferCheckScope {
+ public:
+ // Tell whether or not the scope needs to ensure the associated CodeBuffer
+ // has enough space for the requested size.
+ enum CheckPolicy {
+ kNoCheck,
+ kCheck
+ };
- friend class BlockLiteralPoolScope;
+ // Tell whether or not the scope should assert the amount of code emitted
+ // within the scope is consistent with the requested amount.
+ enum AssertPolicy {
+ kNoAssert, // No assert required.
+ kExactSize, // The code emitted must be exactly size bytes.
+ kMaximumSize // The code emitted must be at most size bytes.
+ };
+ CodeBufferCheckScope(Assembler* assm,
+ size_t size,
+ CheckPolicy check_policy = kCheck,
+ AssertPolicy assert_policy = kMaximumSize)
+ : assm_(assm) {
+ if (check_policy == kCheck) assm->EnsureSpaceFor(size);
#ifdef DEBUG
- bool finalized_;
+ assm->bind(&start_);
+ size_ = size;
+ assert_policy_ = assert_policy;
+ assm->AcquireBuffer();
+#else
+ USE(assert_policy);
#endif
-};
+ }
-class BlockLiteralPoolScope {
- public:
- explicit BlockLiteralPoolScope(Assembler* assm) : assm_(assm) {
- assm_->BlockLiteralPool();
+ // This is a shortcut for CodeBufferCheckScope(assm, 0, kNoCheck, kNoAssert).
+ explicit CodeBufferCheckScope(Assembler* assm) : assm_(assm) {
+#ifdef DEBUG
+ size_ = 0;
+ assert_policy_ = kNoAssert;
+ assm->AcquireBuffer();
+#endif
}
- ~BlockLiteralPoolScope() {
- assm_->ReleaseLiteralPool();
+ ~CodeBufferCheckScope() {
+#ifdef DEBUG
+ assm_->ReleaseBuffer();
+ switch (assert_policy_) {
+ case kNoAssert: break;
+ case kExactSize:
+ VIXL_ASSERT(assm_->SizeOfCodeGeneratedSince(&start_) == size_);
+ break;
+ case kMaximumSize:
+ VIXL_ASSERT(assm_->SizeOfCodeGeneratedSince(&start_) <= size_);
+ break;
+ default:
+ VIXL_UNREACHABLE();
+ }
+#endif
}
- private:
+ protected:
Assembler* assm_;
+#ifdef DEBUG
+ Label start_;
+ size_t size_;
+ AssertPolicy assert_policy_;
+#endif
};
+
} // namespace vixl
#endif // VIXL_A64_ASSEMBLER_A64_H_
diff --git a/disas/libvixl/a64/constants-a64.h b/disas/libvixl/a64/constants-a64.h
index 99677c1be..7a14f85f5 100644
--- a/disas/libvixl/a64/constants-a64.h
+++ b/disas/libvixl/a64/constants-a64.h
@@ -46,13 +46,13 @@ R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
#define INSTRUCTION_FIELDS_LIST(V_) \
/* Register fields */ \
-V_(Rd, 4, 0, Bits) /* Destination register. */ \
-V_(Rn, 9, 5, Bits) /* First source register. */ \
-V_(Rm, 20, 16, Bits) /* Second source register. */ \
-V_(Ra, 14, 10, Bits) /* Third source register. */ \
-V_(Rt, 4, 0, Bits) /* Load dest / store source. */ \
-V_(Rt2, 14, 10, Bits) /* Load second dest / */ \
- /* store second source. */ \
+V_(Rd, 4, 0, Bits) /* Destination register. */ \
+V_(Rn, 9, 5, Bits) /* First source register. */ \
+V_(Rm, 20, 16, Bits) /* Second source register. */ \
+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 */ \
@@ -126,6 +126,13 @@ V_(SysOp1, 18, 16, Bits) \
V_(SysOp2, 7, 5, Bits) \
V_(CRn, 15, 12, Bits) \
V_(CRm, 11, 8, Bits) \
+ \
+/* Load-/store-exclusive */ \
+V_(LdStXLoad, 22, 22, Bits) \
+V_(LdStXNotExclusive, 23, 23, Bits) \
+V_(LdStXAcquireRelease, 15, 15, Bits) \
+V_(LdStXSizeLog2, 31, 30, Bits) \
+V_(LdStXPair, 21, 21, Bits) \
#define SYSTEM_REGISTER_FIELDS_LIST(V_, M_) \
@@ -585,6 +592,13 @@ enum MemBarrierOp {
ISB = MemBarrierFixed | 0x00000040
};
+enum SystemExclusiveMonitorOp {
+ SystemExclusiveMonitorFixed = 0xD503305F,
+ SystemExclusiveMonitorFMask = 0xFFFFF0FF,
+ SystemExclusiveMonitorMask = 0xFFFFF0FF,
+ CLREX = SystemExclusiveMonitorFixed
+};
+
// Any load or store.
enum LoadStoreAnyOp {
LoadStoreAnyFMask = 0x0a000000,
@@ -702,7 +716,7 @@ enum LoadStoreUnscaledOffsetOp {
// Load/store (post, pre, offset and unsigned.)
enum LoadStoreOp {
- LoadStoreOpMask = 0xC4C00000,
+ LoadStoreOpMask = 0xC4C00000,
#define LOAD_STORE(A, B, C, D) \
A##B##_##C = D
LOAD_STORE_OP_LIST(LOAD_STORE),
@@ -756,6 +770,44 @@ enum LoadStoreRegisterOffset {
#undef LOAD_STORE_REGISTER_OFFSET
};
+enum LoadStoreExclusive {
+ LoadStoreExclusiveFixed = 0x08000000,
+ LoadStoreExclusiveFMask = 0x3F000000,
+ LoadStoreExclusiveMask = 0xFFE08000,
+ STXRB_w = LoadStoreExclusiveFixed | 0x00000000,
+ STXRH_w = LoadStoreExclusiveFixed | 0x40000000,
+ STXR_w = LoadStoreExclusiveFixed | 0x80000000,
+ STXR_x = LoadStoreExclusiveFixed | 0xC0000000,
+ LDXRB_w = LoadStoreExclusiveFixed | 0x00400000,
+ LDXRH_w = LoadStoreExclusiveFixed | 0x40400000,
+ LDXR_w = LoadStoreExclusiveFixed | 0x80400000,
+ LDXR_x = LoadStoreExclusiveFixed | 0xC0400000,
+ STXP_w = LoadStoreExclusiveFixed | 0x80200000,
+ STXP_x = LoadStoreExclusiveFixed | 0xC0200000,
+ LDXP_w = LoadStoreExclusiveFixed | 0x80600000,
+ LDXP_x = LoadStoreExclusiveFixed | 0xC0600000,
+ STLXRB_w = LoadStoreExclusiveFixed | 0x00008000,
+ STLXRH_w = LoadStoreExclusiveFixed | 0x40008000,
+ STLXR_w = LoadStoreExclusiveFixed | 0x80008000,
+ STLXR_x = LoadStoreExclusiveFixed | 0xC0008000,
+ LDAXRB_w = LoadStoreExclusiveFixed | 0x00408000,
+ LDAXRH_w = LoadStoreExclusiveFixed | 0x40408000,
+ LDAXR_w = LoadStoreExclusiveFixed | 0x80408000,
+ LDAXR_x = LoadStoreExclusiveFixed | 0xC0408000,
+ STLXP_w = LoadStoreExclusiveFixed | 0x80208000,
+ STLXP_x = LoadStoreExclusiveFixed | 0xC0208000,
+ LDAXP_w = LoadStoreExclusiveFixed | 0x80608000,
+ LDAXP_x = LoadStoreExclusiveFixed | 0xC0608000,
+ STLRB_w = LoadStoreExclusiveFixed | 0x00808000,
+ STLRH_w = LoadStoreExclusiveFixed | 0x40808000,
+ STLR_w = LoadStoreExclusiveFixed | 0x80808000,
+ STLR_x = LoadStoreExclusiveFixed | 0xC0808000,
+ LDARB_w = LoadStoreExclusiveFixed | 0x00C08000,
+ LDARH_w = LoadStoreExclusiveFixed | 0x40C08000,
+ LDAR_w = LoadStoreExclusiveFixed | 0x80C08000,
+ LDAR_x = LoadStoreExclusiveFixed | 0xC0C08000
+};
+
// Conditional compare.
enum ConditionalCompareOp {
ConditionalCompareMask = 0x60000000,
diff --git a/disas/libvixl/a64/cpu-a64.h b/disas/libvixl/a64/cpu-a64.h
index dfd8f015c..59b7974a1 100644
--- a/disas/libvixl/a64/cpu-a64.h
+++ b/disas/libvixl/a64/cpu-a64.h
@@ -28,6 +28,7 @@
#define VIXL_CPU_A64_H
#include "globals.h"
+#include "instructions-a64.h"
namespace vixl {
@@ -42,6 +43,32 @@ class CPU {
// safely run.
static void EnsureIAndDCacheCoherency(void *address, size_t length);
+ // Handle tagged pointers.
+ template <typename T>
+ static T SetPointerTag(T pointer, uint64_t tag) {
+ VIXL_ASSERT(is_uintn(kAddressTagWidth, tag));
+
+ // Use C-style casts to get static_cast behaviour for integral types (T),
+ // and reinterpret_cast behaviour for other types.
+
+ uint64_t raw = (uint64_t)pointer;
+ VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(raw));
+
+ raw = (raw & ~kAddressTagMask) | (tag << kAddressTagOffset);
+ return (T)raw;
+ }
+
+ template <typename T>
+ static uint64_t GetPointerTag(T pointer) {
+ // Use C-style casts to get static_cast behaviour for integral types (T),
+ // and reinterpret_cast behaviour for other types.
+
+ uint64_t raw = (uint64_t)pointer;
+ VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(raw));
+
+ return (raw & kAddressTagMask) >> kAddressTagOffset;
+ }
+
private:
// Return the content of the cache type register.
static uint32_t GetCacheType();
diff --git a/disas/libvixl/a64/decoder-a64.cc b/disas/libvixl/a64/decoder-a64.cc
index 8450eb3b4..82591ca30 100644
--- a/disas/libvixl/a64/decoder-a64.cc
+++ b/disas/libvixl/a64/decoder-a64.cc
@@ -29,8 +29,8 @@
#include "a64/decoder-a64.h"
namespace vixl {
-// Top-level instruction decode function.
-void Decoder::Decode(Instruction *instr) {
+
+void Decoder::DecodeInstruction(const Instruction *instr) {
if (instr->Bits(28, 27) == 0) {
VisitUnallocated(instr);
} else {
@@ -109,20 +109,17 @@ void Decoder::Decode(Instruction *instr) {
}
void Decoder::AppendVisitor(DecoderVisitor* new_visitor) {
- visitors_.remove(new_visitor);
- visitors_.push_front(new_visitor);
+ visitors_.push_back(new_visitor);
}
void Decoder::PrependVisitor(DecoderVisitor* new_visitor) {
- visitors_.remove(new_visitor);
- visitors_.push_back(new_visitor);
+ visitors_.push_front(new_visitor);
}
void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor,
DecoderVisitor* registered_visitor) {
- visitors_.remove(new_visitor);
std::list<DecoderVisitor*>::iterator it;
for (it = visitors_.begin(); it != visitors_.end(); it++) {
if (*it == registered_visitor) {
@@ -139,7 +136,6 @@ void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor,
void Decoder::InsertVisitorAfter(DecoderVisitor* new_visitor,
DecoderVisitor* registered_visitor) {
- visitors_.remove(new_visitor);
std::list<DecoderVisitor*>::iterator it;
for (it = visitors_.begin(); it != visitors_.end(); it++) {
if (*it == registered_visitor) {
@@ -160,7 +156,7 @@ void Decoder::RemoveVisitor(DecoderVisitor* visitor) {
}
-void Decoder::DecodePCRelAddressing(Instruction* instr) {
+void Decoder::DecodePCRelAddressing(const Instruction* instr) {
VIXL_ASSERT(instr->Bits(27, 24) == 0x0);
// We know bit 28 is set, as <b28:b27> = 0 is filtered out at the top level
// decode.
@@ -169,11 +165,11 @@ void Decoder::DecodePCRelAddressing(Instruction* instr) {
}
-void Decoder::DecodeBranchSystemException(Instruction* instr) {
+void Decoder::DecodeBranchSystemException(const Instruction* instr) {
VIXL_ASSERT((instr->Bits(27, 24) == 0x4) ||
- (instr->Bits(27, 24) == 0x5) ||
- (instr->Bits(27, 24) == 0x6) ||
- (instr->Bits(27, 24) == 0x7) );
+ (instr->Bits(27, 24) == 0x5) ||
+ (instr->Bits(27, 24) == 0x6) ||
+ (instr->Bits(27, 24) == 0x7) );
switch (instr->Bits(31, 29)) {
case 0:
@@ -270,18 +266,17 @@ void Decoder::DecodeBranchSystemException(Instruction* instr) {
}
-void Decoder::DecodeLoadStore(Instruction* instr) {
+void Decoder::DecodeLoadStore(const Instruction* instr) {
VIXL_ASSERT((instr->Bits(27, 24) == 0x8) ||
- (instr->Bits(27, 24) == 0x9) ||
- (instr->Bits(27, 24) == 0xC) ||
- (instr->Bits(27, 24) == 0xD) );
+ (instr->Bits(27, 24) == 0x9) ||
+ (instr->Bits(27, 24) == 0xC) ||
+ (instr->Bits(27, 24) == 0xD) );
if (instr->Bit(24) == 0) {
if (instr->Bit(28) == 0) {
if (instr->Bit(29) == 0) {
if (instr->Bit(26) == 0) {
- // TODO: VisitLoadStoreExclusive.
- VisitUnimplemented(instr);
+ VisitLoadStoreExclusive(instr);
} else {
DecodeAdvSIMDLoadStore(instr);
}
@@ -389,7 +384,7 @@ void Decoder::DecodeLoadStore(Instruction* instr) {
}
-void Decoder::DecodeLogical(Instruction* instr) {
+void Decoder::DecodeLogical(const Instruction* instr) {
VIXL_ASSERT(instr->Bits(27, 24) == 0x2);
if (instr->Mask(0x80400000) == 0x00400000) {
@@ -408,7 +403,7 @@ void Decoder::DecodeLogical(Instruction* instr) {
}
-void Decoder::DecodeBitfieldExtract(Instruction* instr) {
+void Decoder::DecodeBitfieldExtract(const Instruction* instr) {
VIXL_ASSERT(instr->Bits(27, 24) == 0x3);
if ((instr->Mask(0x80400000) == 0x80000000) ||
@@ -433,7 +428,7 @@ void Decoder::DecodeBitfieldExtract(Instruction* instr) {
}
-void Decoder::DecodeAddSubImmediate(Instruction* instr) {
+void Decoder::DecodeAddSubImmediate(const Instruction* instr) {
VIXL_ASSERT(instr->Bits(27, 24) == 0x1);
if (instr->Bit(23) == 1) {
VisitUnallocated(instr);
@@ -443,7 +438,7 @@ void Decoder::DecodeAddSubImmediate(Instruction* instr) {
}
-void Decoder::DecodeDataProcessing(Instruction* instr) {
+void Decoder::DecodeDataProcessing(const Instruction* instr) {
VIXL_ASSERT((instr->Bits(27, 24) == 0xA) ||
(instr->Bits(27, 24) == 0xB));
@@ -558,7 +553,7 @@ void Decoder::DecodeDataProcessing(Instruction* instr) {
}
-void Decoder::DecodeFP(Instruction* instr) {
+void Decoder::DecodeFP(const Instruction* instr) {
VIXL_ASSERT((instr->Bits(27, 24) == 0xE) ||
(instr->Bits(27, 24) == 0xF));
@@ -685,14 +680,14 @@ void Decoder::DecodeFP(Instruction* instr) {
}
-void Decoder::DecodeAdvSIMDLoadStore(Instruction* instr) {
+void Decoder::DecodeAdvSIMDLoadStore(const Instruction* instr) {
// TODO: Implement Advanced SIMD load/store instruction decode.
VIXL_ASSERT(instr->Bits(29, 25) == 0x6);
VisitUnimplemented(instr);
}
-void Decoder::DecodeAdvSIMDDataProcessing(Instruction* instr) {
+void Decoder::DecodeAdvSIMDDataProcessing(const Instruction* instr) {
// TODO: Implement Advanced SIMD data processing instruction decode.
VIXL_ASSERT(instr->Bits(27, 25) == 0x7);
VisitUnimplemented(instr);
@@ -700,7 +695,7 @@ void Decoder::DecodeAdvSIMDDataProcessing(Instruction* instr) {
#define DEFINE_VISITOR_CALLERS(A) \
- void Decoder::Visit##A(Instruction *instr) { \
+ void Decoder::Visit##A(const Instruction *instr) { \
VIXL_ASSERT(instr->Mask(A##FMask) == A##Fixed); \
std::list<DecoderVisitor*>::iterator it; \
for (it = visitors_.begin(); it != visitors_.end(); it++) { \
diff --git a/disas/libvixl/a64/decoder-a64.h b/disas/libvixl/a64/decoder-a64.h
index bbbbd8124..172594c89 100644
--- a/disas/libvixl/a64/decoder-a64.h
+++ b/disas/libvixl/a64/decoder-a64.h
@@ -59,6 +59,7 @@
V(LoadStorePreIndex) \
V(LoadStoreRegisterOffset) \
V(LoadStoreUnsignedOffset) \
+ V(LoadStoreExclusive) \
V(LogicalShifted) \
V(AddSubShifted) \
V(AddSubExtended) \
@@ -87,112 +88,152 @@ namespace vixl {
// must provide implementations for all of these functions.
class DecoderVisitor {
public:
- #define DECLARE(A) virtual void Visit##A(Instruction* instr) = 0;
+ enum VisitorConstness {
+ kConstVisitor,
+ kNonConstVisitor
+ };
+ explicit DecoderVisitor(VisitorConstness constness = kConstVisitor)
+ : constness_(constness) {}
+
+ virtual ~DecoderVisitor() {}
+
+ #define DECLARE(A) virtual void Visit##A(const Instruction* instr) = 0;
VISITOR_LIST(DECLARE)
#undef DECLARE
- virtual ~DecoderVisitor() {}
+ bool IsConstVisitor() const { return constness_ == kConstVisitor; }
+ Instruction* MutableInstruction(const Instruction* instr) {
+ VIXL_ASSERT(!IsConstVisitor());
+ return const_cast<Instruction*>(instr);
+ }
private:
- // Visitors are registered in a list.
- std::list<DecoderVisitor*> visitors_;
-
- friend class Decoder;
+ VisitorConstness constness_;
};
-class Decoder: public DecoderVisitor {
+class Decoder {
public:
Decoder() {}
- // Top-level instruction decoder function. Decodes an instruction and calls
- // the visitor functions registered with the Decoder class.
- void Decode(Instruction *instr);
+ // Top-level wrappers around the actual decoding function.
+ void Decode(const Instruction* instr) {
+ std::list<DecoderVisitor*>::iterator it;
+ for (it = visitors_.begin(); it != visitors_.end(); it++) {
+ VIXL_ASSERT((*it)->IsConstVisitor());
+ }
+ DecodeInstruction(instr);
+ }
+ void Decode(Instruction* instr) {
+ DecodeInstruction(const_cast<const Instruction*>(instr));
+ }
// Register a new visitor class with the decoder.
// Decode() will call the corresponding visitor method from all registered
// visitor classes when decoding reaches the leaf node of the instruction
// decode tree.
- // Visitors are called in the order.
- // A visitor can only be registered once.
- // Registering an already registered visitor will update its position.
+ // Visitors are called in order.
+ // A visitor can be registered multiple times.
//
// d.AppendVisitor(V1);
// d.AppendVisitor(V2);
- // d.PrependVisitor(V2); // Move V2 at the start of the list.
- // d.InsertVisitorBefore(V3, V2);
- // d.AppendVisitor(V4);
- // d.AppendVisitor(V4); // No effect.
+ // d.PrependVisitor(V2);
+ // d.AppendVisitor(V3);
//
// d.Decode(i);
//
- // will call in order visitor methods in V3, V2, V1, V4.
+ // will call in order visitor methods in V2, V1, V2, V3.
void AppendVisitor(DecoderVisitor* visitor);
void PrependVisitor(DecoderVisitor* visitor);
+ // These helpers register `new_visitor` before or after the first instance of
+ // `registered_visiter` in the list.
+ // So if
+ // V1, V2, V1, V2
+ // are registered in this order in the decoder, calls to
+ // d.InsertVisitorAfter(V3, V1);
+ // d.InsertVisitorBefore(V4, V2);
+ // will yield the order
+ // V1, V3, V4, V2, V1, V2
+ //
+ // For more complex modifications of the order of registered visitors, one can
+ // directly access and modify the list of visitors via the `visitors()'
+ // accessor.
void InsertVisitorBefore(DecoderVisitor* new_visitor,
DecoderVisitor* registered_visitor);
void InsertVisitorAfter(DecoderVisitor* new_visitor,
DecoderVisitor* registered_visitor);
- // Remove a previously registered visitor class from the list of visitors
- // stored by the decoder.
+ // Remove all instances of a previously registered visitor class from the list
+ // of visitors stored by the decoder.
void RemoveVisitor(DecoderVisitor* visitor);
- #define DECLARE(A) void Visit##A(Instruction* instr);
+ #define DECLARE(A) void Visit##A(const Instruction* instr);
VISITOR_LIST(DECLARE)
#undef DECLARE
+
+ std::list<DecoderVisitor*>* visitors() { return &visitors_; }
+
private:
+ // Decodes an instruction and calls the visitor functions registered with the
+ // Decoder class.
+ void DecodeInstruction(const Instruction* instr);
+
// Decode the PC relative addressing instruction, and call the corresponding
// visitors.
// On entry, instruction bits 27:24 = 0x0.
- void DecodePCRelAddressing(Instruction* instr);
+ void DecodePCRelAddressing(const Instruction* instr);
// Decode the add/subtract immediate instruction, and call the correspoding
// visitors.
// On entry, instruction bits 27:24 = 0x1.
- void DecodeAddSubImmediate(Instruction* instr);
+ void DecodeAddSubImmediate(const Instruction* instr);
// Decode the branch, system command, and exception generation parts of
// the instruction tree, and call the corresponding visitors.
// On entry, instruction bits 27:24 = {0x4, 0x5, 0x6, 0x7}.
- void DecodeBranchSystemException(Instruction* instr);
+ void DecodeBranchSystemException(const Instruction* instr);
// Decode the load and store parts of the instruction tree, and call
// the corresponding visitors.
// On entry, instruction bits 27:24 = {0x8, 0x9, 0xC, 0xD}.
- void DecodeLoadStore(Instruction* instr);
+ void DecodeLoadStore(const Instruction* instr);
// Decode the logical immediate and move wide immediate parts of the
// instruction tree, and call the corresponding visitors.
// On entry, instruction bits 27:24 = 0x2.
- void DecodeLogical(Instruction* instr);
+ void DecodeLogical(const Instruction* instr);
// Decode the bitfield and extraction parts of the instruction tree,
// and call the corresponding visitors.
// On entry, instruction bits 27:24 = 0x3.
- void DecodeBitfieldExtract(Instruction* instr);
+ void DecodeBitfieldExtract(const Instruction* instr);
// Decode the data processing parts of the instruction tree, and call the
// corresponding visitors.
// On entry, instruction bits 27:24 = {0x1, 0xA, 0xB}.
- void DecodeDataProcessing(Instruction* instr);
+ void DecodeDataProcessing(const Instruction* instr);
// Decode the floating point parts of the instruction tree, and call the
// corresponding visitors.
// On entry, instruction bits 27:24 = {0xE, 0xF}.
- void DecodeFP(Instruction* instr);
+ void DecodeFP(const Instruction* instr);
// Decode the Advanced SIMD (NEON) load/store part of the instruction tree,
// and call the corresponding visitors.
// On entry, instruction bits 29:25 = 0x6.
- void DecodeAdvSIMDLoadStore(Instruction* instr);
+ void DecodeAdvSIMDLoadStore(const Instruction* instr);
// Decode the Advanced SIMD (NEON) data processing part of the instruction
// tree, and call the corresponding visitors.
// On entry, instruction bits 27:25 = 0x7.
- void DecodeAdvSIMDDataProcessing(Instruction* instr);
+ void DecodeAdvSIMDDataProcessing(const Instruction* instr);
+
+ private:
+ // Visitors are registered in a list.
+ std::list<DecoderVisitor*> visitors_;
};
+
} // namespace vixl
#endif // VIXL_A64_DECODER_A64_H_
diff --git a/disas/libvixl/a64/disasm-a64.cc b/disas/libvixl/a64/disasm-a64.cc
index f81ce4bbb..e4a74aa57 100644
--- a/disas/libvixl/a64/disasm-a64.cc
+++ b/disas/libvixl/a64/disasm-a64.cc
@@ -24,6 +24,7 @@
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <cstdlib>
#include "a64/disasm-a64.h"
namespace vixl {
@@ -56,7 +57,7 @@ char* Disassembler::GetOutput() {
}
-void Disassembler::VisitAddSubImmediate(Instruction* instr) {
+void Disassembler::VisitAddSubImmediate(const Instruction* instr) {
bool rd_is_zr = RdIsZROrSP(instr);
bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
(instr->ImmAddSub() == 0) ? true : false;
@@ -101,7 +102,7 @@ void Disassembler::VisitAddSubImmediate(Instruction* instr) {
}
-void Disassembler::VisitAddSubShifted(Instruction* instr) {
+void Disassembler::VisitAddSubShifted(const Instruction* instr) {
bool rd_is_zr = RdIsZROrSP(instr);
bool rn_is_zr = RnIsZROrSP(instr);
const char *mnemonic = "";
@@ -148,7 +149,7 @@ void Disassembler::VisitAddSubShifted(Instruction* instr) {
}
-void Disassembler::VisitAddSubExtended(Instruction* instr) {
+void Disassembler::VisitAddSubExtended(const Instruction* instr) {
bool rd_is_zr = RdIsZROrSP(instr);
const char *mnemonic = "";
Extend mode = static_cast<Extend>(instr->ExtendMode());
@@ -186,7 +187,7 @@ void Disassembler::VisitAddSubExtended(Instruction* instr) {
}
-void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
+void Disassembler::VisitAddSubWithCarry(const Instruction* instr) {
bool rn_is_zr = RnIsZROrSP(instr);
const char *mnemonic = "";
const char *form = "'Rd, 'Rn, 'Rm";
@@ -221,7 +222,7 @@ void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
}
-void Disassembler::VisitLogicalImmediate(Instruction* instr) {
+void Disassembler::VisitLogicalImmediate(const Instruction* instr) {
bool rd_is_zr = RdIsZROrSP(instr);
bool rn_is_zr = RnIsZROrSP(instr);
const char *mnemonic = "";
@@ -293,7 +294,7 @@ bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
}
-void Disassembler::VisitLogicalShifted(Instruction* instr) {
+void Disassembler::VisitLogicalShifted(const Instruction* instr) {
bool rd_is_zr = RdIsZROrSP(instr);
bool rn_is_zr = RnIsZROrSP(instr);
const char *mnemonic = "";
@@ -344,7 +345,7 @@ void Disassembler::VisitLogicalShifted(Instruction* instr) {
}
-void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
+void Disassembler::VisitConditionalCompareRegister(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
@@ -359,7 +360,7 @@ void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
}
-void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
+void Disassembler::VisitConditionalCompareImmediate(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
@@ -374,7 +375,7 @@ void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
}
-void Disassembler::VisitConditionalSelect(Instruction* instr) {
+void Disassembler::VisitConditionalSelect(const Instruction* instr) {
bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
bool rn_is_rm = (instr->Rn() == instr->Rm());
const char *mnemonic = "";
@@ -427,7 +428,7 @@ void Disassembler::VisitConditionalSelect(Instruction* instr) {
}
-void Disassembler::VisitBitfield(Instruction* instr) {
+void Disassembler::VisitBitfield(const Instruction* instr) {
unsigned s = instr->ImmS();
unsigned r = instr->ImmR();
unsigned rd_size_minus_1 =
@@ -505,7 +506,7 @@ void Disassembler::VisitBitfield(Instruction* instr) {
}
-void Disassembler::VisitExtract(Instruction* instr) {
+void Disassembler::VisitExtract(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
@@ -526,16 +527,16 @@ void Disassembler::VisitExtract(Instruction* instr) {
}
-void Disassembler::VisitPCRelAddressing(Instruction* instr) {
+void Disassembler::VisitPCRelAddressing(const Instruction* instr) {
switch (instr->Mask(PCRelAddressingMask)) {
case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
- // ADRP is not implemented.
+ case ADRP: Format(instr, "adrp", "'Xd, 'AddrPCRelPage"); break;
default: Format(instr, "unimplemented", "(PCRelAddressing)");
}
}
-void Disassembler::VisitConditionalBranch(Instruction* instr) {
+void Disassembler::VisitConditionalBranch(const Instruction* instr) {
switch (instr->Mask(ConditionalBranchMask)) {
case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
default: VIXL_UNREACHABLE();
@@ -543,7 +544,8 @@ void Disassembler::VisitConditionalBranch(Instruction* instr) {
}
-void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) {
+void Disassembler::VisitUnconditionalBranchToRegister(
+ const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "'Xn";
@@ -563,7 +565,7 @@ void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) {
}
-void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
+void Disassembler::VisitUnconditionalBranch(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'BImmUncn";
@@ -576,7 +578,7 @@ void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
}
-void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
+void Disassembler::VisitDataProcessing1Source(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rd, 'Rn";
@@ -597,7 +599,7 @@ void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
}
-void Disassembler::VisitDataProcessing2Source(Instruction* instr) {
+void Disassembler::VisitDataProcessing2Source(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "'Rd, 'Rn, 'Rm";
@@ -618,7 +620,7 @@ void Disassembler::VisitDataProcessing2Source(Instruction* instr) {
}
-void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
+void Disassembler::VisitDataProcessing3Source(const Instruction* instr) {
bool ra_is_zr = RaIsZROrSP(instr);
const char *mnemonic = "";
const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
@@ -696,7 +698,7 @@ void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
}
-void Disassembler::VisitCompareBranch(Instruction* instr) {
+void Disassembler::VisitCompareBranch(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rt, 'BImmCmpa";
@@ -711,7 +713,7 @@ void Disassembler::VisitCompareBranch(Instruction* instr) {
}
-void Disassembler::VisitTestBranch(Instruction* instr) {
+void Disassembler::VisitTestBranch(const Instruction* instr) {
const char *mnemonic = "";
// If the top bit of the immediate is clear, the tested register is
// disassembled as Wt, otherwise Xt. As the top bit of the immediate is
@@ -728,7 +730,7 @@ void Disassembler::VisitTestBranch(Instruction* instr) {
}
-void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
+void Disassembler::VisitMoveWideImmediate(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rd, 'IMoveImm";
@@ -767,7 +769,7 @@ void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
V(LDR_s, "ldr", "'St") \
V(LDR_d, "ldr", "'Dt")
-void Disassembler::VisitLoadStorePreIndex(Instruction* instr) {
+void Disassembler::VisitLoadStorePreIndex(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStorePreIndex)";
@@ -781,7 +783,7 @@ void Disassembler::VisitLoadStorePreIndex(Instruction* instr) {
}
-void Disassembler::VisitLoadStorePostIndex(Instruction* instr) {
+void Disassembler::VisitLoadStorePostIndex(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStorePostIndex)";
@@ -795,7 +797,7 @@ void Disassembler::VisitLoadStorePostIndex(Instruction* instr) {
}
-void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) {
+void Disassembler::VisitLoadStoreUnsignedOffset(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStoreUnsignedOffset)";
@@ -810,7 +812,7 @@ void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) {
}
-void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) {
+void Disassembler::VisitLoadStoreRegisterOffset(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStoreRegisterOffset)";
@@ -825,7 +827,7 @@ void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) {
}
-void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) {
+void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "'Wt, ['Xns'ILS]";
const char *form_x = "'Xt, ['Xns'ILS]";
@@ -856,7 +858,7 @@ void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) {
}
-void Disassembler::VisitLoadLiteral(Instruction* instr) {
+void Disassembler::VisitLoadLiteral(const Instruction* instr) {
const char *mnemonic = "ldr";
const char *form = "(LoadLiteral)";
@@ -865,6 +867,11 @@ void Disassembler::VisitLoadLiteral(Instruction* instr) {
case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
+ case LDRSW_x_lit: {
+ mnemonic = "ldrsw";
+ form = "'Xt, 'ILLiteral 'LValue";
+ break;
+ }
default: mnemonic = "unimplemented";
}
Format(instr, mnemonic, form);
@@ -882,7 +889,7 @@ void Disassembler::VisitLoadLiteral(Instruction* instr) {
V(STP_d, "stp", "'Dt, 'Dt2", "8") \
V(LDP_d, "ldp", "'Dt, 'Dt2", "8")
-void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) {
+void Disassembler::VisitLoadStorePairPostIndex(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStorePairPostIndex)";
@@ -896,7 +903,7 @@ void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) {
}
-void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) {
+void Disassembler::VisitLoadStorePairPreIndex(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStorePairPreIndex)";
@@ -910,7 +917,7 @@ void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) {
}
-void Disassembler::VisitLoadStorePairOffset(Instruction* instr) {
+void Disassembler::VisitLoadStorePairOffset(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStorePairOffset)";
@@ -924,7 +931,7 @@ void Disassembler::VisitLoadStorePairOffset(Instruction* instr) {
}
-void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) {
+void Disassembler::VisitLoadStorePairNonTemporal(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form;
@@ -943,7 +950,50 @@ void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) {
}
-void Disassembler::VisitFPCompare(Instruction* instr) {
+void Disassembler::VisitLoadStoreExclusive(const Instruction* instr) {
+ const char *mnemonic = "unimplemented";
+ const char *form;
+
+ switch (instr->Mask(LoadStoreExclusiveMask)) {
+ case STXRB_w: mnemonic = "stxrb"; form = "'Ws, 'Wt, ['Xns]"; break;
+ case STXRH_w: mnemonic = "stxrh"; form = "'Ws, 'Wt, ['Xns]"; break;
+ case STXR_w: mnemonic = "stxr"; form = "'Ws, 'Wt, ['Xns]"; break;
+ case STXR_x: mnemonic = "stxr"; form = "'Ws, 'Xt, ['Xns]"; break;
+ case LDXRB_w: mnemonic = "ldxrb"; form = "'Wt, ['Xns]"; break;
+ case LDXRH_w: mnemonic = "ldxrh"; form = "'Wt, ['Xns]"; break;
+ case LDXR_w: mnemonic = "ldxr"; form = "'Wt, ['Xns]"; break;
+ case LDXR_x: mnemonic = "ldxr"; form = "'Xt, ['Xns]"; break;
+ case STXP_w: mnemonic = "stxp"; form = "'Ws, 'Wt, 'Wt2, ['Xns]"; break;
+ case STXP_x: mnemonic = "stxp"; form = "'Ws, 'Xt, 'Xt2, ['Xns]"; break;
+ case LDXP_w: mnemonic = "ldxp"; form = "'Wt, 'Wt2, ['Xns]"; break;
+ case LDXP_x: mnemonic = "ldxp"; form = "'Xt, 'Xt2, ['Xns]"; break;
+ case STLXRB_w: mnemonic = "stlxrb"; form = "'Ws, 'Wt, ['Xns]"; break;
+ case STLXRH_w: mnemonic = "stlxrh"; form = "'Ws, 'Wt, ['Xns]"; break;
+ case STLXR_w: mnemonic = "stlxr"; form = "'Ws, 'Wt, ['Xns]"; break;
+ case STLXR_x: mnemonic = "stlxr"; form = "'Ws, 'Xt, ['Xns]"; break;
+ case LDAXRB_w: mnemonic = "ldaxrb"; form = "'Wt, ['Xns]"; break;
+ case LDAXRH_w: mnemonic = "ldaxrh"; form = "'Wt, ['Xns]"; break;
+ case LDAXR_w: mnemonic = "ldaxr"; form = "'Wt, ['Xns]"; break;
+ case LDAXR_x: mnemonic = "ldaxr"; form = "'Xt, ['Xns]"; break;
+ case STLXP_w: mnemonic = "stlxp"; form = "'Ws, 'Wt, 'Wt2, ['Xns]"; break;
+ case STLXP_x: mnemonic = "stlxp"; form = "'Ws, 'Xt, 'Xt2, ['Xns]"; break;
+ case LDAXP_w: mnemonic = "ldaxp"; form = "'Wt, 'Wt2, ['Xns]"; break;
+ case LDAXP_x: mnemonic = "ldaxp"; form = "'Xt, 'Xt2, ['Xns]"; break;
+ case STLRB_w: mnemonic = "stlrb"; form = "'Wt, ['Xns]"; break;
+ case STLRH_w: mnemonic = "stlrh"; form = "'Wt, ['Xns]"; break;
+ case STLR_w: mnemonic = "stlr"; form = "'Wt, ['Xns]"; break;
+ case STLR_x: mnemonic = "stlr"; form = "'Xt, ['Xns]"; break;
+ case LDARB_w: mnemonic = "ldarb"; form = "'Wt, ['Xns]"; break;
+ case LDARH_w: mnemonic = "ldarh"; form = "'Wt, ['Xns]"; break;
+ case LDAR_w: mnemonic = "ldar"; form = "'Wt, ['Xns]"; break;
+ case LDAR_x: mnemonic = "ldar"; form = "'Xt, ['Xns]"; break;
+ default: form = "(LoadStoreExclusive)";
+ }
+ Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitFPCompare(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "'Fn, 'Fm";
const char *form_zero = "'Fn, #0.0";
@@ -959,7 +1009,7 @@ void Disassembler::VisitFPCompare(Instruction* instr) {
}
-void Disassembler::VisitFPConditionalCompare(Instruction* instr) {
+void Disassembler::VisitFPConditionalCompare(const Instruction* instr) {
const char *mnemonic = "unmplemented";
const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
@@ -974,7 +1024,7 @@ void Disassembler::VisitFPConditionalCompare(Instruction* instr) {
}
-void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
+void Disassembler::VisitFPConditionalSelect(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
@@ -987,7 +1037,7 @@ void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
}
-void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) {
+void Disassembler::VisitFPDataProcessing1Source(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "'Fd, 'Fn";
@@ -1015,7 +1065,7 @@ void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) {
}
-void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
+void Disassembler::VisitFPDataProcessing2Source(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Fd, 'Fn, 'Fm";
@@ -1039,7 +1089,7 @@ void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
}
-void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
+void Disassembler::VisitFPDataProcessing3Source(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
@@ -1058,7 +1108,7 @@ void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
}
-void Disassembler::VisitFPImmediate(Instruction* instr) {
+void Disassembler::VisitFPImmediate(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "(FPImmediate)";
@@ -1071,7 +1121,7 @@ void Disassembler::VisitFPImmediate(Instruction* instr) {
}
-void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
+void Disassembler::VisitFPIntegerConvert(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(FPIntegerConvert)";
const char *form_rf = "'Rd, 'Fn";
@@ -1127,7 +1177,7 @@ void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
}
-void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
+void Disassembler::VisitFPFixedPointConvert(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rd, 'Fn, 'IFPFBits";
const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
@@ -1155,14 +1205,22 @@ void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
}
-void Disassembler::VisitSystem(Instruction* instr) {
+void Disassembler::VisitSystem(const Instruction* instr) {
// Some system instructions hijack their Op and Cp fields to represent a
// range of immediates instead of indicating a different instruction. This
// makes the decoding tricky.
const char *mnemonic = "unimplemented";
const char *form = "(System)";
- if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
+ if (instr->Mask(SystemExclusiveMonitorFMask) == SystemExclusiveMonitorFixed) {
+ switch (instr->Mask(SystemExclusiveMonitorMask)) {
+ case CLREX: {
+ mnemonic = "clrex";
+ form = (instr->CRm() == 0xf) ? NULL : "'IX";
+ break;
+ }
+ }
+ } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
switch (instr->Mask(SystemSysRegMask)) {
case MRS: {
mnemonic = "mrs";
@@ -1184,7 +1242,6 @@ void Disassembler::VisitSystem(Instruction* instr) {
}
}
} else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
- VIXL_ASSERT(instr->Mask(SystemHintMask) == HINT);
switch (instr->ImmHint()) {
case NOP: {
mnemonic = "nop";
@@ -1216,7 +1273,7 @@ void Disassembler::VisitSystem(Instruction* instr) {
}
-void Disassembler::VisitException(Instruction* instr) {
+void Disassembler::VisitException(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "'IDebug";
@@ -1235,22 +1292,75 @@ void Disassembler::VisitException(Instruction* instr) {
}
-void Disassembler::VisitUnimplemented(Instruction* instr) {
+void Disassembler::VisitUnimplemented(const Instruction* instr) {
Format(instr, "unimplemented", "(Unimplemented)");
}
-void Disassembler::VisitUnallocated(Instruction* instr) {
+void Disassembler::VisitUnallocated(const Instruction* instr) {
Format(instr, "unallocated", "(Unallocated)");
}
-void Disassembler::ProcessOutput(Instruction* /*instr*/) {
+void Disassembler::ProcessOutput(const Instruction* /*instr*/) {
// The base disasm does nothing more than disassembling into a buffer.
}
-void Disassembler::Format(Instruction* instr, const char* mnemonic,
+void Disassembler::AppendRegisterNameToOutput(const Instruction* instr,
+ const CPURegister& reg) {
+ USE(instr);
+ VIXL_ASSERT(reg.IsValid());
+ char reg_char;
+
+ if (reg.IsRegister()) {
+ reg_char = reg.Is64Bits() ? 'x' : 'w';
+ } else {
+ VIXL_ASSERT(reg.IsFPRegister());
+ reg_char = reg.Is64Bits() ? 'd' : 's';
+ }
+
+ if (reg.IsFPRegister() || !(reg.Aliases(sp) || reg.Aliases(xzr))) {
+ // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
+ AppendToOutput("%c%d", reg_char, reg.code());
+ } else if (reg.Aliases(sp)) {
+ // Disassemble w31/x31 as stack pointer wsp/sp.
+ AppendToOutput("%s", reg.Is64Bits() ? "sp" : "wsp");
+ } else {
+ // Disassemble w31/x31 as zero register wzr/xzr.
+ AppendToOutput("%czr", reg_char);
+ }
+}
+
+
+void Disassembler::AppendPCRelativeOffsetToOutput(const Instruction* instr,
+ int64_t offset) {
+ USE(instr);
+ char sign = (offset < 0) ? '-' : '+';
+ AppendToOutput("#%c0x%" PRIx64, sign, std::abs(offset));
+}
+
+
+void Disassembler::AppendAddressToOutput(const Instruction* instr,
+ const void* addr) {
+ USE(instr);
+ AppendToOutput("(addr %p)", addr);
+}
+
+
+void Disassembler::AppendCodeAddressToOutput(const Instruction* instr,
+ const void* addr) {
+ AppendAddressToOutput(instr, addr);
+}
+
+
+void Disassembler::AppendDataAddressToOutput(const Instruction* instr,
+ const void* addr) {
+ AppendAddressToOutput(instr, addr);
+}
+
+
+void Disassembler::Format(const Instruction* instr, const char* mnemonic,
const char* format) {
VIXL_ASSERT(mnemonic != NULL);
ResetOutput();
@@ -1264,7 +1374,7 @@ void Disassembler::Format(Instruction* instr, const char* mnemonic,
}
-void Disassembler::Substitute(Instruction* instr, const char* string) {
+void Disassembler::Substitute(const Instruction* instr, const char* string) {
char chr = *string++;
while (chr != '\0') {
if (chr == '\'') {
@@ -1277,7 +1387,8 @@ void Disassembler::Substitute(Instruction* instr, const char* string) {
}
-int Disassembler::SubstituteField(Instruction* instr, const char* format) {
+int Disassembler::SubstituteField(const Instruction* instr,
+ const char* format) {
switch (format[0]) {
case 'R': // Register. X or W, selected by sf bit.
case 'F': // FP Register. S or D, selected by type field.
@@ -1303,7 +1414,7 @@ int Disassembler::SubstituteField(Instruction* instr, const char* format) {
}
-int Disassembler::SubstituteRegisterField(Instruction* instr,
+int Disassembler::SubstituteRegisterField(const Instruction* instr,
const char* format) {
unsigned reg_num = 0;
unsigned field_len = 2;
@@ -1312,6 +1423,7 @@ int Disassembler::SubstituteRegisterField(Instruction* instr,
case 'n': reg_num = instr->Rn(); break;
case 'm': reg_num = instr->Rm(); break;
case 'a': reg_num = instr->Ra(); break;
+ case 's': reg_num = instr->Rs(); break;
case 't': {
if (format[2] == '2') {
reg_num = instr->Rt2();
@@ -1329,34 +1441,47 @@ int Disassembler::SubstituteRegisterField(Instruction* instr,
field_len = 3;
}
- char reg_type;
+ CPURegister::RegisterType reg_type;
+ unsigned reg_size;
+
if (format[0] == 'R') {
// Register type is R: use sf bit to choose X and W.
- reg_type = instr->SixtyFourBits() ? 'x' : 'w';
+ reg_type = CPURegister::kRegister;
+ reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
} else if (format[0] == 'F') {
// Floating-point register: use type field to choose S or D.
- reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd';
+ reg_type = CPURegister::kFPRegister;
+ reg_size = ((instr->FPType() & 1) == 0) ? kSRegSize : kDRegSize;
} else {
- // Register type is specified. Make it lower case.
- reg_type = format[0] + 0x20;
+ // The register type is specified.
+ switch (format[0]) {
+ case 'W':
+ reg_type = CPURegister::kRegister; reg_size = kWRegSize; break;
+ case 'X':
+ reg_type = CPURegister::kRegister; reg_size = kXRegSize; break;
+ case 'S':
+ reg_type = CPURegister::kFPRegister; reg_size = kSRegSize; break;
+ case 'D':
+ reg_type = CPURegister::kFPRegister; reg_size = kDRegSize; break;
+ default:
+ VIXL_UNREACHABLE();
+ reg_type = CPURegister::kRegister;
+ reg_size = kXRegSize;
+ }
}
- if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) {
- // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
- AppendToOutput("%c%d", reg_type, reg_num);
- } else if (format[2] == 's') {
- // Disassemble w31/x31 as stack pointer wsp/sp.
- AppendToOutput("%s", (reg_type == 'w') ? "wsp" : "sp");
- } else {
- // Disassemble w31/x31 as zero register wzr/xzr.
- AppendToOutput("%czr", reg_type);
+ if ((reg_type == CPURegister::kRegister) &&
+ (reg_num == kZeroRegCode) && (format[2] == 's')) {
+ reg_num = kSPRegInternalCode;
}
+ AppendRegisterNameToOutput(instr, CPURegister(reg_num, reg_size, reg_type));
+
return field_len;
}
-int Disassembler::SubstituteImmediateField(Instruction* instr,
+int Disassembler::SubstituteImmediateField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(format[0] == 'I');
@@ -1406,8 +1531,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
}
case 'C': { // ICondB - Immediate Conditional Branch.
int64_t offset = instr->ImmCondBranch() << 2;
- char sign = (offset >= 0) ? '+' : '-';
- AppendToOutput("#%c0x%" PRIx64, sign, offset);
+ AppendPCRelativeOffsetToOutput(instr, offset);
return 6;
}
case 'A': { // IAddSub.
@@ -1458,6 +1582,10 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
AppendToOutput("#0x%" PRIx64, instr->ImmException());
return 6;
}
+ case 'X': { // IX - CLREX instruction.
+ AppendToOutput("#0x%" PRIx64, instr->CRm());
+ return 2;
+ }
default: {
VIXL_UNIMPLEMENTED();
return 0;
@@ -1466,7 +1594,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
}
-int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
+int Disassembler::SubstituteBitfieldImmediateField(const Instruction* instr,
const char* format) {
VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B'));
unsigned r = instr->ImmR();
@@ -1501,7 +1629,7 @@ int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
}
-int Disassembler::SubstituteLiteralField(Instruction* instr,
+int Disassembler::SubstituteLiteralField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);
USE(format);
@@ -1509,16 +1637,21 @@ int Disassembler::SubstituteLiteralField(Instruction* instr,
switch (instr->Mask(LoadLiteralMask)) {
case LDR_w_lit:
case LDR_x_lit:
+ case LDRSW_x_lit:
case LDR_s_lit:
- case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break;
- default: VIXL_UNREACHABLE();
+ case LDR_d_lit:
+ AppendDataAddressToOutput(instr, instr->LiteralAddress());
+ break;
+ default:
+ VIXL_UNREACHABLE();
}
return 6;
}
-int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
+int Disassembler::SubstituteShiftField(const Instruction* instr,
+ const char* format) {
VIXL_ASSERT(format[0] == 'H');
VIXL_ASSERT(instr->ShiftDP() <= 0x3);
@@ -1541,7 +1674,7 @@ int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
}
-int Disassembler::SubstituteConditionField(Instruction* instr,
+int Disassembler::SubstituteConditionField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(format[0] == 'C');
const char* condition_code[] = { "eq", "ne", "hs", "lo",
@@ -1562,28 +1695,28 @@ int Disassembler::SubstituteConditionField(Instruction* instr,
}
-int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
+int Disassembler::SubstitutePCRelAddressField(const Instruction* instr,
const char* format) {
- USE(format);
- VIXL_ASSERT(strncmp(format, "AddrPCRel", 9) == 0);
-
- int offset = instr->ImmPCRel();
+ VIXL_ASSERT((strcmp(format, "AddrPCRelByte") == 0) || // Used by `adr`.
+ (strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`.
- // Only ADR (AddrPCRelByte) is supported.
- VIXL_ASSERT(strcmp(format, "AddrPCRelByte") == 0);
+ int64_t offset = instr->ImmPCRel();
+ const Instruction * base = instr;
- char sign = '+';
- if (offset < 0) {
- offset = -offset;
- sign = '-';
+ if (format[9] == 'P') {
+ offset *= kPageSize;
+ base = AlignDown(base, kPageSize);
}
- VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
- AppendToOutput("#%c0x%x (addr %p)", sign, offset, instr + offset);
+
+ const void* target = reinterpret_cast<const void*>(base + offset);
+ AppendPCRelativeOffsetToOutput(instr, offset);
+ AppendToOutput(" ");
+ AppendAddressToOutput(instr, target);
return 13;
}
-int Disassembler::SubstituteBranchTargetField(Instruction* instr,
+int Disassembler::SubstituteBranchTargetField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(strncmp(format, "BImm", 4) == 0);
@@ -1600,18 +1733,18 @@ int Disassembler::SubstituteBranchTargetField(Instruction* instr,
default: VIXL_UNIMPLEMENTED();
}
offset <<= kInstructionSizeLog2;
- char sign = '+';
- if (offset < 0) {
- offset = -offset;
- sign = '-';
- }
+ const void* target_address = reinterpret_cast<const void*>(instr + offset);
VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
- AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, offset, instr + offset);
+
+ AppendPCRelativeOffsetToOutput(instr, offset);
+ AppendToOutput(" ");
+ AppendCodeAddressToOutput(instr, target_address);
+
return 8;
}
-int Disassembler::SubstituteExtendField(Instruction* instr,
+int Disassembler::SubstituteExtendField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(strncmp(format, "Ext", 3) == 0);
VIXL_ASSERT(instr->ExtendMode() <= 7);
@@ -1638,7 +1771,7 @@ int Disassembler::SubstituteExtendField(Instruction* instr,
}
-int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
+int Disassembler::SubstituteLSRegOffsetField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0);
const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
@@ -1667,7 +1800,7 @@ int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
}
-int Disassembler::SubstitutePrefetchField(Instruction* instr,
+int Disassembler::SubstitutePrefetchField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(format[0] == 'P');
USE(format);
@@ -1682,7 +1815,7 @@ int Disassembler::SubstitutePrefetchField(Instruction* instr,
return 6;
}
-int Disassembler::SubstituteBarrierField(Instruction* instr,
+int Disassembler::SubstituteBarrierField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(format[0] == 'M');
USE(format);
@@ -1714,7 +1847,7 @@ void Disassembler::AppendToOutput(const char* format, ...) {
}
-void PrintDisassembler::ProcessOutput(Instruction* instr) {
+void PrintDisassembler::ProcessOutput(const Instruction* instr) {
fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
reinterpret_cast<uint64_t>(instr),
instr->InstructionBits(),
diff --git a/disas/libvixl/a64/disasm-a64.h b/disas/libvixl/a64/disasm-a64.h
index 3a56e1551..db043375c 100644
--- a/disas/libvixl/a64/disasm-a64.h
+++ b/disas/libvixl/a64/disasm-a64.h
@@ -31,6 +31,7 @@
#include "utils.h"
#include "instructions-a64.h"
#include "decoder-a64.h"
+#include "assembler-a64.h"
namespace vixl {
@@ -42,50 +43,85 @@ class Disassembler: public DecoderVisitor {
char* GetOutput();
// Declare all Visitor functions.
- #define DECLARE(A) void Visit##A(Instruction* instr);
+ #define DECLARE(A) void Visit##A(const Instruction* instr);
VISITOR_LIST(DECLARE)
#undef DECLARE
protected:
- virtual void ProcessOutput(Instruction* instr);
+ virtual void ProcessOutput(const Instruction* instr);
+
+ // Default output functions. The functions below implement a default way of
+ // printing elements in the disassembly. A sub-class can override these to
+ // customize the disassembly output.
+
+ // Prints the name of a register.
+ virtual void AppendRegisterNameToOutput(const Instruction* instr,
+ const CPURegister& reg);
+
+ // Prints a PC-relative offset. This is used for example when disassembling
+ // branches to immediate offsets.
+ virtual void AppendPCRelativeOffsetToOutput(const Instruction* instr,
+ int64_t offset);
+
+ // 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);
+
+ // 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);
+
+ // Prints the address of some data.
+ // This is used for example to print the source address of a load literal
+ // instruction.
+ virtual void AppendDataAddressToOutput(const Instruction* instr,
+ const void* addr);
private:
- void Format(Instruction* instr, const char* mnemonic, const char* format);
- void Substitute(Instruction* instr, const char* string);
- int SubstituteField(Instruction* instr, const char* format);
- int SubstituteRegisterField(Instruction* instr, const char* format);
- int SubstituteImmediateField(Instruction* instr, const char* format);
- int SubstituteLiteralField(Instruction* instr, const char* format);
- int SubstituteBitfieldImmediateField(Instruction* instr, const char* format);
- int SubstituteShiftField(Instruction* instr, const char* format);
- int SubstituteExtendField(Instruction* instr, const char* format);
- int SubstituteConditionField(Instruction* instr, const char* format);
- int SubstitutePCRelAddressField(Instruction* instr, const char* format);
- int SubstituteBranchTargetField(Instruction* instr, const char* format);
- int SubstituteLSRegOffsetField(Instruction* instr, const char* format);
- int SubstitutePrefetchField(Instruction* instr, const char* format);
- int SubstituteBarrierField(Instruction* instr, const char* format);
-
- inline bool RdIsZROrSP(Instruction* instr) const {
+ void Format(
+ const Instruction* instr, const char* mnemonic, const char* format);
+ void Substitute(const Instruction* instr, const char* string);
+ int SubstituteField(const Instruction* instr, const char* format);
+ int SubstituteRegisterField(const Instruction* instr, const char* format);
+ int SubstituteImmediateField(const Instruction* instr, const char* format);
+ int SubstituteLiteralField(const Instruction* instr, const char* format);
+ int SubstituteBitfieldImmediateField(
+ const Instruction* instr, const char* format);
+ int SubstituteShiftField(const Instruction* instr, const char* format);
+ int SubstituteExtendField(const Instruction* instr, const char* format);
+ int SubstituteConditionField(const Instruction* instr, const char* format);
+ int SubstitutePCRelAddressField(const Instruction* instr, const char* format);
+ int SubstituteBranchTargetField(const Instruction* instr, const char* format);
+ int SubstituteLSRegOffsetField(const Instruction* instr, const char* format);
+ int SubstitutePrefetchField(const Instruction* instr, const char* format);
+ int SubstituteBarrierField(const Instruction* instr, const char* format);
+
+ inline bool RdIsZROrSP(const Instruction* instr) const {
return (instr->Rd() == kZeroRegCode);
}
- inline bool RnIsZROrSP(Instruction* instr) const {
+ inline bool RnIsZROrSP(const Instruction* instr) const {
return (instr->Rn() == kZeroRegCode);
}
- inline bool RmIsZROrSP(Instruction* instr) const {
+ inline bool RmIsZROrSP(const Instruction* instr) const {
return (instr->Rm() == kZeroRegCode);
}
- inline bool RaIsZROrSP(Instruction* instr) const {
+ inline bool RaIsZROrSP(const Instruction* instr) const {
return (instr->Ra() == kZeroRegCode);
}
bool IsMovzMovnImm(unsigned reg_size, uint64_t value);
+ protected:
void ResetOutput();
- void AppendToOutput(const char* string, ...);
+ void AppendToOutput(const char* string, ...) PRINTF_CHECK(2, 3);
char* buffer_;
uint32_t buffer_pos_;
@@ -97,10 +133,10 @@ class Disassembler: public DecoderVisitor {
class PrintDisassembler: public Disassembler {
public:
explicit PrintDisassembler(FILE* stream) : stream_(stream) { }
- ~PrintDisassembler() { }
+ virtual ~PrintDisassembler() { }
protected:
- virtual void ProcessOutput(Instruction* instr);
+ virtual void ProcessOutput(const Instruction* instr);
private:
FILE *stream_;
diff --git a/disas/libvixl/a64/instructions-a64.cc b/disas/libvixl/a64/instructions-a64.cc
index c4eb7c451..1f08c781e 100644
--- a/disas/libvixl/a64/instructions-a64.cc
+++ b/disas/libvixl/a64/instructions-a64.cc
@@ -57,7 +57,7 @@ static uint64_t RepeatBitsAcrossReg(unsigned reg_size,
// 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.
-uint64_t Instruction::ImmLogical() {
+uint64_t Instruction::ImmLogical() const {
unsigned reg_size = SixtyFourBits() ? kXRegSize : kWRegSize;
int64_t n = BitN();
int64_t imm_s = ImmSetBits();
@@ -108,7 +108,7 @@ uint64_t Instruction::ImmLogical() {
}
-float Instruction::ImmFP32() {
+float Instruction::ImmFP32() const {
// ImmFP: abcdefgh (8 bits)
// Single: aBbb.bbbc.defg.h000.0000.0000.0000.0000 (32 bits)
// where B is b ^ 1
@@ -122,7 +122,7 @@ float Instruction::ImmFP32() {
}
-double Instruction::ImmFP64() {
+double Instruction::ImmFP64() const {
// ImmFP: abcdefgh (8 bits)
// Double: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
// 0000.0000.0000.0000.0000.0000.0000.0000 (64 bits)
@@ -148,18 +148,25 @@ LSDataSize CalcLSPairDataSize(LoadStorePairOp op) {
}
-Instruction* Instruction::ImmPCOffsetTarget() {
+const Instruction* Instruction::ImmPCOffsetTarget() const {
+ const Instruction * base = this;
ptrdiff_t offset;
if (IsPCRelAddressing()) {
- // PC-relative addressing. Only ADR is supported.
+ // ADR and ADRP.
offset = ImmPCRel();
+ if (Mask(PCRelAddressingMask) == ADRP) {
+ base = AlignDown(base, kPageSize);
+ offset *= kPageSize;
+ } else {
+ VIXL_ASSERT(Mask(PCRelAddressingMask) == ADR);
+ }
} else {
// All PC-relative branches.
VIXL_ASSERT(BranchType() != UnknownBranchType);
// Relative branch offsets are instruction-size-aligned.
offset = ImmBranch() << kInstructionSizeLog2;
}
- return this + offset;
+ return base + offset;
}
@@ -175,7 +182,7 @@ inline int Instruction::ImmBranch() const {
}
-void Instruction::SetImmPCOffsetTarget(Instruction* target) {
+void Instruction::SetImmPCOffsetTarget(const Instruction* target) {
if (IsPCRelAddressing()) {
SetPCRelImmTarget(target);
} else {
@@ -184,17 +191,23 @@ void Instruction::SetImmPCOffsetTarget(Instruction* target) {
}
-void Instruction::SetPCRelImmTarget(Instruction* target) {
- // ADRP is not supported, so 'this' must point to an ADR instruction.
- VIXL_ASSERT(Mask(PCRelAddressingMask) == ADR);
-
- Instr imm = Assembler::ImmPCRelAddress(target - this);
+void Instruction::SetPCRelImmTarget(const Instruction* target) {
+ int32_t imm21;
+ if ((Mask(PCRelAddressingMask) == ADR)) {
+ imm21 = target - this;
+ } else {
+ VIXL_ASSERT(Mask(PCRelAddressingMask) == ADRP);
+ uintptr_t this_page = reinterpret_cast<uintptr_t>(this) / kPageSize;
+ uintptr_t target_page = reinterpret_cast<uintptr_t>(target) / kPageSize;
+ imm21 = target_page - this_page;
+ }
+ Instr imm = Assembler::ImmPCRelAddress(imm21);
SetInstructionBits(Mask(~ImmPCRel_mask) | imm);
}
-void Instruction::SetBranchImmTarget(Instruction* target) {
+void Instruction::SetBranchImmTarget(const Instruction* target) {
VIXL_ASSERT(((target - this) & 3) == 0);
Instr branch_imm = 0;
uint32_t imm_mask = 0;
@@ -226,9 +239,9 @@ void Instruction::SetBranchImmTarget(Instruction* target) {
}
-void Instruction::SetImmLLiteral(Instruction* source) {
- VIXL_ASSERT(((source - this) & 3) == 0);
- int offset = (source - this) >> kLiteralEntrySizeLog2;
+void Instruction::SetImmLLiteral(const Instruction* source) {
+ VIXL_ASSERT(IsWordAligned(source));
+ ptrdiff_t offset = (source - this) >> kLiteralEntrySizeLog2;
Instr imm = Assembler::ImmLLiteral(offset);
Instr mask = ImmLLiteral_mask;
diff --git a/disas/libvixl/a64/instructions-a64.h b/disas/libvixl/a64/instructions-a64.h
index a4240d7d3..29f972291 100644
--- a/disas/libvixl/a64/instructions-a64.h
+++ b/disas/libvixl/a64/instructions-a64.h
@@ -41,6 +41,11 @@ const unsigned kLiteralEntrySize = 4;
const unsigned kLiteralEntrySizeLog2 = 2;
const unsigned kMaxLoadLiteralRange = 1 * MBytes;
+// This is the nominal page size (as used by the adrp instruction); the actual
+// size of the memory pages allocated by the kernel is likely to differ.
+const unsigned kPageSize = 4 * KBytes;
+const unsigned kPageSizeLog2 = 12;
+
const unsigned kWRegSize = 32;
const unsigned kWRegSizeLog2 = 5;
const unsigned kWRegSizeInBytes = kWRegSize / 8;
@@ -79,36 +84,18 @@ const unsigned kZeroRegCode = 31;
const unsigned kSPRegInternalCode = 63;
const unsigned kRegCodeMask = 0x1f;
+const unsigned kAddressTagOffset = 56;
+const unsigned kAddressTagWidth = 8;
+const uint64_t kAddressTagMask =
+ ((UINT64_C(1) << kAddressTagWidth) - 1) << kAddressTagOffset;
+VIXL_STATIC_ASSERT(kAddressTagMask == UINT64_C(0xff00000000000000));
+
// AArch64 floating-point specifics. These match IEEE-754.
const unsigned kDoubleMantissaBits = 52;
const unsigned kDoubleExponentBits = 11;
const unsigned kFloatMantissaBits = 23;
const unsigned kFloatExponentBits = 8;
-const 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));
-
-// This value is a signalling NaN as both a double and as a float (taking the
-// least-significant word).
-static const double kFP64SignallingNaN =
- rawbits_to_double(UINT64_C(0x7ff000007f800001));
-static const float kFP32SignallingNaN = rawbits_to_float(0x7f800001);
-
-// A similar value, but as a quiet NaN.
-static const double kFP64QuietNaN =
- rawbits_to_double(UINT64_C(0x7ff800007fc00001));
-static const float kFP32QuietNaN = rawbits_to_float(0x7fc00001);
-
-// The default NaN values (for FPCR.DN=1).
-static const double kFP64DefaultNaN =
- rawbits_to_double(UINT64_C(0x7ff8000000000000));
-static const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000);
-
-
enum LSDataSize {
LSByte = 0,
LSHalfword = 1,
@@ -191,9 +178,9 @@ class Instruction {
return signed_bitextract_32(width-1, 0, offset);
}
- uint64_t ImmLogical();
- float ImmFP32();
- double ImmFP64();
+ uint64_t ImmLogical() const;
+ float ImmFP32() const;
+ double ImmFP64() const;
inline LSDataSize SizeLSPair() const {
return CalcLSPairDataSize(
@@ -301,46 +288,49 @@ class Instruction {
// Find the target of this instruction. 'this' may be a branch or a
// PC-relative addressing instruction.
- Instruction* ImmPCOffsetTarget();
+ const Instruction* ImmPCOffsetTarget() const;
// Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
// a PC-relative addressing instruction.
- void SetImmPCOffsetTarget(Instruction* target);
+ void SetImmPCOffsetTarget(const Instruction* target);
// Patch a literal load instruction to load from 'source'.
- void SetImmLLiteral(Instruction* source);
+ void SetImmLLiteral(const Instruction* source);
- inline uint8_t* LiteralAddress() {
+ inline uint8_t* LiteralAddress() const {
int offset = ImmLLiteral() << kLiteralEntrySizeLog2;
- return reinterpret_cast<uint8_t*>(this) + offset;
+ 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);
}
- inline uint32_t Literal32() {
+ inline uint32_t Literal32() const {
uint32_t literal;
memcpy(&literal, LiteralAddress(), sizeof(literal));
return literal;
}
- inline uint64_t Literal64() {
+ inline uint64_t Literal64() const {
uint64_t literal;
memcpy(&literal, LiteralAddress(), sizeof(literal));
return literal;
}
- inline float LiteralFP32() {
+ inline float LiteralFP32() const {
return rawbits_to_float(Literal32());
}
- inline double LiteralFP64() {
+ inline double LiteralFP64() const {
return rawbits_to_double(Literal64());
}
- inline Instruction* NextInstruction() {
+ inline const Instruction* NextInstruction() const {
return this + kInstructionSize;
}
- inline Instruction* InstructionAtOffset(int64_t offset) {
+ inline const Instruction* InstructionAtOffset(int64_t offset) const {
VIXL_ASSERT(IsWordAligned(this + offset));
return this + offset;
}
@@ -349,11 +339,15 @@ class Instruction {
return reinterpret_cast<Instruction*>(src);
}
+ template<typename T> static inline const Instruction* CastConst(T src) {
+ return reinterpret_cast<const Instruction*>(src);
+ }
+
private:
inline int ImmBranch() const;
- void SetPCRelImmTarget(Instruction* target);
- void SetBranchImmTarget(Instruction* target);
+ void SetPCRelImmTarget(const Instruction* target);
+ void SetBranchImmTarget(const Instruction* target);
};
} // namespace vixl
diff --git a/disas/libvixl/code-buffer.h b/disas/libvixl/code-buffer.h
new file mode 100644
index 000000000..da6233dd8
--- /dev/null
+++ b/disas/libvixl/code-buffer.h
@@ -0,0 +1,113 @@
+// Copyright 2014, ARM Limited
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of ARM Limited nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef VIXL_CODE_BUFFER_H
+#define VIXL_CODE_BUFFER_H
+
+#include <string.h>
+#include "globals.h"
+
+namespace vixl {
+
+class CodeBuffer {
+ public:
+ explicit CodeBuffer(size_t capacity = 4 * KBytes);
+ CodeBuffer(void* buffer, size_t capacity);
+ ~CodeBuffer();
+
+ void Reset();
+
+ ptrdiff_t OffsetFrom(ptrdiff_t offset) const {
+ ptrdiff_t cursor_offset = cursor_ - buffer_;
+ VIXL_ASSERT((offset >= 0) && (offset <= cursor_offset));
+ return cursor_offset - offset;
+ }
+
+ ptrdiff_t CursorOffset() const {
+ return OffsetFrom(0);
+ }
+
+ template <typename T>
+ T GetOffsetAddress(ptrdiff_t offset) const {
+ VIXL_ASSERT((offset >= 0) && (offset <= (cursor_ - buffer_)));
+ return reinterpret_cast<T>(buffer_ + offset);
+ }
+
+ size_t RemainingBytes() const {
+ VIXL_ASSERT((cursor_ >= buffer_) && (cursor_ <= (buffer_ + capacity_)));
+ return (buffer_ + capacity_) - cursor_;
+ }
+
+ // A code buffer can emit:
+ // * 32-bit data: instruction and constant.
+ // * 64-bit data: constant.
+ // * string: debug info.
+ void Emit32(uint32_t data) { Emit(data); }
+
+ void Emit64(uint64_t data) { Emit(data); }
+
+ void EmitString(const char* string);
+
+ // Align to kInstructionSize.
+ void Align();
+
+ size_t capacity() const { return capacity_; }
+
+ bool IsManaged() const { return managed_; }
+
+ void Grow(size_t new_capacity);
+
+ bool IsDirty() const { return dirty_; }
+
+ void SetClean() { dirty_ = false; }
+
+ private:
+ template <typename T>
+ void Emit(T value) {
+ VIXL_ASSERT(RemainingBytes() >= sizeof(value));
+ dirty_ = true;
+ memcpy(cursor_, &value, sizeof(value));
+ cursor_ += sizeof(value);
+ }
+
+ // Backing store of the buffer.
+ byte* buffer_;
+ // If true the backing store is allocated and deallocated by the buffer. The
+ // backing store can then grow on demand. If false the backing store is
+ // provided by the user and cannot be resized internally.
+ bool managed_;
+ // Pointer to the next location to be written.
+ byte* cursor_;
+ // True if there has been any write since the buffer was created or cleaned.
+ bool dirty_;
+ // Capacity in bytes of the backing store.
+ size_t capacity_;
+};
+
+} // namespace vixl
+
+#endif // VIXL_CODE_BUFFER_H
+
diff --git a/disas/libvixl/platform.h b/disas/libvixl/platform.h
index b5c2085b9..de2b110cc 100644
--- a/disas/libvixl/platform.h
+++ b/disas/libvixl/platform.h
@@ -28,14 +28,10 @@
#define PLATFORM_H
// Define platform specific functionalities.
+#include <signal.h>
namespace vixl {
-#ifdef USE_SIMULATOR
-// Currently we assume running the simulator implies running on x86 hardware.
-inline void HostBreakpoint() { asm("int3"); }
-#else
-inline void HostBreakpoint() { asm("brk"); }
-#endif
+inline void HostBreakpoint() { raise(SIGINT); }
} // namespace vixl
#endif
diff --git a/disas/libvixl/utils.cc b/disas/libvixl/utils.cc
index c9c05d1e1..21965d7a1 100644
--- a/disas/libvixl/utils.cc
+++ b/disas/libvixl/utils.cc
@@ -124,4 +124,15 @@ int CountSetBits(uint64_t value, int width) {
return value;
}
+
+
+uint64_t LowestSetBit(uint64_t value) {
+ return value & -value;
+}
+
+
+bool IsPowerOf2(int64_t value) {
+ return (value != 0) && ((value & (value - 1)) == 0);
+}
+
} // namespace vixl
diff --git a/disas/libvixl/utils.h b/disas/libvixl/utils.h
index 83c928c8e..1540c3060 100644
--- a/disas/libvixl/utils.h
+++ b/disas/libvixl/utils.h
@@ -33,6 +33,14 @@
namespace vixl {
+// Macros for compile-time format checking.
+#if defined(__GNUC__)
+#define PRINTF_CHECK(format_index, varargs_index) \
+ __attribute__((format(printf, format_index, varargs_index)))
+#else
+#define PRINTF_CHECK(format_index, varargs_index)
+#endif
+
// Check number width.
inline bool is_intn(unsigned n, int64_t x) {
VIXL_ASSERT((0 < n) && (n < 64));
@@ -155,35 +163,46 @@ int CountLeadingZeros(uint64_t value, int width);
int CountLeadingSignBits(int64_t value, int width);
int CountTrailingZeros(uint64_t value, int width);
int CountSetBits(uint64_t value, int width);
+uint64_t LowestSetBit(uint64_t value);
+bool IsPowerOf2(int64_t value);
// Pointer alignment
// TODO: rename/refactor to make it specific to instructions.
template<typename T>
bool IsWordAligned(T pointer) {
VIXL_ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof)
- return (reinterpret_cast<intptr_t>(pointer) & 3) == 0;
+ return ((intptr_t)(pointer) & 3) == 0;
}
// Increment a pointer until it has the specified alignment.
template<class T>
T AlignUp(T pointer, size_t alignment) {
- VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(uintptr_t));
- uintptr_t pointer_raw = reinterpret_cast<uintptr_t>(pointer);
+ // 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));
+
size_t align_step = (alignment - pointer_raw) % alignment;
VIXL_ASSERT((pointer_raw + align_step) % alignment == 0);
- return reinterpret_cast<T>(pointer_raw + align_step);
+
+ return (T)(pointer_raw + align_step);
}
// Decrement a pointer until it has the specified alignment.
template<class T>
T AlignDown(T pointer, size_t alignment) {
- VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(uintptr_t));
- uintptr_t pointer_raw = reinterpret_cast<uintptr_t>(pointer);
+ // 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));
+
size_t align_step = pointer_raw % alignment;
VIXL_ASSERT((pointer_raw - align_step) % alignment == 0);
- return reinterpret_cast<T>(pointer_raw - align_step);
-}
+ return (T)(pointer_raw - align_step);
+}
} // namespace vixl