X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FTarget%2FMips%2FDisassembler%2FMipsDisassembler.cpp;h=118c3b0b293dacc06d5d1a6d557f24118ced617d;hp=a543840132367e2824792d6c8e48e1dcab52b4ce;hb=18700de8fc1c8d772969a877ec36e7a67212ce67;hpb=2a80d7db79f9ed8744101eb8a47a86aa482f7c52 diff --git a/lib/Target/Mips/Disassembler/MipsDisassembler.cpp b/lib/Target/Mips/Disassembler/MipsDisassembler.cpp index a5438401323..118c3b0b293 100644 --- a/lib/Target/Mips/Disassembler/MipsDisassembler.cpp +++ b/lib/Target/Mips/Disassembler/MipsDisassembler.cpp @@ -14,81 +14,80 @@ #include "Mips.h" #include "MipsRegisterInfo.h" #include "MipsSubtarget.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler.h" #include "llvm/MC/MCFixedLenDisassembler.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/MathExtras.h" -#include "llvm/Support/MemoryObject.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; +#define DEBUG_TYPE "mips-disassembler" + typedef MCDisassembler::DecodeStatus DecodeStatus; namespace { -/// MipsDisassemblerBase - a disasembler class for Mips. +/// A disasembler class for Mips. class MipsDisassemblerBase : public MCDisassembler { public: - /// Constructor - Initializes the disassembler. - /// - MipsDisassemblerBase(const MCSubtargetInfo &STI, const MCRegisterInfo *Info, - bool bigEndian) : - MCDisassembler(STI), RegInfo(Info), - IsN64(STI.getFeatureBits() & Mips::FeatureN64), isBigEndian(bigEndian) {} + MipsDisassemblerBase(const MCSubtargetInfo &STI, MCContext &Ctx, + bool IsBigEndian) + : MCDisassembler(STI, Ctx), + IsN64(STI.getFeatureBits() & Mips::FeatureN64), + IsBigEndian(IsBigEndian) {} virtual ~MipsDisassemblerBase() {} - const MCRegisterInfo *getRegInfo() const { return RegInfo.get(); } - bool isN64() const { return IsN64; } private: - OwningPtr RegInfo; bool IsN64; protected: - bool isBigEndian; + bool IsBigEndian; }; -/// MipsDisassembler - a disasembler class for Mips32. +/// A disasembler class for Mips32. class MipsDisassembler : public MipsDisassemblerBase { bool IsMicroMips; public: - /// Constructor - Initializes the disassembler. - /// - MipsDisassembler(const MCSubtargetInfo &STI, const MCRegisterInfo *Info, - bool bigEndian) : - MipsDisassemblerBase(STI, Info, bigEndian) { - IsMicroMips = STI.getFeatureBits() & Mips::FeatureMicroMips; - } + MipsDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool bigEndian) + : MipsDisassemblerBase(STI, Ctx, bigEndian) { + IsMicroMips = STI.getFeatureBits() & Mips::FeatureMicroMips; + } - /// getInstruction - See MCDisassembler. - virtual DecodeStatus getInstruction(MCInst &instr, - uint64_t &size, - const MemoryObject ®ion, - uint64_t address, - raw_ostream &vStream, - raw_ostream &cStream) const; -}; + bool hasMips3() const { return STI.getFeatureBits() & Mips::FeatureMips3; } + bool hasMips32() const { return STI.getFeatureBits() & Mips::FeatureMips32; } + bool hasMips32r6() const { + return STI.getFeatureBits() & Mips::FeatureMips32r6; + } + + bool isGP64() const { return STI.getFeatureBits() & Mips::FeatureGP64Bit; } + bool hasCOP3() const { + // Only present in MIPS-I and MIPS-II + return !hasMips32() && !hasMips3(); + } + + DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef Bytes, uint64_t Address, + raw_ostream &VStream, + raw_ostream &CStream) const override; +}; -/// Mips64Disassembler - a disasembler class for Mips64. +/// A disasembler class for Mips64. class Mips64Disassembler : public MipsDisassemblerBase { public: - /// Constructor - Initializes the disassembler. - /// - Mips64Disassembler(const MCSubtargetInfo &STI, const MCRegisterInfo *Info, + Mips64Disassembler(const MCSubtargetInfo &STI, MCContext &Ctx, bool bigEndian) : - MipsDisassemblerBase(STI, Info, bigEndian) {} - - /// getInstruction - See MCDisassembler. - virtual DecodeStatus getInstruction(MCInst &instr, - uint64_t &size, - const MemoryObject ®ion, - uint64_t address, - raw_ostream &vStream, - raw_ostream &cStream) const; + MipsDisassemblerBase(STI, Ctx, bigEndian) {} + + DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef Bytes, uint64_t Address, + raw_ostream &VStream, + raw_ostream &CStream) const override; }; } // end anonymous namespace @@ -105,6 +104,11 @@ static DecodeStatus DecodeCPU16RegsRegisterClass(MCInst &Inst, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeGPRMM16RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + static DecodeStatus DecodeGPR32RegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, @@ -130,11 +134,6 @@ static DecodeStatus DecodeFGR32RegisterClass(MCInst &Inst, uint64_t Address, const void *Decoder); -static DecodeStatus DecodeFGRH32RegisterClass(MCInst &Inst, - unsigned RegNo, - uint64_t Address, - const void *Decoder); - static DecodeStatus DecodeCCRRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, @@ -145,6 +144,10 @@ static DecodeStatus DecodeFCCRegisterClass(MCInst &Inst, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeFGRCCRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, + const void *Decoder); + static DecodeStatus DecodeHWRegsRegisterClass(MCInst &Inst, unsigned Insn, uint64_t Address, @@ -195,6 +198,11 @@ static DecodeStatus DecodeMSACtrlRegisterClass(MCInst &Inst, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeCOP2RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + static DecodeStatus DecodeBranchTarget(MCInst &Inst, unsigned Offset, uint64_t Address, @@ -205,6 +213,16 @@ static DecodeStatus DecodeJumpTarget(MCInst &Inst, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeBranchTarget21(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeBranchTarget26(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + // DecodeBranchTargetMM - Decode microMIPS branch offset, which is // shifted left by 1 bit. static DecodeStatus DecodeBranchTargetMM(MCInst &Inst, @@ -224,6 +242,11 @@ static DecodeStatus DecodeMem(MCInst &Inst, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeCacheOp(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + static DecodeStatus DecodeMSA128Mem(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); @@ -241,6 +264,19 @@ static DecodeStatus DecodeFMem(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeFMem2(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFMem3(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeSpecial3LlSc(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + static DecodeStatus DecodeSimm16(MCInst &Inst, unsigned Insn, uint64_t Address, @@ -263,6 +299,52 @@ static DecodeStatus DecodeExtSize(MCInst &Inst, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeSimm19Lsl2(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +static DecodeStatus DecodeSimm18Lsl3(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +/// INSVE_[BHWD] have an implicit operand that the generated decoder doesn't +/// handle. +template +static DecodeStatus DecodeINSVE_DF(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template +static DecodeStatus +DecodeAddiGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template +static DecodeStatus +DecodeDaddiGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template +static DecodeStatus +DecodeBlezlGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template +static DecodeStatus +DecodeBgtzlGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template +static DecodeStatus +DecodeBgtzGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +template +static DecodeStatus +DecodeBlezGroupBranch(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeRegListOperand(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + namespace llvm { extern Target TheMipselTarget, TheMipsTarget, TheMips64Target, TheMips64elTarget; @@ -270,26 +352,30 @@ extern Target TheMipselTarget, TheMipsTarget, TheMips64Target, static MCDisassembler *createMipsDisassembler( const Target &T, - const MCSubtargetInfo &STI) { - return new MipsDisassembler(STI, T.createMCRegInfo(""), true); + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new MipsDisassembler(STI, Ctx, true); } static MCDisassembler *createMipselDisassembler( const Target &T, - const MCSubtargetInfo &STI) { - return new MipsDisassembler(STI, T.createMCRegInfo(""), false); + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new MipsDisassembler(STI, Ctx, false); } static MCDisassembler *createMips64Disassembler( const Target &T, - const MCSubtargetInfo &STI) { - return new Mips64Disassembler(STI, T.createMCRegInfo(""), true); + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new Mips64Disassembler(STI, Ctx, true); } static MCDisassembler *createMips64elDisassembler( const Target &T, - const MCSubtargetInfo &STI) { - return new Mips64Disassembler(STI, T.createMCRegInfo(""), false); + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new Mips64Disassembler(STI, Ctx, false); } extern "C" void LLVMInitializeMipsDisassembler() { @@ -304,46 +390,365 @@ extern "C" void LLVMInitializeMipsDisassembler() { createMips64elDisassembler); } - #include "MipsGenDisassemblerTables.inc" - /// readInstruction - read four bytes from the MemoryObject - /// and return 32 bit word sorted according to the given endianess -static DecodeStatus readInstruction32(const MemoryObject ®ion, - uint64_t address, - uint64_t &size, - uint32_t &insn, - bool isBigEndian, - bool IsMicroMips) { - uint8_t Bytes[4]; +static unsigned getReg(const void *D, unsigned RC, unsigned RegNo) { + const MipsDisassemblerBase *Dis = static_cast(D); + const MCRegisterInfo *RegInfo = Dis->getContext().getRegisterInfo(); + return *(RegInfo->getRegClass(RC).begin() + RegNo); +} - // We want to read exactly 4 Bytes of data. - if (region.readBytes(address, 4, Bytes) == -1) { - size = 0; +template +static DecodeStatus DecodeINSVE_DF(MCInst &MI, InsnType insn, uint64_t Address, + const void *Decoder) { + typedef DecodeStatus (*DecodeFN)(MCInst &, unsigned, uint64_t, const void *); + // The size of the n field depends on the element size + // The register class also depends on this. + InsnType tmp = fieldFromInstruction(insn, 17, 5); + unsigned NSize = 0; + DecodeFN RegDecoder = nullptr; + if ((tmp & 0x18) == 0x00) { // INSVE_B + NSize = 4; + RegDecoder = DecodeMSA128BRegisterClass; + } else if ((tmp & 0x1c) == 0x10) { // INSVE_H + NSize = 3; + RegDecoder = DecodeMSA128HRegisterClass; + } else if ((tmp & 0x1e) == 0x18) { // INSVE_W + NSize = 2; + RegDecoder = DecodeMSA128WRegisterClass; + } else if ((tmp & 0x1f) == 0x1c) { // INSVE_D + NSize = 1; + RegDecoder = DecodeMSA128DRegisterClass; + } else + llvm_unreachable("Invalid encoding"); + + assert(NSize != 0 && RegDecoder != nullptr); + + // $wd + tmp = fieldFromInstruction(insn, 6, 5); + if (RegDecoder(MI, tmp, Address, Decoder) == MCDisassembler::Fail) + return MCDisassembler::Fail; + // $wd_in + if (RegDecoder(MI, tmp, Address, Decoder) == MCDisassembler::Fail) + return MCDisassembler::Fail; + // $n + tmp = fieldFromInstruction(insn, 16, NSize); + MI.addOperand(MCOperand::CreateImm(tmp)); + // $ws + tmp = fieldFromInstruction(insn, 11, 5); + if (RegDecoder(MI, tmp, Address, Decoder) == MCDisassembler::Fail) return MCDisassembler::Fail; + // $n2 + MI.addOperand(MCOperand::CreateImm(0)); + + return MCDisassembler::Success; +} + +template +static DecodeStatus DecodeAddiGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the ADDI instruction from the earlier + // ISA's instead). + // + // We have: + // 0b001000 sssss ttttt iiiiiiiiiiiiiiii + // BOVC if rs >= rt + // BEQZALC if rs == 0 && rt != 0 + // BEQC if rs < rt && rs != 0 + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4; + bool HasRs = false; + + if (Rs >= Rt) { + MI.setOpcode(Mips::BOVC); + HasRs = true; + } else if (Rs != 0 && Rs < Rt) { + MI.setOpcode(Mips::BEQC); + HasRs = true; + } else + MI.setOpcode(Mips::BEQZALC); + + if (HasRs) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + MI.addOperand(MCOperand::CreateImm(Imm)); + + return MCDisassembler::Success; +} + +template +static DecodeStatus DecodeDaddiGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the ADDI instruction from the earlier + // ISA's instead). + // + // We have: + // 0b011000 sssss ttttt iiiiiiiiiiiiiiii + // BNVC if rs >= rt + // BNEZALC if rs == 0 && rt != 0 + // BNEC if rs < rt && rs != 0 + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4; + bool HasRs = false; + + if (Rs >= Rt) { + MI.setOpcode(Mips::BNVC); + HasRs = true; + } else if (Rs != 0 && Rs < Rt) { + MI.setOpcode(Mips::BNEC); + HasRs = true; + } else + MI.setOpcode(Mips::BNEZALC); + + if (HasRs) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + MI.addOperand(MCOperand::CreateImm(Imm)); + + return MCDisassembler::Success; +} + +template +static DecodeStatus DecodeBlezlGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the BLEZL instruction from the earlier + // ISA's instead). + // + // We have: + // 0b010110 sssss ttttt iiiiiiiiiiiiiiii + // Invalid if rs == 0 + // BLEZC if rs == 0 && rt != 0 + // BGEZC if rs == rt && rt != 0 + // BGEC if rs != rt && rs != 0 && rt != 0 + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4; + bool HasRs = false; + + if (Rt == 0) + return MCDisassembler::Fail; + else if (Rs == 0) + MI.setOpcode(Mips::BLEZC); + else if (Rs == Rt) + MI.setOpcode(Mips::BGEZC); + else { + HasRs = true; + MI.setOpcode(Mips::BGEC); } - if (isBigEndian) { - // Encoded as a big-endian 32-bit word in the stream. - insn = (Bytes[3] << 0) | - (Bytes[2] << 8) | - (Bytes[1] << 16) | - (Bytes[0] << 24); + if (HasRs) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + + MI.addOperand(MCOperand::CreateImm(Imm)); + + return MCDisassembler::Success; +} + +template +static DecodeStatus DecodeBgtzlGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the BGTZL instruction from the earlier + // ISA's instead). + // + // We have: + // 0b010111 sssss ttttt iiiiiiiiiiiiiiii + // Invalid if rs == 0 + // BGTZC if rs == 0 && rt != 0 + // BLTZC if rs == rt && rt != 0 + // BLTC if rs != rt && rs != 0 && rt != 0 + + bool HasRs = false; + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4; + + if (Rt == 0) + return MCDisassembler::Fail; + else if (Rs == 0) + MI.setOpcode(Mips::BGTZC); + else if (Rs == Rt) + MI.setOpcode(Mips::BLTZC); + else { + MI.setOpcode(Mips::BLTC); + HasRs = true; } + + if (HasRs) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + + MI.addOperand(MCOperand::CreateImm(Imm)); + + return MCDisassembler::Success; +} + +template +static DecodeStatus DecodeBgtzGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the BGTZ instruction from the earlier + // ISA's instead). + // + // We have: + // 0b000111 sssss ttttt iiiiiiiiiiiiiiii + // BGTZ if rt == 0 + // BGTZALC if rs == 0 && rt != 0 + // BLTZALC if rs != 0 && rs == rt + // BLTUC if rs != 0 && rs != rt + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4; + bool HasRs = false; + bool HasRt = false; + + if (Rt == 0) { + MI.setOpcode(Mips::BGTZ); + HasRs = true; + } else if (Rs == 0) { + MI.setOpcode(Mips::BGTZALC); + HasRt = true; + } else if (Rs == Rt) { + MI.setOpcode(Mips::BLTZALC); + HasRs = true; + } else { + MI.setOpcode(Mips::BLTUC); + HasRs = true; + HasRt = true; + } + + if (HasRs) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + + if (HasRt) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + + MI.addOperand(MCOperand::CreateImm(Imm)); + + return MCDisassembler::Success; +} + +template +static DecodeStatus DecodeBlezGroupBranch(MCInst &MI, InsnType insn, + uint64_t Address, + const void *Decoder) { + // If we are called then we can assume that MIPS32r6/MIPS64r6 is enabled + // (otherwise we would have matched the BLEZL instruction from the earlier + // ISA's instead). + // + // We have: + // 0b000110 sssss ttttt iiiiiiiiiiiiiiii + // Invalid if rs == 0 + // BLEZALC if rs == 0 && rt != 0 + // BGEZALC if rs == rt && rt != 0 + // BGEUC if rs != rt && rs != 0 && rt != 0 + + InsnType Rs = fieldFromInstruction(insn, 21, 5); + InsnType Rt = fieldFromInstruction(insn, 16, 5); + InsnType Imm = SignExtend64(fieldFromInstruction(insn, 0, 16), 16) * 4; + bool HasRs = false; + + if (Rt == 0) + return MCDisassembler::Fail; + else if (Rs == 0) + MI.setOpcode(Mips::BLEZALC); + else if (Rs == Rt) + MI.setOpcode(Mips::BGEZALC); else { - // Encoded as a small-endian 32-bit word in the stream. - // Little-endian byte ordering: - // mips32r2: 4 | 3 | 2 | 1 - // microMIPS: 2 | 1 | 4 | 3 + HasRs = true; + MI.setOpcode(Mips::BGEUC); + } + + if (HasRs) + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rs))); + MI.addOperand(MCOperand::CreateReg(getReg(Decoder, Mips::GPR32RegClassID, + Rt))); + + MI.addOperand(MCOperand::CreateImm(Imm)); + + return MCDisassembler::Success; +} + +/// Read two bytes from the ArrayRef and return 16 bit halfword sorted +/// according to the given endianess. +static DecodeStatus readInstruction16(ArrayRef Bytes, uint64_t Address, + uint64_t &Size, uint32_t &Insn, + bool IsBigEndian) { + // We want to read exactly 2 Bytes of data. + if (Bytes.size() < 2) { + Size = 0; + return MCDisassembler::Fail; + } + + if (IsBigEndian) { + Insn = (Bytes[0] << 8) | Bytes[1]; + } else { + Insn = (Bytes[1] << 8) | Bytes[0]; + } + + return MCDisassembler::Success; +} + +/// Read four bytes from the ArrayRef and return 32 bit word sorted +/// according to the given endianess +static DecodeStatus readInstruction32(ArrayRef Bytes, uint64_t Address, + uint64_t &Size, uint32_t &Insn, + bool IsBigEndian, bool IsMicroMips) { + // We want to read exactly 4 Bytes of data. + if (Bytes.size() < 4) { + Size = 0; + return MCDisassembler::Fail; + } + + // High 16 bits of a 32-bit microMIPS instruction (where the opcode is) + // always precede the low 16 bits in the instruction stream (that is, they + // are placed at lower addresses in the instruction stream). + // + // microMIPS byte ordering: + // Big-endian: 0 | 1 | 2 | 3 + // Little-endian: 1 | 0 | 3 | 2 + + if (IsBigEndian) { + // Encoded as a big-endian 32-bit word in the stream. + Insn = + (Bytes[3] << 0) | (Bytes[2] << 8) | (Bytes[1] << 16) | (Bytes[0] << 24); + } else { if (IsMicroMips) { - insn = (Bytes[2] << 0) | - (Bytes[3] << 8) | - (Bytes[0] << 16) | + Insn = (Bytes[2] << 0) | (Bytes[3] << 8) | (Bytes[0] << 16) | (Bytes[1] << 24); } else { - insn = (Bytes[0] << 0) | - (Bytes[1] << 8) | - (Bytes[2] << 16) | + Insn = (Bytes[0] << 0) | (Bytes[1] << 8) | (Bytes[2] << 16) | (Bytes[3] << 24); } } @@ -351,23 +756,33 @@ static DecodeStatus readInstruction32(const MemoryObject ®ion, return MCDisassembler::Success; } -DecodeStatus -MipsDisassembler::getInstruction(MCInst &instr, - uint64_t &Size, - const MemoryObject &Region, - uint64_t Address, - raw_ostream &vStream, - raw_ostream &cStream) const { +DecodeStatus MipsDisassembler::getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef Bytes, + uint64_t Address, + raw_ostream &VStream, + raw_ostream &CStream) const { uint32_t Insn; - - DecodeStatus Result = readInstruction32(Region, Address, Size, - Insn, isBigEndian, IsMicroMips); - if (Result == MCDisassembler::Fail) - return MCDisassembler::Fail; + DecodeStatus Result; if (IsMicroMips) { + Result = readInstruction16(Bytes, Address, Size, Insn, IsBigEndian); + + DEBUG(dbgs() << "Trying MicroMips16 table (16-bit instructions):\n"); + // Calling the auto-generated decoder function. + Result = decodeInstruction(DecoderTableMicroMips16, Instr, Insn, Address, + this, STI); + if (Result != MCDisassembler::Fail) { + Size = 2; + return Result; + } + + Result = readInstruction32(Bytes, Address, Size, Insn, IsBigEndian, true); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + + DEBUG(dbgs() << "Trying MicroMips32 table (32-bit instructions):\n"); // Calling the auto-generated decoder function. - Result = decodeInstruction(DecoderTableMicroMips32, instr, Insn, Address, + Result = decodeInstruction(DecoderTableMicroMips32, Instr, Insn, Address, this, STI); if (Result != MCDisassembler::Fail) { Size = 4; @@ -376,9 +791,44 @@ MipsDisassembler::getInstruction(MCInst &instr, return MCDisassembler::Fail; } + Result = readInstruction32(Bytes, Address, Size, Insn, IsBigEndian, false); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + + if (hasCOP3()) { + DEBUG(dbgs() << "Trying COP3_ table (32-bit opcodes):\n"); + Result = + decodeInstruction(DecoderTableCOP3_32, Instr, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + } + + if (hasMips32r6() && isGP64()) { + DEBUG(dbgs() << "Trying Mips32r6_64r6 (GPR64) table (32-bit opcodes):\n"); + Result = decodeInstruction(DecoderTableMips32r6_64r6_GP6432, Instr, Insn, + Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + } + + if (hasMips32r6()) { + DEBUG(dbgs() << "Trying Mips32r6_64r6 table (32-bit opcodes):\n"); + Result = decodeInstruction(DecoderTableMips32r6_64r632, Instr, Insn, + Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + } + + DEBUG(dbgs() << "Trying Mips table (32-bit opcodes):\n"); // Calling the auto-generated decoder function. - Result = decodeInstruction(DecoderTableMips32, instr, Insn, Address, - this, STI); + Result = + decodeInstruction(DecoderTableMips32, Instr, Insn, Address, this, STI); if (Result != MCDisassembler::Fail) { Size = 4; return Result; @@ -387,30 +837,28 @@ MipsDisassembler::getInstruction(MCInst &instr, return MCDisassembler::Fail; } -DecodeStatus -Mips64Disassembler::getInstruction(MCInst &instr, - uint64_t &Size, - const MemoryObject &Region, - uint64_t Address, - raw_ostream &vStream, - raw_ostream &cStream) const { +DecodeStatus Mips64Disassembler::getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef Bytes, + uint64_t Address, + raw_ostream &VStream, + raw_ostream &CStream) const { uint32_t Insn; - DecodeStatus Result = readInstruction32(Region, Address, Size, - Insn, isBigEndian, false); + DecodeStatus Result = + readInstruction32(Bytes, Address, Size, Insn, IsBigEndian, false); if (Result == MCDisassembler::Fail) return MCDisassembler::Fail; // Calling the auto-generated decoder function. - Result = decodeInstruction(DecoderTableMips6432, instr, Insn, Address, - this, STI); + Result = + decodeInstruction(DecoderTableMips6432, Instr, Insn, Address, this, STI); if (Result != MCDisassembler::Fail) { Size = 4; return Result; } // If we fail to decode in Mips64 decoder space we can try in Mips32 - Result = decodeInstruction(DecoderTableMips32, instr, Insn, Address, - this, STI); + Result = + decodeInstruction(DecoderTableMips32, Instr, Insn, Address, this, STI); if (Result != MCDisassembler::Fail) { Size = 4; return Result; @@ -419,11 +867,6 @@ Mips64Disassembler::getInstruction(MCInst &instr, return MCDisassembler::Fail; } -static unsigned getReg(const void *D, unsigned RC, unsigned RegNo) { - const MipsDisassemblerBase *Dis = static_cast(D); - return *(Dis->getRegInfo()->getRegClass(RC).begin() + RegNo); -} - static DecodeStatus DecodeCPU16RegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, @@ -446,6 +889,17 @@ static DecodeStatus DecodeGPR64RegisterClass(MCInst &Inst, return MCDisassembler::Success; } +static DecodeStatus DecodeGPRMM16RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 7) + return MCDisassembler::Fail; + unsigned Reg = getReg(Decoder, Mips::GPRMM16RegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + static DecodeStatus DecodeGPR32RegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, @@ -498,18 +952,6 @@ static DecodeStatus DecodeFGR32RegisterClass(MCInst &Inst, return MCDisassembler::Success; } -static DecodeStatus DecodeFGRH32RegisterClass(MCInst &Inst, - unsigned RegNo, - uint64_t Address, - const void *Decoder) { - if (RegNo > 31) - return MCDisassembler::Fail; - - unsigned Reg = getReg(Decoder, Mips::FGRH32RegClassID, RegNo); - Inst.addOperand(MCOperand::CreateReg(Reg)); - return MCDisassembler::Success; -} - static DecodeStatus DecodeCCRRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, @@ -532,6 +974,17 @@ static DecodeStatus DecodeFCCRegisterClass(MCInst &Inst, return MCDisassembler::Success; } +static DecodeStatus DecodeFGRCCRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::FGRCCRegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + static DecodeStatus DecodeMem(MCInst &Inst, unsigned Insn, uint64_t Address, @@ -554,6 +1007,23 @@ static DecodeStatus DecodeMem(MCInst &Inst, return MCDisassembler::Success; } +static DecodeStatus DecodeCacheOp(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Hint = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + Inst.addOperand(MCOperand::CreateImm(Hint)); + + return MCDisassembler::Success; +} + static DecodeStatus DecodeMSA128Mem(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder) { int Offset = SignExtend32<10>(fieldFromInstruction(Insn, 16, 10)); @@ -585,15 +1055,15 @@ static DecodeStatus DecodeMSA128Mem(MCInst &Inst, unsigned Insn, break; case Mips::LD_H: case Mips::ST_H: - Inst.addOperand(MCOperand::CreateImm(Offset << 1)); + Inst.addOperand(MCOperand::CreateImm(Offset * 2)); break; case Mips::LD_W: case Mips::ST_W: - Inst.addOperand(MCOperand::CreateImm(Offset << 2)); + Inst.addOperand(MCOperand::CreateImm(Offset * 4)); break; case Mips::LD_D: case Mips::ST_D: - Inst.addOperand(MCOperand::CreateImm(Offset << 3)); + Inst.addOperand(MCOperand::CreateImm(Offset * 8)); break; } @@ -611,12 +1081,23 @@ static DecodeStatus DecodeMemMMImm12(MCInst &Inst, Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); Base = getReg(Decoder, Mips::GPR32RegClassID, Base); - if (Inst.getOpcode() == Mips::SC_MM) + switch (Inst.getOpcode()) { + case Mips::SWM32_MM: + case Mips::LWM32_MM: + if (DecodeRegListOperand(Inst, Insn, Address, Decoder) + == MCDisassembler::Fail) + return MCDisassembler::Fail; + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + break; + case Mips::SC_MM: Inst.addOperand(MCOperand::CreateReg(Reg)); - - Inst.addOperand(MCOperand::CreateReg(Reg)); - Inst.addOperand(MCOperand::CreateReg(Base)); - Inst.addOperand(MCOperand::CreateImm(Offset)); + // fallthrough + default: + Inst.addOperand(MCOperand::CreateReg(Reg)); + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + } return MCDisassembler::Success; } @@ -657,6 +1138,63 @@ static DecodeStatus DecodeFMem(MCInst &Inst, return MCDisassembler::Success; } +static DecodeStatus DecodeFMem2(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Reg = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Reg = getReg(Decoder, Mips::COP2RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::CreateReg(Reg)); + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeFMem3(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Reg = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Reg = getReg(Decoder, Mips::COP3RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::CreateReg(Reg)); + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeSpecial3LlSc(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int64_t Offset = SignExtend64<9>((Insn >> 7) & 0x1ff); + unsigned Rt = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Rt = getReg(Decoder, Mips::GPR32RegClassID, Rt); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + if(Inst.getOpcode() == Mips::SC_R6 || Inst.getOpcode() == Mips::SCD_R6){ + Inst.addOperand(MCOperand::CreateReg(Rt)); + } + + Inst.addOperand(MCOperand::CreateReg(Rt)); + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + + return MCDisassembler::Success; +} static DecodeStatus DecodeHWRegsRegisterClass(MCInst &Inst, unsigned RegNo, @@ -778,12 +1316,23 @@ static DecodeStatus DecodeMSACtrlRegisterClass(MCInst &Inst, return MCDisassembler::Success; } +static DecodeStatus DecodeCOP2RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::COP2RegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + static DecodeStatus DecodeBranchTarget(MCInst &Inst, unsigned Offset, uint64_t Address, const void *Decoder) { - unsigned BranchOffset = Offset & 0xffff; - BranchOffset = SignExtend32<18>(BranchOffset << 2) + 4; + int32_t BranchOffset = (SignExtend32<16>(Offset) * 4) + 4; Inst.addOperand(MCOperand::CreateImm(BranchOffset)); return MCDisassembler::Success; } @@ -798,12 +1347,31 @@ static DecodeStatus DecodeJumpTarget(MCInst &Inst, return MCDisassembler::Success; } +static DecodeStatus DecodeBranchTarget21(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + int32_t BranchOffset = SignExtend32<21>(Offset) * 4; + + Inst.addOperand(MCOperand::CreateImm(BranchOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeBranchTarget26(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + int32_t BranchOffset = SignExtend32<26>(Offset) * 4; + + Inst.addOperand(MCOperand::CreateImm(BranchOffset)); + return MCDisassembler::Success; +} + static DecodeStatus DecodeBranchTargetMM(MCInst &Inst, unsigned Offset, uint64_t Address, const void *Decoder) { - unsigned BranchOffset = Offset & 0xffff; - BranchOffset = SignExtend32<18>(BranchOffset << 1); + int32_t BranchOffset = SignExtend32<16>(Offset) * 2; Inst.addOperand(MCOperand::CreateImm(BranchOffset)); return MCDisassembler::Success; } @@ -853,3 +1421,38 @@ static DecodeStatus DecodeExtSize(MCInst &Inst, Inst.addOperand(MCOperand::CreateImm(SignExtend32<16>(Size))); return MCDisassembler::Success; } + +static DecodeStatus DecodeSimm19Lsl2(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + Inst.addOperand(MCOperand::CreateImm(SignExtend32<19>(Insn) * 4)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeSimm18Lsl3(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + Inst.addOperand(MCOperand::CreateImm(SignExtend32<18>(Insn) * 8)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeRegListOperand(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + unsigned Regs[] = {Mips::S0, Mips::S1, Mips::S2, Mips::S3, Mips::S4, Mips::S5, + Mips::S6, Mips::FP}; + unsigned RegNum; + + unsigned RegLst = fieldFromInstruction(Insn, 21, 5); + // Empty register lists are not allowed. + if (RegLst == 0) + return MCDisassembler::Fail; + + RegNum = RegLst & 0xf; + for (unsigned i = 0; i < RegNum; i++) + Inst.addOperand(MCOperand::CreateReg(Regs[i])); + + if (RegLst & 0x10) + Inst.addOperand(MCOperand::CreateReg(Mips::RA)); + + return MCDisassembler::Success; +}