diff options
-rw-r--r-- | disas/arm-a64.cc | 2 | ||||
-rw-r--r-- | disas/libvixl/README | 2 | ||||
-rw-r--r-- | disas/libvixl/a64/assembler-a64.h | 385 | ||||
-rw-r--r-- | disas/libvixl/a64/decoder-a64.cc | 34 | ||||
-rw-r--r-- | disas/libvixl/a64/decoder-a64.h | 102 | ||||
-rw-r--r-- | disas/libvixl/a64/disasm-a64.cc | 259 | ||||
-rw-r--r-- | disas/libvixl/a64/disasm-a64.h | 84 | ||||
-rw-r--r-- | disas/libvixl/a64/instructions-a64.cc | 22 | ||||
-rw-r--r-- | disas/libvixl/a64/instructions-a64.h | 40 | ||||
-rw-r--r-- | disas/libvixl/code-buffer.h | 113 | ||||
-rw-r--r-- | disas/libvixl/utils.cc | 1 | ||||
-rw-r--r-- | disas/libvixl/utils.h | 3 |
12 files changed, 715 insertions, 332 deletions
diff --git a/disas/arm-a64.cc b/disas/arm-a64.cc index 162be0c..ca29f6f 100644 --- a/disas/arm-a64.cc +++ b/disas/arm-a64.cc @@ -39,7 +39,7 @@ public: ~QEMUDisassembler() { } protected: - void ProcessOutput(Instruction *instr) { + virtual void ProcessOutput(const Instruction *instr) { fprintf(stream_, "%08" PRIx32 " %s", instr->InstructionBits(), GetOutput()); } diff --git a/disas/libvixl/README b/disas/libvixl/README index 8301996..cba31b4 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.5). +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 cc0b758..16a704b 100644 --- a/disas/libvixl/a64/assembler-a64.h +++ b/disas/libvixl/a64/assembler-a64.h @@ -32,6 +32,7 @@ #include "globals.h" #include "utils.h" +#include "code-buffer.h" #include "a64/instructions-a64.h" namespace vixl { @@ -168,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; @@ -191,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 { @@ -536,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, @@ -552,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_; } @@ -565,7 +571,7 @@ class MemOperand { private: Register base_; Register regoffset_; - ptrdiff_t offset_; + int64_t offset_; AddrMode addrmode_; Shift shift_; Extend extend_; @@ -680,32 +686,80 @@ class Label { }; -// 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; } -// 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 -}; + 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_; -// Literal pool entry. -class Literal { - public: - Literal(Instruction* pc, uint64_t imm, unsigned size) - : pc_(pc), value_(imm), size_(size) {} + friend class Assembler; +}; - private: - Instruction* pc_; - int64_t value_; - unsigned size_; - friend class Assembler; +template <typename T> +class Literal : public RawLiteral { + public: + explicit Literal(T value) { + size_ = sizeof(value); + memcpy(&raw_value_, &value, sizeof(value)); + } }; @@ -750,7 +804,9 @@ enum LoadStoreScalingOption { // 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: @@ -763,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 @@ -776,13 +829,47 @@ class Assembler { // Bind a label to the current PC. void bind(Label* label); + // 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)); - VIXL_STATIC_ASSERT(sizeof(*buffer_) == 1); - return reinterpret_cast<T>(buffer_ + label->location()); + 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. @@ -1324,14 +1411,17 @@ 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 single precision floating point literal to FP register. - void ldr(const FPRegister& ft, float imm); + // 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); @@ -1618,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. @@ -1912,43 +2003,39 @@ class Assembler { return scale << FPScale_offset; } - // Size of the code generated in bytes - size_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. size_t SizeOfCodeGeneratedSince(Label* label) const { - size_t pc_offset = SizeOfCodeGenerated(); - VIXL_ASSERT(label->IsBound()); - VIXL_ASSERT(pc_offset >= static_cast<size_t>(label->location())); - VIXL_ASSERT(pc_offset < buffer_size_); - - return pc_offset - label->location(); + 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 inline PositionIndependentCodeOption pic() { return pic_; @@ -1959,22 +2046,30 @@ class Assembler { (pic() == PositionDependentCode); } - protected: - inline const Register& AppropriateZeroRegFor(const CPURegister& reg) const { + static inline const Register& AppropriateZeroRegFor(const CPURegister& reg) { return reg.Is64Bits() ? xzr : wzr; } + protected: void LoadStore(const CPURegister& rt, const MemOperand& addr, LoadStoreOp op, LoadStoreScalingOption option = PreferScaledOffset); - static bool IsImmLSUnscaled(ptrdiff_t offset); - static bool IsImmLSScaled(ptrdiff_t offset, LSDataSize size); + 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, @@ -2035,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: @@ -2053,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, @@ -2088,8 +2180,6 @@ 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. @@ -2098,79 +2188,102 @@ class Assembler { ptrdiff_t LinkAndGetPageOffsetTo(Label * label); // A common implementation for the LinkAndGet<Type>OffsetTo helpers. - template <int element_size> + template <int element_shift> ptrdiff_t LinkAndGetOffsetTo(Label* label); - // Emit the instruction at pc_. + // Literal load offset are in words (32-bit). + ptrdiff_t LinkAndGetWordOffsetTo(RawLiteral* literal); + + // Emit the instruction in buffer_. void Emit(Instr instruction) { - VIXL_STATIC_ASSERT(sizeof(*pc_) == 1); VIXL_STATIC_ASSERT(sizeof(instruction) == kInstructionSize); - VIXL_ASSERT((pc_ + sizeof(instruction)) <= (buffer_ + buffer_size_)); - -#ifdef DEBUG - finalized_ = false; -#endif - - memcpy(pc_, &instruction, sizeof(instruction)); - pc_ += sizeof(instruction); - CheckBufferSpace(); + 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. - size_t buffer_size_; - Instruction* pc_; - std::list<Literal*> literals_; - Instruction* next_literal_pool_check_; - unsigned literal_pool_monitor_; - PositionIndependentCodeOption pic_; +// 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 Label; - 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/decoder-a64.cc b/disas/libvixl/a64/decoder-a64.cc index 5831b73..82591ca 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,7 +165,7 @@ 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) || @@ -270,7 +266,7 @@ 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) || @@ -388,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) { @@ -407,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) || @@ -432,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); @@ -442,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)); @@ -557,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)); @@ -684,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); @@ -699,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 72c1519..172594c 100644 --- a/disas/libvixl/a64/decoder-a64.h +++ b/disas/libvixl/a64/decoder-a64.h @@ -88,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 248ebfd..e4a74aa 100644 --- a/disas/libvixl/a64/disasm-a64.cc +++ b/disas/libvixl/a64/disasm-a64.cc @@ -57,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; @@ -102,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 = ""; @@ -149,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()); @@ -187,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"; @@ -222,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 = ""; @@ -294,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 = ""; @@ -345,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"; @@ -360,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"; @@ -375,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 = ""; @@ -428,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 = @@ -506,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"; @@ -527,7 +527,7 @@ 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; case ADRP: Format(instr, "adrp", "'Xd, 'AddrPCRelPage"); break; @@ -536,7 +536,7 @@ void Disassembler::VisitPCRelAddressing(Instruction* instr) { } -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(); @@ -544,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"; @@ -564,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"; @@ -577,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"; @@ -598,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"; @@ -619,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"; @@ -697,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"; @@ -712,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 @@ -729,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"; @@ -768,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)"; @@ -782,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)"; @@ -796,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)"; @@ -811,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)"; @@ -826,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]"; @@ -857,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)"; @@ -866,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); @@ -883,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)"; @@ -897,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)"; @@ -911,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)"; @@ -925,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; @@ -944,7 +950,7 @@ void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) { } -void Disassembler::VisitLoadStoreExclusive(Instruction* instr) { +void Disassembler::VisitLoadStoreExclusive(const Instruction* instr) { const char *mnemonic = "unimplemented"; const char *form; @@ -987,7 +993,7 @@ void Disassembler::VisitLoadStoreExclusive(Instruction* instr) { } -void Disassembler::VisitFPCompare(Instruction* instr) { +void Disassembler::VisitFPCompare(const Instruction* instr) { const char *mnemonic = "unimplemented"; const char *form = "'Fn, 'Fm"; const char *form_zero = "'Fn, #0.0"; @@ -1003,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"; @@ -1018,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"; @@ -1031,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"; @@ -1059,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"; @@ -1083,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"; @@ -1102,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)"; @@ -1115,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"; @@ -1171,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"; @@ -1199,7 +1205,7 @@ 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. @@ -1267,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"; @@ -1286,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(); @@ -1315,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 == '\'') { @@ -1328,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. @@ -1354,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; @@ -1381,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'); @@ -1458,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. @@ -1522,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(); @@ -1557,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); @@ -1565,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); @@ -1597,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", @@ -1618,27 +1695,28 @@ int Disassembler::SubstituteConditionField(Instruction* instr, } -int Disassembler::SubstitutePCRelAddressField(Instruction* instr, +int Disassembler::SubstitutePCRelAddressField(const Instruction* instr, const char* format) { VIXL_ASSERT((strcmp(format, "AddrPCRelByte") == 0) || // Used by `adr`. (strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`. int64_t offset = instr->ImmPCRel(); - Instruction * base = instr; + const Instruction * base = instr; if (format[9] == 'P') { offset *= kPageSize; base = AlignDown(base, kPageSize); } - char sign = (offset < 0) ? '-' : '+'; - void * target = reinterpret_cast<void *>(base + offset); - AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, std::abs(offset), target); + 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); @@ -1655,19 +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); - void * address = reinterpret_cast<void *>(instr + offset); - AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, offset, address); + + 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); @@ -1694,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", @@ -1723,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); @@ -1738,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); @@ -1770,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 06ee43f..db04337 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,48 +43,83 @@ 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, ...) PRINTF_CHECK(2, 3); @@ -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 e9caceb..1f08c78 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,8 +148,8 @@ LSDataSize CalcLSPairDataSize(LoadStorePairOp op) { } -Instruction* Instruction::ImmPCOffsetTarget() { - Instruction * base = this; +const Instruction* Instruction::ImmPCOffsetTarget() const { + const Instruction * base = this; ptrdiff_t offset; if (IsPCRelAddressing()) { // ADR and ADRP. @@ -182,7 +182,7 @@ inline int Instruction::ImmBranch() const { } -void Instruction::SetImmPCOffsetTarget(Instruction* target) { +void Instruction::SetImmPCOffsetTarget(const Instruction* target) { if (IsPCRelAddressing()) { SetPCRelImmTarget(target); } else { @@ -191,7 +191,7 @@ void Instruction::SetImmPCOffsetTarget(Instruction* target) { } -void Instruction::SetPCRelImmTarget(Instruction* target) { +void Instruction::SetPCRelImmTarget(const Instruction* target) { int32_t imm21; if ((Mask(PCRelAddressingMask) == ADR)) { imm21 = target - this; @@ -207,7 +207,7 @@ void Instruction::SetPCRelImmTarget(Instruction* target) { } -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; @@ -239,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 d5b90c5..38f079f 100644 --- a/disas/libvixl/a64/instructions-a64.h +++ b/disas/libvixl/a64/instructions-a64.h @@ -44,6 +44,7 @@ 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; @@ -201,9 +202,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( @@ -311,46 +312,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; } @@ -359,11 +363,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 0000000..da6233d --- /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/utils.cc b/disas/libvixl/utils.cc index 4d4fcbd..21965d7 100644 --- a/disas/libvixl/utils.cc +++ b/disas/libvixl/utils.cc @@ -134,4 +134,5 @@ uint64_t LowestSetBit(uint64_t 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 b472f0e..1540c30 100644 --- a/disas/libvixl/utils.h +++ b/disas/libvixl/utils.h @@ -171,7 +171,7 @@ bool IsPowerOf2(int64_t value); 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. @@ -204,7 +204,6 @@ T AlignDown(T pointer, size_t alignment) { return (T)(pointer_raw - align_step); } - } // namespace vixl #endif // VIXL_UTILS_H |