diff options
author | Chanho Park <chanho61.park@samsung.com> | 2014-12-10 15:42:55 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-12-10 15:42:55 +0900 |
commit | 0d6a2f7e595218b5632ba7005128470e65138951 (patch) | |
tree | 596b09930ef1538e6606450e2d8b88ec2e296a9b /disas | |
parent | 16b1353a36171ae06d63fd309f4772dbfb1da113 (diff) | |
download | qemu-0d6a2f7e595218b5632ba7005128470e65138951.tar.gz qemu-0d6a2f7e595218b5632ba7005128470e65138951.tar.bz2 qemu-0d6a2f7e595218b5632ba7005128470e65138951.zip |
Imported Upstream version 2.2.0upstream/2.2.1upstream/2.2.0
Diffstat (limited to 'disas')
-rw-r--r-- | disas/arm-a64.cc | 2 | ||||
-rw-r--r-- | disas/libvixl/README | 2 | ||||
-rw-r--r-- | disas/libvixl/a64/assembler-a64.h | 710 | ||||
-rw-r--r-- | disas/libvixl/a64/constants-a64.h | 68 | ||||
-rw-r--r-- | disas/libvixl/a64/cpu-a64.h | 27 | ||||
-rw-r--r-- | disas/libvixl/a64/decoder-a64.cc | 49 | ||||
-rw-r--r-- | disas/libvixl/a64/decoder-a64.h | 103 | ||||
-rw-r--r-- | disas/libvixl/a64/disasm-a64.cc | 333 | ||||
-rw-r--r-- | disas/libvixl/a64/disasm-a64.h | 86 | ||||
-rw-r--r-- | disas/libvixl/a64/instructions-a64.cc | 45 | ||||
-rw-r--r-- | disas/libvixl/a64/instructions-a64.h | 74 | ||||
-rw-r--r-- | disas/libvixl/code-buffer.h | 113 | ||||
-rw-r--r-- | disas/libvixl/platform.h | 8 | ||||
-rw-r--r-- | disas/libvixl/utils.cc | 11 | ||||
-rw-r--r-- | disas/libvixl/utils.h | 35 | ||||
-rw-r--r-- | disas/mips.c | 929 | ||||
-rw-r--r-- | disas/sparc.c | 34 |
17 files changed, 2185 insertions, 444 deletions
diff --git a/disas/arm-a64.cc b/disas/arm-a64.cc index 162be0c42..ca29f6f25 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 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 diff --git a/disas/mips.c b/disas/mips.c index 2106b574c..2614c52a4 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -119,6 +119,8 @@ see <http://www.gnu.org/licenses/>. */ #define OP_SH_IMMEDIATE 0 #define OP_MASK_DELTA 0xffff #define OP_SH_DELTA 0 +#define OP_MASK_DELTA_R6 0x1ff +#define OP_SH_DELTA_R6 7 #define OP_MASK_FUNCT 0x3f #define OP_SH_FUNCT 0 #define OP_MASK_SPEC 0x3f @@ -218,6 +220,28 @@ see <http://www.gnu.org/licenses/>. */ #define OP_SH_MTACC_D 13 #define OP_MASK_MTACC_D 0x3 +/* MSA */ +#define OP_MASK_1BIT 0x1 +#define OP_SH_1BIT 16 +#define OP_MASK_2BIT 0x3 +#define OP_SH_2BIT 16 +#define OP_MASK_3BIT 0x7 +#define OP_SH_3BIT 16 +#define OP_MASK_4BIT 0xf +#define OP_SH_4BIT 16 +#define OP_MASK_5BIT 0x1f +#define OP_SH_5BIT 16 +#define OP_MASK_10BIT 0x3ff +#define OP_SH_10BIT 11 +#define OP_MASK_MSACR11 0x1f +#define OP_SH_MSACR11 11 +#define OP_MASK_MSACR6 0x1f +#define OP_SH_MSACR6 6 +#define OP_MASK_GPR 0x1f +#define OP_SH_GPR 6 +#define OP_MASK_1_TO_4 0x3 +#define OP_SH_1_TO_4 6 + #define OP_OP_COP0 0x10 #define OP_OP_COP1 0x11 #define OP_OP_COP2 0x12 @@ -405,6 +429,12 @@ struct mips_opcode "+3" UDI immediate bits 6-20 "+4" UDI immediate bits 6-25 + R6 immediates/displacements : + (adding suffix to 'o' to avoid adding new characters) + "+o" 9 bits immediate/displacement (shift = 7) + "+o1" 18 bits immediate/displacement (shift = 0) + "+o2" 19 bits immediate/displacement (shift = 0) + Other: "()" parens surrounding optional value "," separates operands @@ -502,6 +532,9 @@ struct mips_opcode /* Instruction writes MDMX accumulator. */ #define INSN2_WRITE_MDMX_ACC 0x00000004 +/* Reads the general purpose register in OP_*_RD. */ +#define INSN2_READ_GPR_D 0x00000200 + /* Instruction is actually a macro. It should be ignored by the disassembler, and requires special treatment by the assembler. */ #define INSN_MACRO 0xffffffff @@ -521,6 +554,8 @@ struct mips_opcode #define INSN_ISA64 0x00000040 #define INSN_ISA32R2 0x00000080 #define INSN_ISA64R2 0x00000100 +#define INSN_ISA32R6 0x00000200 +#define INSN_ISA64R6 0x00000400 /* Masks used for MIPS-defined ASEs. */ #define INSN_ASE_MASK 0x0000f000 @@ -557,7 +592,12 @@ struct mips_opcode #define INSN_5500 0x02000000 /* MDMX ASE */ -#define INSN_MDMX 0x04000000 +#define INSN_MDMX 0x00000000 /* Deprecated */ + +/* MIPS MSA Extension */ +#define INSN_MSA 0x04000000 +#define INSN_MSA64 0x04000000 + /* MT ASE */ #define INSN_MT 0x08000000 /* SmartMIPS ASE */ @@ -585,6 +625,8 @@ struct mips_opcode #define ISA_MIPS32R2 (ISA_MIPS32 | INSN_ISA32R2) #define ISA_MIPS64R2 (ISA_MIPS64 | INSN_ISA32R2 | INSN_ISA64R2) +#define ISA_MIPS32R6 (ISA_MIPS32R2 | INSN_ISA32R6) +#define ISA_MIPS64R6 (ISA_MIPS64R2 | INSN_ISA32R6 | INSN_ISA64R6) /* CPU defines, use instead of hardcoding processor number. Keep this in sync with bfd/archures.c in order for machine selection to work. */ @@ -1121,6 +1163,8 @@ extern const int bfd_mips16_num_opcodes; #define I64 INSN_ISA64 #define I33 INSN_ISA32R2 #define I65 INSN_ISA64R2 +#define I32R6 INSN_ISA32R6 +#define I64R6 INSN_ISA64R6 /* MIPS64 MIPS-3D ASE support. */ #define I16 INSN_MIPS16 @@ -1190,6 +1234,17 @@ extern const int bfd_mips16_num_opcodes; /* MIPS MT ASE support. */ #define MT32 INSN_MT +/* MSA */ +#define MSA INSN_MSA +#define MSA64 INSN_MSA64 +#define WR_VD INSN_WRITE_FPR_D /* Reuse INSN_WRITE_FPR_D */ +#define RD_VD WR_VD /* Reuse WR_VD */ +#define RD_VT INSN_READ_FPR_T /* Reuse INSN_READ_FPR_T */ +#define RD_VS INSN_READ_FPR_S /* Reuse INSN_READ_FPR_S */ +#define RD_d INSN2_READ_GPR_D /* Reuse INSN2_READ_GPR_D */ + +#define RD_rd6 0 + /* The order of overloaded instructions matters. Label arguments and register arguments look the same. Instructions that can have either for arguments must apear in the correct order in this table for the @@ -1209,6 +1264,681 @@ const struct mips_opcode mips_builtin_opcodes[] = them first. The assemblers uses a hash table based on the instruction name anyhow. */ /* name, args, match, mask, pinfo, membership */ +{"lwpc", "s,+o2", 0xec080000, 0xfc180000, WR_d, 0, I32R6}, +{"lwupc", "s,+o2", 0xec100000, 0xfc180000, WR_d, 0, I64R6}, +{"ldpc", "s,+o1", 0xec180000, 0xfc1c0000, WR_d, 0, I64R6}, +{"addiupc", "s,+o2", 0xec000000, 0xfc180000, WR_d, 0, I32R6}, +{"auipc", "s,u", 0xec1e0000, 0xfc1f0000, WR_d, 0, I32R6}, +{"aluipc", "s,u", 0xec1f0000, 0xfc1f0000, WR_d, 0, I32R6}, +{"daui", "s,t,u", 0x74000000, 0xfc000000, RD_s|WR_t, 0, I64R6}, +{"dahi", "s,u", 0x04060000, 0xfc1f0000, RD_s, 0, I64R6}, +{"dati", "s,u", 0x041e0000, 0xfc1f0000, RD_s, 0, I64R6}, +{"lsa", "d,s,t", 0x00000005, 0xfc00073f, WR_d|RD_s|RD_t, 0, I32R6}, +{"dlsa", "d,s,t", 0x00000015, 0xfc00073f, WR_d|RD_s|RD_t, 0, I64R6}, +{"clz", "U,s", 0x00000050, 0xfc1f07ff, WR_d|RD_s, 0, I32R6}, +{"clo", "U,s", 0x00000051, 0xfc1f07ff, WR_d|RD_s, 0, I32R6}, +{"dclz", "U,s", 0x00000052, 0xfc1f07ff, WR_d|RD_s, 0, I64R6}, +{"dclo", "U,s", 0x00000053, 0xfc1f07ff, WR_d|RD_s, 0, I64R6}, +{"sdbbp", "B", 0x0000000e, 0xfc00003f, TRAP, 0, I32R6}, +{"mul", "d,s,t", 0x00000098, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"muh", "d,s,t", 0x000000d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"mulu", "d,s,t", 0x00000099, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"muhu", "d,s,t", 0x000000d9, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"div", "d,s,t", 0x0000009a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"mod", "d,s,t", 0x000000da, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"divu", "d,s,t", 0x0000009b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"modu", "d,s,t", 0x000000db, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"dmul", "d,s,t", 0x0000009c, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"dmuh", "d,s,t", 0x000000dc, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"dmulu", "d,s,t", 0x0000009d, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"dmuhu", "d,s,t", 0x000000dd, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"ddiv", "d,s,t", 0x0000009e, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"dmod", "d,s,t", 0x000000de, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"ddivu", "d,s,t", 0x0000009f, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"dmodu", "d,s,t", 0x000000df, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6}, +{"ll", "t,o(b)", 0x7c000036, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6}, +{"sc", "t,o(b)", 0x7c000026, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6}, +{"lld", "t,o(b)", 0x7c000037, 0xfc00007f, LDD|RD_b|WR_t, 0, I64R6}, +{"scd", "t,o(b)", 0x7c000027, 0xfc00007f, LDD|RD_b|WR_t, 0, I64R6}, +{"pref", "h,o(b)", 0x7c000035, 0xfc00007f, RD_b, 0, I32R6}, +{"cache", "k,o(b)", 0x7c000025, 0xfc00007f, RD_b, 0, I32R6}, +{"seleqz", "d,v,t", 0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"selnez", "d,v,t", 0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"maddf.s", "D,S,T", 0x46000018, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"maddf.d", "D,S,T", 0x46200018, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"msubf.s", "D,S,T", 0x46000019, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"msubf.d", "D,S,T", 0x46200019, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"max.s", "D,S,T", 0x4600001e, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"max.d", "D,S,T", 0x4620001e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"maxa.s", "D,S,T", 0x4600001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"maxa.d", "D,S,T", 0x4620001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"rint.s", "D,S", 0x4600001a, 0xffff003f, WR_D|RD_S|FP_S, 0, I32R6}, +{"rint.d", "D,S", 0x4620001a, 0xffff003f, WR_D|RD_S|FP_D, 0, I32R6}, +{"class.s", "D,S", 0x4600001b, 0xffff003f, WR_D|RD_S|FP_S, 0, I32R6}, +{"class.d", "D,S", 0x4620001b, 0xffff003f, WR_D|RD_S|FP_D, 0, I32R6}, +{"min.s", "D,S,T", 0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"min.d", "D,S,T", 0x4620001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"mina.s", "D,S,T", 0x4600001d, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"mina.d", "D,S,T", 0x4620001d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"sel.s", "D,S,T", 0x46000010, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"sel.d", "D,S,T", 0x46200010, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"seleqz.s", "D,S,T", 0x46000014, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"seleqz.d", "D,S,T", 0x46200014, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"selnez.s", "D,S,T", 0x46000017, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"selnez.d", "D,S,T", 0x46200017, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"align", "d,v,t", 0x7c000220, 0xfc00073f, WR_d|RD_s|RD_t, 0, I32R6}, +{"dalign", "d,v,t", 0x7c000224, 0xfc00063f, WR_d|RD_s|RD_t, 0, I64R6}, +{"bitswap", "d,w", 0x7c000020, 0xffe007ff, WR_d|RD_t, 0, I32R6}, +{"dbitswap","d,w", 0x7c000024, 0xffe007ff, WR_d|RD_t, 0, I64R6}, +{"balc", "+p", 0xe8000000, 0xfc000000, UBD|WR_31, 0, I32R6}, +{"bc", "+p", 0xc8000000, 0xfc000000, UBD|WR_31, 0, I32R6}, +{"jic", "t,o", 0xd8000000, 0xffe00000, UBD|RD_t, 0, I32R6}, +{"beqzc", "s,+p", 0xd8000000, 0xfc000000, CBD|RD_s, 0, I32R6}, +{"jialc", "t,o", 0xf8000000, 0xffe00000, UBD|RD_t, 0, I32R6}, +{"bnezc", "s,+p", 0xf8000000, 0xfc000000, CBD|RD_s, 0, I32R6}, +{"beqzalc", "s,t,p", 0x20000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, +{"bovc", "s,t,p", 0x20000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"beqc", "s,t,p", 0x20000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bnezalc", "s,t,p", 0x60000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, +{"bnvc", "s,t,p", 0x60000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bnec", "s,t,p", 0x60000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"blezc", "s,t,p", 0x58000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, +{"bgezc", "s,t,p", 0x58000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bgec", "s,t,p", 0x58000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bgtzc", "s,t,p", 0x5c000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, +{"bltzc", "s,t,p", 0x5c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bltc", "s,t,p", 0x5c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"blezalc", "s,t,p", 0x18000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, +{"bgezalc", "s,t,p", 0x18000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bgeuc", "s,t,p", 0x18000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bgtzalc", "s,t,p", 0x1c000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6}, +{"bltzalc", "s,t,p", 0x1c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"bltuc", "s,t,p", 0x1c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6}, +{"nal", "p", 0x04100000, 0xffff0000, WR_31, 0, I32R6}, +{"bal", "p", 0x04110000, 0xffff0000, UBD|WR_31, 0, I32R6}, +{"bc1eqz", "T,p", 0x45200000, 0xffe00000, CBD|RD_T|FP_S|FP_D, 0, I32R6}, +{"bc1nez", "T,p", 0x45a00000, 0xffe00000, CBD|RD_T|FP_S|FP_D, 0, I32R6}, +{"bc2eqz", "E,p", 0x49200000, 0xffe00000, CBD|RD_C2, 0, I32R6}, +{"bc2nez", "E,p", 0x49a00000, 0xffe00000, CBD|RD_C2, 0, I32R6}, +{"cmp.af.s", "D,S,T", 0x46800000, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.un.s", "D,S,T", 0x46800001, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.eq.s", "D,S,T", 0x46800002, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.ueq.s", "D,S,T", 0x46800003, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.lt.s", "D,S,T", 0x46800004, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.ult.s", "D,S,T", 0x46800005, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.le.s", "D,S,T", 0x46800006, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.ule.s", "D,S,T", 0x46800007, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.saf.s", "D,S,T", 0x46800008, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sun.s", "D,S,T", 0x46800009, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.seq.s", "D,S,T", 0x4680000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sueq.s", "D,S,T", 0x4680000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.slt.s", "D,S,T", 0x4680000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sult.s", "D,S,T", 0x4680000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sle.s", "D,S,T", 0x4680000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sule.s", "D,S,T", 0x4680000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.or.s", "D,S,T", 0x46800011, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.une.s", "D,S,T", 0x46800012, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.ne.s", "D,S,T", 0x46800013, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sor.s", "D,S,T", 0x46800019, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sune.s", "D,S,T", 0x4680001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.sne.s", "D,S,T", 0x4680001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6}, +{"cmp.af.d", "D,S,T", 0x46a00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.un.d", "D,S,T", 0x46a00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.eq.d", "D,S,T", 0x46a00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.ueq.d", "D,S,T", 0x46a00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.lt.d", "D,S,T", 0x46a00004, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.ult.d", "D,S,T", 0x46a00005, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.le.d", "D,S,T", 0x46a00006, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.ule.d", "D,S,T", 0x46a00007, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.saf.d", "D,S,T", 0x46a00008, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sun.d", "D,S,T", 0x46a00009, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.seq.d", "D,S,T", 0x46a0000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sueq.d", "D,S,T", 0x46a0000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.slt.d", "D,S,T", 0x46a0000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sult.d", "D,S,T", 0x46a0000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sle.d", "D,S,T", 0x46a0000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sule.d", "D,S,T", 0x46a0000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.or.d", "D,S,T", 0x46a00011, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.une.d", "D,S,T", 0x46a00012, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.ne.d", "D,S,T", 0x46a00013, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sor.d", "D,S,T", 0x46a00019, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sune.d", "D,S,T", 0x46a0001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, +{"cmp.sne.d", "D,S,T", 0x46a0001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6}, + +/* MSA */ +{"sll.b", "+d,+e,+f", 0x7800000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sll.h", "+d,+e,+f", 0x7820000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sll.w", "+d,+e,+f", 0x7840000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sll.d", "+d,+e,+f", 0x7860000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"slli.b", "+d,+e,+7", 0x78700009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"slli.h", "+d,+e,+8", 0x78600009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"slli.w", "+d,+e,+9", 0x78400009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"slli.d", "+d,+e,'", 0x78000009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"sra.b", "+d,+e,+f", 0x7880000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sra.h", "+d,+e,+f", 0x78a0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sra.w", "+d,+e,+f", 0x78c0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sra.d", "+d,+e,+f", 0x78e0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srai.b", "+d,+e,+7", 0x78f00009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"srai.h", "+d,+e,+8", 0x78e00009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"srai.w", "+d,+e,+9", 0x78c00009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"srai.d", "+d,+e,'", 0x78800009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"srl.b", "+d,+e,+f", 0x7900000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srl.h", "+d,+e,+f", 0x7920000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srl.w", "+d,+e,+f", 0x7940000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srl.d", "+d,+e,+f", 0x7960000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srli.b", "+d,+e,+7", 0x79700009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"srli.h", "+d,+e,+8", 0x79600009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"srli.w", "+d,+e,+9", 0x79400009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"srli.d", "+d,+e,'", 0x79000009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"bclr.b", "+d,+e,+f", 0x7980000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bclr.h", "+d,+e,+f", 0x79a0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bclr.w", "+d,+e,+f", 0x79c0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bclr.d", "+d,+e,+f", 0x79e0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bclri.b", "+d,+e,+7", 0x79f00009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"bclri.h", "+d,+e,+8", 0x79e00009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"bclri.w", "+d,+e,+9", 0x79c00009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"bclri.d", "+d,+e,'", 0x79800009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"bset.b", "+d,+e,+f", 0x7a00000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bset.h", "+d,+e,+f", 0x7a20000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bset.w", "+d,+e,+f", 0x7a40000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bset.d", "+d,+e,+f", 0x7a60000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bseti.b", "+d,+e,+7", 0x7a700009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"bseti.h", "+d,+e,+8", 0x7a600009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"bseti.w", "+d,+e,+9", 0x7a400009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"bseti.d", "+d,+e,'", 0x7a000009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"bneg.b", "+d,+e,+f", 0x7a80000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bneg.h", "+d,+e,+f", 0x7aa0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bneg.w", "+d,+e,+f", 0x7ac0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bneg.d", "+d,+e,+f", 0x7ae0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bnegi.b", "+d,+e,+7", 0x7af00009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"bnegi.h", "+d,+e,+8", 0x7ae00009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"bnegi.w", "+d,+e,+9", 0x7ac00009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"bnegi.d", "+d,+e,'", 0x7a800009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"binsl.b", "+d,+e,+f", 0x7b00000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsl.h", "+d,+e,+f", 0x7b20000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsl.w", "+d,+e,+f", 0x7b40000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsl.d", "+d,+e,+f", 0x7b60000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsli.b", "+d,+e,+7", 0x7b700009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"binsli.h", "+d,+e,+8", 0x7b600009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"binsli.w", "+d,+e,+9", 0x7b400009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"binsli.d", "+d,+e,'", 0x7b000009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"binsr.b", "+d,+e,+f", 0x7b80000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsr.h", "+d,+e,+f", 0x7ba0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsr.w", "+d,+e,+f", 0x7bc0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsr.d", "+d,+e,+f", 0x7be0000d, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"binsri.b", "+d,+e,+7", 0x7bf00009, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"binsri.h", "+d,+e,+8", 0x7be00009, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"binsri.w", "+d,+e,+9", 0x7bc00009, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"binsri.d", "+d,+e,'", 0x7b800009, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"addv.b", "+d,+e,+f", 0x7800000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"addv.h", "+d,+e,+f", 0x7820000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"addv.w", "+d,+e,+f", 0x7840000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"addv.d", "+d,+e,+f", 0x7860000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"addvi.b", "+d,+e,k", 0x78000006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"addvi.h", "+d,+e,k", 0x78200006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"addvi.w", "+d,+e,k", 0x78400006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"addvi.d", "+d,+e,k", 0x78600006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"subv.b", "+d,+e,+f", 0x7880000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subv.h", "+d,+e,+f", 0x78a0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subv.w", "+d,+e,+f", 0x78c0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subv.d", "+d,+e,+f", 0x78e0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subvi.b", "+d,+e,k", 0x78800006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"subvi.h", "+d,+e,k", 0x78a00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"subvi.w", "+d,+e,k", 0x78c00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"subvi.d", "+d,+e,k", 0x78e00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"max_s.b", "+d,+e,+f", 0x7900000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_s.h", "+d,+e,+f", 0x7920000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_s.w", "+d,+e,+f", 0x7940000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_s.d", "+d,+e,+f", 0x7960000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maxi_s.b", "+d,+e,+5", 0x79000006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"maxi_s.h", "+d,+e,+5", 0x79200006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"maxi_s.w", "+d,+e,+5", 0x79400006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"maxi_s.d", "+d,+e,+5", 0x79600006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"max_u.b", "+d,+e,+f", 0x7980000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_u.h", "+d,+e,+f", 0x79a0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_u.w", "+d,+e,+f", 0x79c0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_u.d", "+d,+e,+f", 0x79e0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maxi_u.b", "+d,+e,k", 0x79800006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"maxi_u.h", "+d,+e,k", 0x79a00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"maxi_u.w", "+d,+e,k", 0x79c00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"maxi_u.d", "+d,+e,k", 0x79e00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"min_s.b", "+d,+e,+f", 0x7a00000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_s.h", "+d,+e,+f", 0x7a20000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_s.w", "+d,+e,+f", 0x7a40000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_s.d", "+d,+e,+f", 0x7a60000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mini_s.b", "+d,+e,+5", 0x7a000006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"mini_s.h", "+d,+e,+5", 0x7a200006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"mini_s.w", "+d,+e,+5", 0x7a400006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"mini_s.d", "+d,+e,+5", 0x7a600006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"min_u.b", "+d,+e,+f", 0x7a80000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_u.h", "+d,+e,+f", 0x7aa0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_u.w", "+d,+e,+f", 0x7ac0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_u.d", "+d,+e,+f", 0x7ae0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mini_u.b", "+d,+e,k", 0x7a800006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"mini_u.h", "+d,+e,k", 0x7aa00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"mini_u.w", "+d,+e,k", 0x7ac00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"mini_u.d", "+d,+e,k", 0x7ae00006, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"max_a.b", "+d,+e,+f", 0x7b00000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_a.h", "+d,+e,+f", 0x7b20000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_a.w", "+d,+e,+f", 0x7b40000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"max_a.d", "+d,+e,+f", 0x7b60000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_a.b", "+d,+e,+f", 0x7b80000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_a.h", "+d,+e,+f", 0x7ba0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_a.w", "+d,+e,+f", 0x7bc0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"min_a.d", "+d,+e,+f", 0x7be0000e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ceq.b", "+d,+e,+f", 0x7800000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ceq.h", "+d,+e,+f", 0x7820000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ceq.w", "+d,+e,+f", 0x7840000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ceq.d", "+d,+e,+f", 0x7860000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ceqi.b", "+d,+e,+5", 0x78000007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"ceqi.h", "+d,+e,+5", 0x78200007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"ceqi.w", "+d,+e,+5", 0x78400007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"ceqi.d", "+d,+e,+5", 0x78600007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clt_s.b", "+d,+e,+f", 0x7900000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clt_s.h", "+d,+e,+f", 0x7920000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clt_s.w", "+d,+e,+f", 0x7940000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clt_s.d", "+d,+e,+f", 0x7960000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clti_s.b", "+d,+e,+5", 0x79000007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clti_s.h", "+d,+e,+5", 0x79200007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clti_s.w", "+d,+e,+5", 0x79400007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clti_s.d", "+d,+e,+5", 0x79600007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clt_u.b", "+d,+e,+f", 0x7980000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clt_u.h", "+d,+e,+f", 0x79a0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clt_u.w", "+d,+e,+f", 0x79c0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clt_u.d", "+d,+e,+f", 0x79e0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clti_u.b", "+d,+e,k", 0x79800007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clti_u.h", "+d,+e,k", 0x79a00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clti_u.w", "+d,+e,k", 0x79c00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clti_u.d", "+d,+e,k", 0x79e00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"cle_s.b", "+d,+e,+f", 0x7a00000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"cle_s.h", "+d,+e,+f", 0x7a20000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"cle_s.w", "+d,+e,+f", 0x7a40000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"cle_s.d", "+d,+e,+f", 0x7a60000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clei_s.b", "+d,+e,+5", 0x7a000007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clei_s.h", "+d,+e,+5", 0x7a200007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clei_s.w", "+d,+e,+5", 0x7a400007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clei_s.d", "+d,+e,+5", 0x7a600007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"cle_u.b", "+d,+e,+f", 0x7a80000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"cle_u.h", "+d,+e,+f", 0x7aa0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"cle_u.w", "+d,+e,+f", 0x7ac0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"cle_u.d", "+d,+e,+f", 0x7ae0000f, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"clei_u.b", "+d,+e,k", 0x7a800007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clei_u.h", "+d,+e,k", 0x7aa00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clei_u.w", "+d,+e,k", 0x7ac00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"clei_u.d", "+d,+e,k", 0x7ae00007, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"ld.b", "+d,+^(d)", 0x78000020, 0xfc00003f, WR_VD|LDD, RD_d, MSA}, +{"ld.h", "+d,+#(d)", 0x78000021, 0xfc00003f, WR_VD|LDD, RD_d, MSA}, +{"ld.w", "+d,+$(d)", 0x78000022, 0xfc00003f, WR_VD|LDD, RD_d, MSA}, +{"ld.d", "+d,+%(d)", 0x78000023, 0xfc00003f, WR_VD|LDD, RD_d, MSA}, +{"st.b", "+d,+^(d)", 0x78000024, 0xfc00003f, RD_VD|SM, RD_d, MSA}, +{"st.h", "+d,+#(d)", 0x78000025, 0xfc00003f, RD_VD|SM, RD_d, MSA}, +{"st.w", "+d,+$(d)", 0x78000026, 0xfc00003f, RD_VD|SM, RD_d, MSA}, +{"st.d", "+d,+%(d)", 0x78000027, 0xfc00003f, RD_VD|SM, RD_d, MSA}, +{"sat_s.b", "+d,+e,+7", 0x7870000a, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"sat_s.h", "+d,+e,+8", 0x7860000a, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"sat_s.w", "+d,+e,+9", 0x7840000a, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"sat_s.d", "+d,+e,'", 0x7800000a, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"sat_u.b", "+d,+e,+7", 0x78f0000a, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"sat_u.h", "+d,+e,+8", 0x78e0000a, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"sat_u.w", "+d,+e,+9", 0x78c0000a, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"sat_u.d", "+d,+e,'", 0x7880000a, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"add_a.b", "+d,+e,+f", 0x78000010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"add_a.h", "+d,+e,+f", 0x78200010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"add_a.w", "+d,+e,+f", 0x78400010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"add_a.d", "+d,+e,+f", 0x78600010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_a.b", "+d,+e,+f", 0x78800010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_a.h", "+d,+e,+f", 0x78a00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_a.w", "+d,+e,+f", 0x78c00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_a.d", "+d,+e,+f", 0x78e00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_s.b", "+d,+e,+f", 0x79000010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_s.h", "+d,+e,+f", 0x79200010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_s.w", "+d,+e,+f", 0x79400010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_s.d", "+d,+e,+f", 0x79600010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_u.b", "+d,+e,+f", 0x79800010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_u.h", "+d,+e,+f", 0x79a00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_u.w", "+d,+e,+f", 0x79c00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"adds_u.d", "+d,+e,+f", 0x79e00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_s.b", "+d,+e,+f", 0x7a000010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_s.h", "+d,+e,+f", 0x7a200010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_s.w", "+d,+e,+f", 0x7a400010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_s.d", "+d,+e,+f", 0x7a600010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_u.b", "+d,+e,+f", 0x7a800010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_u.h", "+d,+e,+f", 0x7aa00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_u.w", "+d,+e,+f", 0x7ac00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ave_u.d", "+d,+e,+f", 0x7ae00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_s.b", "+d,+e,+f", 0x7b000010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_s.h", "+d,+e,+f", 0x7b200010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_s.w", "+d,+e,+f", 0x7b400010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_s.d", "+d,+e,+f", 0x7b600010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_u.b", "+d,+e,+f", 0x7b800010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_u.h", "+d,+e,+f", 0x7ba00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_u.w", "+d,+e,+f", 0x7bc00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"aver_u.d", "+d,+e,+f", 0x7be00010, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_s.b", "+d,+e,+f", 0x78000011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_s.h", "+d,+e,+f", 0x78200011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_s.w", "+d,+e,+f", 0x78400011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_s.d", "+d,+e,+f", 0x78600011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_u.b", "+d,+e,+f", 0x78800011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_u.h", "+d,+e,+f", 0x78a00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_u.w", "+d,+e,+f", 0x78c00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subs_u.d", "+d,+e,+f", 0x78e00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsus_u.b", "+d,+e,+f", 0x79000011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsus_u.h", "+d,+e,+f", 0x79200011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsus_u.w", "+d,+e,+f", 0x79400011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsus_u.d", "+d,+e,+f", 0x79600011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsuu_s.b", "+d,+e,+f", 0x79800011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsuu_s.h", "+d,+e,+f", 0x79a00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsuu_s.w", "+d,+e,+f", 0x79c00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"subsuu_s.d", "+d,+e,+f", 0x79e00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_s.b", "+d,+e,+f", 0x7a000011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_s.h", "+d,+e,+f", 0x7a200011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_s.w", "+d,+e,+f", 0x7a400011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_s.d", "+d,+e,+f", 0x7a600011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_u.b", "+d,+e,+f", 0x7a800011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_u.h", "+d,+e,+f", 0x7aa00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_u.w", "+d,+e,+f", 0x7ac00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"asub_u.d", "+d,+e,+f", 0x7ae00011, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mulv.b", "+d,+e,+f", 0x78000012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mulv.h", "+d,+e,+f", 0x78200012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mulv.w", "+d,+e,+f", 0x78400012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mulv.d", "+d,+e,+f", 0x78600012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maddv.b", "+d,+e,+f", 0x78800012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maddv.h", "+d,+e,+f", 0x78a00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maddv.w", "+d,+e,+f", 0x78c00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maddv.d", "+d,+e,+f", 0x78e00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msubv.b", "+d,+e,+f", 0x79000012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msubv.h", "+d,+e,+f", 0x79200012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msubv.w", "+d,+e,+f", 0x79400012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msubv.d", "+d,+e,+f", 0x79600012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_s.b", "+d,+e,+f", 0x7a000012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_s.h", "+d,+e,+f", 0x7a200012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_s.w", "+d,+e,+f", 0x7a400012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_s.d", "+d,+e,+f", 0x7a600012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_u.b", "+d,+e,+f", 0x7a800012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_u.h", "+d,+e,+f", 0x7aa00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_u.w", "+d,+e,+f", 0x7ac00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"div_u.d", "+d,+e,+f", 0x7ae00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_s.b", "+d,+e,+f", 0x7b000012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_s.h", "+d,+e,+f", 0x7b200012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_s.w", "+d,+e,+f", 0x7b400012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_s.d", "+d,+e,+f", 0x7b600012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_u.b", "+d,+e,+f", 0x7b800012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_u.h", "+d,+e,+f", 0x7ba00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_u.w", "+d,+e,+f", 0x7bc00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mod_u.d", "+d,+e,+f", 0x7be00012, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dotp_s.h", "+d,+e,+f", 0x78200013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dotp_s.w", "+d,+e,+f", 0x78400013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dotp_s.d", "+d,+e,+f", 0x78600013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dotp_u.h", "+d,+e,+f", 0x78a00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dotp_u.w", "+d,+e,+f", 0x78c00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dotp_u.d", "+d,+e,+f", 0x78e00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpadd_s.h", "+d,+e,+f", 0x79200013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpadd_s.w", "+d,+e,+f", 0x79400013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpadd_s.d", "+d,+e,+f", 0x79600013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpadd_u.h", "+d,+e,+f", 0x79a00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpadd_u.w", "+d,+e,+f", 0x79c00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpadd_u.d", "+d,+e,+f", 0x79e00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpsub_s.h", "+d,+e,+f", 0x7a200013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpsub_s.w", "+d,+e,+f", 0x7a400013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpsub_s.d", "+d,+e,+f", 0x7a600013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpsub_u.h", "+d,+e,+f", 0x7aa00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpsub_u.w", "+d,+e,+f", 0x7ac00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"dpsub_u.d", "+d,+e,+f", 0x7ae00013, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"sld.b", "+d,+e[t]", 0x78000014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"sld.h", "+d,+e[t]", 0x78200014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"sld.w", "+d,+e[t]", 0x78400014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"sld.d", "+d,+e[t]", 0x78600014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"sldi.b", "+d,+e[+9]", 0x78000019, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"sldi.h", "+d,+e[+8]", 0x78200019, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"sldi.w", "+d,+e[+7]", 0x78300019, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"sldi.d", "+d,+e[+6]", 0x78380019, 0xfffc003f, WR_VD|RD_VS, 0, MSA}, +{"splat.b", "+d,+e[t]", 0x78800014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"splat.h", "+d,+e[t]", 0x78a00014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"splat.w", "+d,+e[t]", 0x78c00014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"splat.d", "+d,+e[t]", 0x78e00014, 0xffe0003f, WR_VD|RD_VS|RD_t, 0, MSA}, +{"splati.b", "+d,+e[+9]", 0x78400019, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"splati.h", "+d,+e[+8]", 0x78600019, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"splati.w", "+d,+e[+7]", 0x78700019, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"splati.d", "+d,+e[+6]", 0x78780019, 0xfffc003f, WR_VD|RD_VS, 0, MSA}, +{"pckev.b", "+d,+e,+f", 0x79000014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckev.h", "+d,+e,+f", 0x79200014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckev.w", "+d,+e,+f", 0x79400014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckev.d", "+d,+e,+f", 0x79600014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckod.b", "+d,+e,+f", 0x79800014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckod.h", "+d,+e,+f", 0x79a00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckod.w", "+d,+e,+f", 0x79c00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"pckod.d", "+d,+e,+f", 0x79e00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvl.b", "+d,+e,+f", 0x7a000014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvl.h", "+d,+e,+f", 0x7a200014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvl.w", "+d,+e,+f", 0x7a400014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvl.d", "+d,+e,+f", 0x7a600014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvr.b", "+d,+e,+f", 0x7a800014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvr.h", "+d,+e,+f", 0x7aa00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvr.w", "+d,+e,+f", 0x7ac00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvr.d", "+d,+e,+f", 0x7ae00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvev.b", "+d,+e,+f", 0x7b000014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvev.h", "+d,+e,+f", 0x7b200014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvev.w", "+d,+e,+f", 0x7b400014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvev.d", "+d,+e,+f", 0x7b600014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvod.b", "+d,+e,+f", 0x7b800014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvod.h", "+d,+e,+f", 0x7ba00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvod.w", "+d,+e,+f", 0x7bc00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ilvod.d", "+d,+e,+f", 0x7be00014, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"vshf.b", "+d,+e,+f", 0x78000015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"vshf.h", "+d,+e,+f", 0x78200015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"vshf.w", "+d,+e,+f", 0x78400015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"vshf.d", "+d,+e,+f", 0x78600015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srar.b", "+d,+e,+f", 0x78800015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srar.h", "+d,+e,+f", 0x78a00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srar.w", "+d,+e,+f", 0x78c00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srar.d", "+d,+e,+f", 0x78e00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srari.b", "+d,+e,+7", 0x7970000a, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"srari.h", "+d,+e,+8", 0x7960000a, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"srari.w", "+d,+e,+9", 0x7940000a, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"srari.d", "+d,+e,'", 0x7900000a, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"srlr.b", "+d,+e,+f", 0x79000015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srlr.h", "+d,+e,+f", 0x79200015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srlr.w", "+d,+e,+f", 0x79400015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srlr.d", "+d,+e,+f", 0x79600015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"srlri.b", "+d,+e,+7", 0x79f0000a, 0xfff8003f, WR_VD|RD_VS, 0, MSA}, +{"srlri.h", "+d,+e,+8", 0x79e0000a, 0xfff0003f, WR_VD|RD_VS, 0, MSA}, +{"srlri.w", "+d,+e,+9", 0x79c0000a, 0xffe0003f, WR_VD|RD_VS, 0, MSA}, +{"srlri.d", "+d,+e,'", 0x7980000a, 0xffc0003f, WR_VD|RD_VS, 0, MSA}, +{"hadd_s.h", "+d,+e,+f", 0x7a200015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hadd_s.w", "+d,+e,+f", 0x7a400015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hadd_s.d", "+d,+e,+f", 0x7a600015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hadd_u.h", "+d,+e,+f", 0x7aa00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hadd_u.w", "+d,+e,+f", 0x7ac00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hadd_u.d", "+d,+e,+f", 0x7ae00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hsub_s.h", "+d,+e,+f", 0x7b200015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hsub_s.w", "+d,+e,+f", 0x7b400015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hsub_s.d", "+d,+e,+f", 0x7b600015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hsub_u.h", "+d,+e,+f", 0x7ba00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hsub_u.w", "+d,+e,+f", 0x7bc00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"hsub_u.d", "+d,+e,+f", 0x7be00015, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"and.v", "+d,+e,+f", 0x7800001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"andi.b", "+d,+e,5", 0x78000000, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"or.v", "+d,+e,+f", 0x7820001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ori.b", "+d,+e,5", 0x79000000, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"nor.v", "+d,+e,+f", 0x7840001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"nori.b", "+d,+e,5", 0x7a000000, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"xor.v", "+d,+e,+f", 0x7860001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"xori.b", "+d,+e,5", 0x7b000000, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"bmnz.v", "+d,+e,+f", 0x7880001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bmnzi.b", "+d,+e,5", 0x78000001, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"bmz.v", "+d,+e,+f", 0x78a0001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bmzi.b", "+d,+e,5", 0x79000001, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"bsel.v", "+d,+e,+f", 0x78c0001e, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"bseli.b", "+d,+e,5", 0x7a000001, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"shf.b", "+d,+e,5", 0x78000002, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"shf.h", "+d,+e,5", 0x79000002, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"shf.w", "+d,+e,5", 0x7a000002, 0xff00003f, WR_VD|RD_VS, 0, MSA}, +{"bnz.v", "+f,p", 0x45e00000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bz.v", "+f,p", 0x45600000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"fill.b", "+d,d", 0x7b00001e, 0xffff003f, WR_VD, RD_d, MSA}, +{"fill.h", "+d,d", 0x7b01001e, 0xffff003f, WR_VD, RD_d, MSA}, +{"fill.w", "+d,d", 0x7b02001e, 0xffff003f, WR_VD, RD_d, MSA}, +{"fill.d", "+d,d", 0x7b03001e, 0xffff003f, WR_VD, RD_d, MSA64}, +{"pcnt.b", "+d,+e", 0x7b04001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"pcnt.h", "+d,+e", 0x7b05001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"pcnt.w", "+d,+e", 0x7b06001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"pcnt.d", "+d,+e", 0x7b07001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nloc.b", "+d,+e", 0x7b08001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nloc.h", "+d,+e", 0x7b09001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nloc.w", "+d,+e", 0x7b0a001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nloc.d", "+d,+e", 0x7b0b001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nlzc.b", "+d,+e", 0x7b0c001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nlzc.h", "+d,+e", 0x7b0d001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nlzc.w", "+d,+e", 0x7b0e001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"nlzc.d", "+d,+e", 0x7b0f001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"copy_s.b", "+i,+e[+9]", 0x78800019, 0xffe0003f, RD_VS, RD_rd6, MSA}, +{"copy_s.h", "+i,+e[+8]", 0x78a00019, 0xfff0003f, RD_VS, RD_rd6, MSA}, +{"copy_s.w", "+i,+e[+7]", 0x78b00019, 0xfff8003f, RD_VS, RD_rd6, MSA}, +{"copy_s.d", "+i,+e[+6]", 0x78b80019, 0xfffc003f, RD_VS, RD_rd6, MSA64}, +{"copy_u.b", "+i,+e[+9]", 0x78c00019, 0xffe0003f, RD_VS, RD_rd6, MSA}, +{"copy_u.h", "+i,+e[+8]", 0x78e00019, 0xfff0003f, RD_VS, RD_rd6, MSA}, +{"copy_u.w", "+i,+e[+7]", 0x78f00019, 0xfff8003f, RD_VS, RD_rd6, MSA}, +{"copy_u.d", "+i,+e[+6]", 0x78f80019, 0xfffc003f, RD_VS, RD_rd6, MSA64}, +{"insert.b", "+d[+9],d", 0x79000019, 0xffe0003f, WR_VD|RD_VD, RD_d, MSA}, +{"insert.h", "+d[+8],d", 0x79200019, 0xfff0003f, WR_VD|RD_VD, RD_d, MSA}, +{"insert.w", "+d[+7],d", 0x79300019, 0xfff8003f, WR_VD|RD_VD, RD_d, MSA}, +{"insert.d", "+d[+6],d", 0x79380019, 0xfffc003f, WR_VD|RD_VD, RD_d, MSA64}, +{"insve.b", "+d[+9],+e[+~]", 0x79400019, 0xffe0003f, WR_VD|RD_VD|RD_VS, 0, MSA}, +{"insve.h", "+d[+8],+e[+~]", 0x79600019, 0xfff0003f, WR_VD|RD_VD|RD_VS, 0, MSA}, +{"insve.w", "+d[+7],+e[+~]", 0x79700019, 0xfff8003f, WR_VD|RD_VD|RD_VS, 0, MSA}, +{"insve.d", "+d[+6],+e[+~]", 0x79780019, 0xfffc003f, WR_VD|RD_VD|RD_VS, 0, MSA}, +{"bnz.b", "+f,p", 0x47800000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bnz.h", "+f,p", 0x47a00000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bnz.w", "+f,p", 0x47c00000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bnz.d", "+f,p", 0x47e00000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bz.b", "+f,p", 0x47000000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bz.h", "+f,p", 0x47200000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bz.w", "+f,p", 0x47400000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"bz.d", "+f,p", 0x47600000, 0xffe00000, CBD|RD_VT, 0, MSA}, +{"ldi.b", "+d,+0", 0x7b000007, 0xffe0003f, WR_VD, 0, MSA}, +{"ldi.h", "+d,+0", 0x7b200007, 0xffe0003f, WR_VD, 0, MSA}, +{"ldi.w", "+d,+0", 0x7b400007, 0xffe0003f, WR_VD, 0, MSA}, +{"ldi.d", "+d,+0", 0x7b600007, 0xffe0003f, WR_VD, 0, MSA}, +{"fcaf.w", "+d,+e,+f", 0x7800001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcaf.d", "+d,+e,+f", 0x7820001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcun.w", "+d,+e,+f", 0x7840001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcun.d", "+d,+e,+f", 0x7860001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fceq.w", "+d,+e,+f", 0x7880001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fceq.d", "+d,+e,+f", 0x78a0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcueq.w", "+d,+e,+f", 0x78c0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcueq.d", "+d,+e,+f", 0x78e0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fclt.w", "+d,+e,+f", 0x7900001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fclt.d", "+d,+e,+f", 0x7920001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcult.w", "+d,+e,+f", 0x7940001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcult.d", "+d,+e,+f", 0x7960001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcle.w", "+d,+e,+f", 0x7980001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcle.d", "+d,+e,+f", 0x79a0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcule.w", "+d,+e,+f", 0x79c0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcule.d", "+d,+e,+f", 0x79e0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsaf.w", "+d,+e,+f", 0x7a00001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsaf.d", "+d,+e,+f", 0x7a20001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsun.w", "+d,+e,+f", 0x7a40001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsun.d", "+d,+e,+f", 0x7a60001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fseq.w", "+d,+e,+f", 0x7a80001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fseq.d", "+d,+e,+f", 0x7aa0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsueq.w", "+d,+e,+f", 0x7ac0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsueq.d", "+d,+e,+f", 0x7ae0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fslt.w", "+d,+e,+f", 0x7b00001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fslt.d", "+d,+e,+f", 0x7b20001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsult.w", "+d,+e,+f", 0x7b40001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsult.d", "+d,+e,+f", 0x7b60001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsle.w", "+d,+e,+f", 0x7b80001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsle.d", "+d,+e,+f", 0x7ba0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsule.w", "+d,+e,+f", 0x7bc0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsule.d", "+d,+e,+f", 0x7be0001a, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fadd.w", "+d,+e,+f", 0x7800001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fadd.d", "+d,+e,+f", 0x7820001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsub.w", "+d,+e,+f", 0x7840001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsub.d", "+d,+e,+f", 0x7860001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmul.w", "+d,+e,+f", 0x7880001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmul.d", "+d,+e,+f", 0x78a0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fdiv.w", "+d,+e,+f", 0x78c0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fdiv.d", "+d,+e,+f", 0x78e0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmadd.w", "+d,+e,+f", 0x7900001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmadd.d", "+d,+e,+f", 0x7920001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmsub.w", "+d,+e,+f", 0x7940001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmsub.d", "+d,+e,+f", 0x7960001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fexp2.w", "+d,+e,+f", 0x79c0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fexp2.d", "+d,+e,+f", 0x79e0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fexdo.h", "+d,+e,+f", 0x7a00001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fexdo.w", "+d,+e,+f", 0x7a20001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ftq.h", "+d,+e,+f", 0x7a80001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"ftq.w", "+d,+e,+f", 0x7aa0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmin.w", "+d,+e,+f", 0x7b00001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmin.d", "+d,+e,+f", 0x7b20001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmin_a.w", "+d,+e,+f", 0x7b40001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmin_a.d", "+d,+e,+f", 0x7b60001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmax.w", "+d,+e,+f", 0x7b80001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmax.d", "+d,+e,+f", 0x7ba0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmax_a.w", "+d,+e,+f", 0x7bc0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fmax_a.d", "+d,+e,+f", 0x7be0001b, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcor.w", "+d,+e,+f", 0x7840001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcor.d", "+d,+e,+f", 0x7860001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcune.w", "+d,+e,+f", 0x7880001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcune.d", "+d,+e,+f", 0x78a0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcne.w", "+d,+e,+f", 0x78c0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fcne.d", "+d,+e,+f", 0x78e0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mul_q.h", "+d,+e,+f", 0x7900001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mul_q.w", "+d,+e,+f", 0x7920001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"madd_q.h", "+d,+e,+f", 0x7940001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"madd_q.w", "+d,+e,+f", 0x7960001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msub_q.h", "+d,+e,+f", 0x7980001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msub_q.w", "+d,+e,+f", 0x79a0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsor.w", "+d,+e,+f", 0x7a40001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsor.d", "+d,+e,+f", 0x7a60001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsune.w", "+d,+e,+f", 0x7a80001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsune.d", "+d,+e,+f", 0x7aa0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsne.w", "+d,+e,+f", 0x7ac0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fsne.d", "+d,+e,+f", 0x7ae0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mulr_q.h", "+d,+e,+f", 0x7b00001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"mulr_q.w", "+d,+e,+f", 0x7b20001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maddr_q.h", "+d,+e,+f", 0x7b40001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"maddr_q.w", "+d,+e,+f", 0x7b60001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msubr_q.h", "+d,+e,+f", 0x7b80001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"msubr_q.w", "+d,+e,+f", 0x7ba0001c, 0xffe0003f, WR_VD|RD_VS|RD_VT, 0, MSA}, +{"fclass.w", "+d,+e", 0x7b20001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fclass.d", "+d,+e", 0x7b21001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fsqrt.w", "+d,+e", 0x7b26001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fsqrt.d", "+d,+e", 0x7b27001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"frsqrt.w", "+d,+e", 0x7b28001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"frsqrt.d", "+d,+e", 0x7b29001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"frcp.w", "+d,+e", 0x7b2a001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"frcp.d", "+d,+e", 0x7b2b001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"frint.w", "+d,+e", 0x7b2c001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"frint.d", "+d,+e", 0x7b2d001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"flog2.w", "+d,+e", 0x7b2e001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"flog2.d", "+d,+e", 0x7b2f001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fexupl.w", "+d,+e", 0x7b30001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fexupl.d", "+d,+e", 0x7b31001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fexupr.w", "+d,+e", 0x7b32001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"fexupr.d", "+d,+e", 0x7b33001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffql.w", "+d,+e", 0x7b34001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffql.d", "+d,+e", 0x7b35001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffqr.w", "+d,+e", 0x7b36001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffqr.d", "+d,+e", 0x7b37001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftint_s.w", "+d,+e", 0x7b38001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftint_s.d", "+d,+e", 0x7b39001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftint_u.w", "+d,+e", 0x7b3a001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftint_u.d", "+d,+e", 0x7b3b001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffint_s.w", "+d,+e", 0x7b3c001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffint_s.d", "+d,+e", 0x7b3d001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffint_u.w", "+d,+e", 0x7b3e001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ffint_u.d", "+d,+e", 0x7b3f001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftrunc_s.w", "+d,+e", 0x7b40001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftrunc_s.d", "+d,+e", 0x7b41001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftrunc_u.w", "+d,+e", 0x7b42001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ftrunc_u.d", "+d,+e", 0x7b43001e, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"ctcmsa", "+h,d", 0x783e0019, 0xffff003f, COD, RD_d, MSA}, +{"cfcmsa", "+i,+g", 0x787e0019, 0xffff003f, COD, 0, MSA}, +{"move.v", "+d,+e", 0x78be0019, 0xffff003f, WR_VD|RD_VS, 0, MSA}, +{"lsa", "d,v,t,+@", 0x00000005, 0xfc00073f, WR_d|RD_s|RD_t, 0, MSA}, +{"dlsa", "d,v,t,+@", 0x00000015, 0xfc00073f, WR_d|RD_s|RD_t, 0, MSA64}, + {"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 }, {"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, 0, I4|I33 }, {"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */ @@ -1753,6 +2483,7 @@ const struct mips_opcode mips_builtin_opcodes[] = {"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 }, {"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, 0, I3 }, {"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, 0, I1 }, +{"aui", "s,t,u", 0x3c000000, 0xfc000000, RD_s|WR_t, 0, I32R6}, {"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I5|I33|N55}, {"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 }, {"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, 0, I1 }, @@ -2255,6 +2986,8 @@ const struct mips_opcode mips_builtin_opcodes[] = {"tlbp", "", 0x42000008, 0xffffffff, INSN_TLB, 0, I1 }, {"tlbr", "", 0x42000001, 0xffffffff, INSN_TLB, 0, I1 }, {"tlbwi", "", 0x42000002, 0xffffffff, INSN_TLB, 0, I1 }, +{"tlbinv", "", 0x42000003, 0xffffffff, INSN_TLB, 0, I32 }, +{"tlbinvf", "", 0x42000004, 0xffffffff, INSN_TLB, 0, I32 }, {"tlbwr", "", 0x42000006, 0xffffffff, INSN_TLB, 0, I1 }, {"tlti", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, 0, I2 }, {"tlt", "s,t", 0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP, 0, I2 }, @@ -2843,6 +3576,13 @@ static const char * const mips_fpr_names_64[32] = "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7" }; +static const char * const mips_wr_names[32] = { + "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", + "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", + "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", + "w24", "w25", "w26", "w27", "w28", "w29", "w30", "w31" +}; + static const char * const mips_cp0_names_numeric[32] = { "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", @@ -3061,6 +3801,20 @@ static const char * const mips_hwr_names_mips3264r2[32] = "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" }; +static const char * const mips_msa_control_names_numeric[32] = { + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + +static const char * const mips_msa_control_names_mips3264r2[32] = { + "MSAIR", "MSACSR", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" +}; + struct mips_abi_choice { const char *name; @@ -3178,7 +3932,7 @@ static const struct mips_arch_choice mips_arch_choices[] = { "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2, (ISA_MIPS32R2 | INSN_MIPS16 | INSN_SMARTMIPS | INSN_DSP | INSN_DSPR2 - | INSN_MIPS3D | INSN_MT), + | INSN_MIPS3D | INSN_MT | INSN_MSA), mips_cp0_names_mips3264r2, mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), mips_hwr_names_mips3264r2 }, @@ -3532,6 +4286,89 @@ print_insn_args (const char *d, (l >> OP_SH_UDI4) & OP_MASK_UDI4); break; + case '5': /* 5-bit signed immediate in bit 16 */ + delta = ((l >> OP_SH_RT) & OP_MASK_RT); + if (delta & 0x10) { /* test sign bit */ + delta |= ~OP_MASK_RT; + } + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case '6': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_2BIT) & OP_MASK_2BIT); + break; + + case '7': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_3BIT) & OP_MASK_3BIT); + break; + + case '8': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_4BIT) & OP_MASK_4BIT); + break; + + case '9': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_5BIT) & OP_MASK_5BIT); + break; + + case ':': + (*info->fprintf_func) (info->stream, "0x%lx", + (l >> OP_SH_1BIT) & OP_MASK_1BIT); + break; + + case '!': /* 10-bit pc-relative target in bit 11 */ + delta = ((l >> OP_SH_10BIT) & OP_MASK_10BIT); + if (delta & 0x200) { /* test sign bit */ + delta |= ~OP_MASK_10BIT; + } + info->target = (delta << 2) + pc + INSNLEN; + (*info->print_address_func) (info->target, info); + break; + + case '~': + (*info->fprintf_func) (info->stream, "0"); + break; + + case '@': + (*info->fprintf_func) (info->stream, "0x%lx", + ((l >> OP_SH_1_TO_4) & OP_MASK_1_TO_4)+1); + break; + + case '^': /* 10-bit signed immediate << 0 in bit 16 */ + delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); + if (delta & 0x200) { /* test sign bit */ + delta |= ~OP_MASK_IMM10; + } + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case '#': /* 10-bit signed immediate << 1 in bit 16 */ + delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); + if (delta & 0x200) { /* test sign bit */ + delta |= ~OP_MASK_IMM10; + } + (*info->fprintf_func) (info->stream, "%d", delta << 1); + break; + + case '$': /* 10-bit signed immediate << 2 in bit 16 */ + delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); + if (delta & 0x200) { /* test sign bit */ + delta |= ~OP_MASK_IMM10; + } + (*info->fprintf_func) (info->stream, "%d", delta << 2); + break; + + case '%': /* 10-bit signed immediate << 3 in bit 16 */ + delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10); + if (delta & 0x200) { /* test sign bit */ + delta |= ~OP_MASK_IMM10; + } + (*info->fprintf_func) (info->stream, "%d", delta << 3); + break; + case 'C': case 'H': msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD; @@ -3575,6 +4412,42 @@ print_insn_args (const char *d, (*info->fprintf_func) (info->stream, "0x%x", msbd + 1); break; + case 'o': + switch (*(d+1)) { + case '1': + d++; + delta = l & ((1 << 18) - 1); + if (delta & 0x20000) { + delta |= ~0x1ffff; + } + break; + case '2': + d++; + delta = l & ((1 << 19) - 1); + if (delta & 0x40000) { + delta |= ~0x3ffff; + } + break; + default: + delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6; + if (delta & 0x8000) { + delta |= ~0xffff; + } + } + + (*info->fprintf_func) (info->stream, "%d", delta); + break; + + case 'p': + /* Sign extend the displacement with 26 bits. */ + delta = (l >> OP_SH_DELTA) & OP_MASK_TARGET; + if (delta & 0x2000000) { + delta |= ~0x3FFFFFF; + } + info->target = (delta << 2) + pc + INSNLEN; + (*info->print_address_func) (info->target, info); + break; + case 't': /* Coprocessor 0 reg name */ (*info->fprintf_func) (info->stream, "%s", mips_cp0_names[(l >> OP_SH_RT) & @@ -3603,6 +4476,38 @@ print_insn_args (const char *d, break; } + case 'd': + (*info->fprintf_func) (info->stream, "%s", + mips_wr_names[(l >> OP_SH_FD) & OP_MASK_FD]); + break; + + case 'e': + (*info->fprintf_func) (info->stream, "%s", + mips_wr_names[(l >> OP_SH_FS) & OP_MASK_FS]); + break; + + case 'f': + (*info->fprintf_func) (info->stream, "%s", + mips_wr_names[(l >> OP_SH_FT) & OP_MASK_FT]); + break; + + case 'g': + (*info->fprintf_func) (info->stream, "%s", + mips_msa_control_names_mips3264r2[(l >> OP_SH_MSACR11) + & OP_MASK_MSACR11]); + break; + + case 'h': + (*info->fprintf_func) (info->stream, "%s", + mips_msa_control_names_mips3264r2[(l >> OP_SH_MSACR6) + & OP_MASK_MSACR6]); + break; + + case 'i': + (*info->fprintf_func) (info->stream, "%s", + mips_gpr_names[(l >> OP_SH_GPR) & OP_MASK_GPR]); + break; + default: /* xgettext:c-format */ (*info->fprintf_func) (info->stream, @@ -3726,7 +4631,8 @@ print_insn_args (const char *d, case 'j': /* Same as i, but sign-extended. */ case 'o': - delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; + delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA; + if (delta & 0x8000) delta |= ~0xffff; (*info->fprintf_func) (info->stream, "%d", @@ -4052,6 +4958,23 @@ print_insn_mips (bfd_vma memaddr, && strcmp (op->name, "jalx")) continue; + if (strcmp(op->name, "bovc") == 0 + || strcmp(op->name, "bnvc") == 0) { + if (((word >> OP_SH_RS) & OP_MASK_RS) < + ((word >> OP_SH_RT) & OP_MASK_RT)) { + continue; + } + } + if (strcmp(op->name, "bgezc") == 0 + || strcmp(op->name, "bltzc") == 0 + || strcmp(op->name, "bgezalc") == 0 + || strcmp(op->name, "bltzalc") == 0) { + if (((word >> OP_SH_RS) & OP_MASK_RS) != + ((word >> OP_SH_RT) & OP_MASK_RT)) { + continue; + } + } + /* Figure out instruction type and branch delay information. */ if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0) { diff --git a/disas/sparc.c b/disas/sparc.c index 8eb22e6fc..8e755d1ba 100644 --- a/disas/sparc.c +++ b/disas/sparc.c @@ -1175,15 +1175,11 @@ static const struct sparc_opcode sparc_opcodes[] = { { "subcc", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|ASI(~0), "1,2,d", 0, v6 }, { "subcc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "1,i,d", 0, v6 }, -{ "subx", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, -{ "subx", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v6notv9 }, -{ "subc", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v9 }, -{ "subc", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v9 }, +{ "subc", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "subc", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v6 }, -{ "subxcc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, -{ "subxcc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v6notv9 }, -{ "subccc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v9 }, -{ "subccc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v9 }, +{ "subccc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "subccc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v6 }, { "and", F3(2, 0x01, 0), F3(~2, ~0x01, ~0)|ASI(~0), "1,2,d", 0, v6 }, { "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "1,i,d", 0, v6 }, @@ -1215,19 +1211,13 @@ static const struct sparc_opcode sparc_opcodes[] = { { "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "1,i,d", 0, v6 }, { "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,1,d", 0, v6 }, -{ "addx", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, -{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v6notv9 }, -{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v6notv9 }, -{ "addc", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v9 }, -{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v9 }, -{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v9 }, +{ "addc", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v6 }, +{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v6 }, -{ "addxcc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v6notv9 }, -{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v6notv9 }, -{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v6notv9 }, -{ "addccc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v9 }, -{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v9 }, -{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v9 }, +{ "addccc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v6 }, +{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v6 }, +{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v6 }, { "smul", F3(2, 0x0b, 0), F3(~2, ~0x0b, ~0)|ASI(~0), "1,2,d", 0, v8 }, { "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "1,i,d", 0, v8 }, @@ -2042,6 +2032,10 @@ IMPDEP ("impdep2", 0x37), #undef IMPDEP +{ "addxc", F3F(2, 0x36, 0x011), F3F(~2, ~0x36, ~0x011), "1,2,d", 0, v9b }, +{ "addxccc", F3F(2, 0x36, 0x013), F3F(~2, ~0x36, ~0x013), "1,2,d", 0, v9b }, +{ "umulxhi", F3F(2, 0x36, 0x016), F3F(~2, ~0x36, ~0x016), "1,2,d", 0, v9b }, + }; static const int sparc_num_opcodes = ((sizeof sparc_opcodes)/(sizeof sparc_opcodes[0])); |