diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
commit | 145449b1e420787bb99721a429341fa6be3adfb6 (patch) | |
tree | 1d56ae694a6de602e348dd80165cf881a36600ed /llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp | |
parent | ecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff) |
Diffstat (limited to 'llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp')
-rw-r--r-- | llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp | 618 |
1 files changed, 76 insertions, 542 deletions
diff --git a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp index a565ff4e004d..31b59c17c0ca 100644 --- a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp +++ b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp @@ -20,8 +20,11 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/MC/MCDecoderOps.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" using namespace llvm; @@ -29,581 +32,112 @@ using namespace llvm; typedef MCDisassembler::DecodeStatus DecodeStatus; -namespace { -constexpr unsigned MaxInstructionWords = 11; - -class M68kInstructionBuffer { - typedef SmallVector<uint16_t, MaxInstructionWords> BufferType; - BufferType Buffer; - -public: - M68kInstructionBuffer() {} - - template <typename TIt> - M68kInstructionBuffer(TIt Start, TIt End) : Buffer(Start, End) {} - - unsigned size() const { return Buffer.size(); } - - BufferType::const_iterator begin() const { return Buffer.begin(); } - BufferType::const_iterator end() const { return Buffer.end(); } - - uint16_t operator[](unsigned Index) const { - assert((Index < Buffer.size()) && "tried to read out of bounds word"); - return Buffer[Index]; - } - - void truncate(unsigned NewLength) { - assert((NewLength <= Buffer.size()) && - "instruction buffer too short to truncate"); - Buffer.resize(NewLength); - } - - void dump() const; - - static M68kInstructionBuffer fill(ArrayRef<uint8_t> Bytes); -}; - -class M68kInstructionReader { - M68kInstructionBuffer Buffer; - unsigned NumRead; - -public: - M68kInstructionReader(M68kInstructionBuffer Buf) : Buffer(Buf), NumRead(0) {} - - unsigned size() const { return (Buffer.size() * 16) - NumRead; } - - uint64_t readBits(unsigned NumBits); -}; - -struct M68kInstructionLookup { - unsigned OpCode; - M68kInstructionBuffer Mask; - M68kInstructionBuffer Value; - - unsigned size() const { return Mask.size(); } - - // Check whether this instruction could possibly match the given bytes. - bool matches(const M68kInstructionBuffer &Test) const; - void dump() const; -}; - -class M68kInstructionLookupBuilder { - std::array<uint16_t, MaxInstructionWords> Mask; - std::array<uint16_t, MaxInstructionWords> Value; - unsigned NumWritten; - -public: - M68kInstructionLookupBuilder() : NumWritten(0) { - Mask.fill(0); - Value.fill(0); - } - - unsigned numWords() const { - assert(!(NumWritten & 0xf) && "instructions must be whole words"); - return NumWritten >> 4; - } - - bool isValid() const; - M68kInstructionLookup build(unsigned OpCode); - void addBits(unsigned N, uint64_t Bits); - void skipBits(unsigned N); -}; - -/// A disassembler class for M68k. -class M68kDisassembler : public MCDisassembler { - MCInstrInfo *MCII; - std::vector<M68kInstructionLookup> Lookups; - -public: - M68kDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, - MCInstrInfo *MCII) - : MCDisassembler(STI, Ctx), MCII(MCII) { - buildBeadTable(); - } - virtual ~M68kDisassembler() {} - - void buildBeadTable(); - DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, - ArrayRef<uint8_t> Bytes, uint64_t Address, - raw_ostream &CStream) const override; - void decodeReg(MCInst &Instr, unsigned int Bead, - M68kInstructionReader &Reader, unsigned &Scratch) const; - void decodeImm(MCInst &Instr, unsigned int Bead, - M68kInstructionReader &Reader, unsigned &Scratch) const; - unsigned int getRegOperandIndex(MCInst &Instr, unsigned int Bead) const; - unsigned int getImmOperandIndex(MCInst &Instr, unsigned int Bead) const; -}; -} // namespace - -static unsigned RegisterDecode[] = { - M68k::A0, M68k::A1, M68k::A2, M68k::A3, M68k::A4, M68k::A5, - M68k::A6, M68k::SP, M68k::D0, M68k::D1, M68k::D2, M68k::D3, - M68k::D4, M68k::D5, M68k::D6, M68k::D7, +static const unsigned RegisterDecode[] = { + M68k::D0, M68k::D1, M68k::D2, M68k::D3, M68k::D4, M68k::D5, + M68k::D6, M68k::D7, M68k::A0, M68k::A1, M68k::A2, M68k::A3, + M68k::A4, M68k::A5, M68k::A6, M68k::SP, }; -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD -void M68kInstructionBuffer::dump() const { - for (auto Word : Buffer) { - for (unsigned B = 0; B < 16; ++B) { - uint16_t Bit = (1 << (16 - B - 1)); - unsigned IsClear = !(Word & Bit); - - if (B == 8) - dbgs() << " "; - - char Ch = IsClear ? '0' : '1'; - dbgs() << Ch; - } - - dbgs() << " "; - } - - dbgs() << "\n"; +static DecodeStatus DecodeRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, const void *Decoder) { + if (RegNo >= 16) + return DecodeStatus::Fail; + Inst.addOperand(MCOperand::createReg(RegisterDecode[RegNo])); + return DecodeStatus::Success; } -#endif - -M68kInstructionBuffer M68kInstructionBuffer::fill(ArrayRef<uint8_t> Bytes) { - SmallVector<uint16_t, MaxInstructionWords> Buffer; - Buffer.resize(std::min(Bytes.size() / 2, Buffer.max_size())); - - for (unsigned I = 0, E = Buffer.size(); I < E; ++I) { - unsigned Offset = I * 2; - uint64_t Hi = Bytes[Offset]; - uint64_t Lo = Bytes[Offset + 1]; - uint64_t Word = (Hi << 8) | Lo; - Buffer[I] = Word; - - LLVM_DEBUG( - errs() << format("Read word %x (%d)\n", (unsigned)Word, Buffer.size())); - } - - return M68kInstructionBuffer(Buffer.begin(), Buffer.end()); -} - -uint64_t M68kInstructionReader::readBits(unsigned NumBits) { - assert((size() >= NumBits) && "not enough bits to read"); - - // We have to read the bits in 16-bit chunks because we read them as - // 16-bit words but they're actually written in big-endian. If a read - // crosses a word boundary we have to be careful. - - uint64_t Value = 0; - unsigned BitsRead = 0; - - while (BitsRead < NumBits) { - unsigned AvailableThisWord = 16 - (NumRead & 0xf); - unsigned ToRead = std::min(NumBits, AvailableThisWord); - - unsigned WordIndex = NumRead >> 4; - uint64_t ThisWord = Buffer[WordIndex] >> (NumRead & 0xf); - uint64_t Mask = (1 << ToRead) - 1; - Value |= (ThisWord & Mask) << BitsRead; - NumRead += ToRead; - BitsRead += ToRead; - } - return Value; -} - -bool M68kInstructionLookup::matches(const M68kInstructionBuffer &Test) const { - if (Test.size() < Value.size()) - return false; - - for (unsigned I = 0, E = Value.size(); I < E; ++I) { - uint16_t Have = Test[I]; - uint16_t Need = Value[I]; - uint16_t WordMask = Mask[I]; - - if ((Have & WordMask) != Need) - return false; - } - - return true; -} - -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD -void M68kInstructionLookup::dump() const { - dbgs() << "M68kInstructionLookup " << OpCode << " "; - - for (unsigned I = 0, E = Mask.size(); I < E; ++I) { - uint16_t WordMask = Mask[I]; - uint16_t WordValue = Value[I]; - - for (unsigned B = 0; B < 16; ++B) { - uint16_t Bit = (1 << (15 - B)); - unsigned IsMasked = !(WordMask & Bit); - unsigned IsClear = !(WordValue & Bit); - - if (B == 8) - dbgs() << " "; - - char Ch = IsMasked ? '?' : (IsClear ? '0' : '1'); - dbgs() << Ch; - } - - dbgs() << " "; - } - dbgs() << "\n"; +static DecodeStatus DecodeDR32RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeRegisterClass(Inst, RegNo, Address, Decoder); } -#endif -bool M68kInstructionLookupBuilder::isValid() const { - for (unsigned I = 0, E = numWords(); I < E; ++I) - if (Mask[I]) - return true; - - return false; +static DecodeStatus DecodeDR16RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeRegisterClass(Inst, RegNo, Address, Decoder); } -M68kInstructionLookup M68kInstructionLookupBuilder::build(unsigned OpCode) { - unsigned NumWords = numWords(); - M68kInstructionBuffer MaskBuffer(Mask.begin(), Mask.begin() + NumWords); - M68kInstructionBuffer ValueBuffer(Value.begin(), Value.begin() + NumWords); - M68kInstructionLookup Ret; - Ret.OpCode = OpCode; - Ret.Mask = MaskBuffer; - Ret.Value = ValueBuffer; - return Ret; +static DecodeStatus DecodeDR8RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeRegisterClass(Inst, RegNo, Address, Decoder); } -void M68kInstructionLookupBuilder::addBits(unsigned N, uint64_t Bits) { - while (N > 0) { - unsigned WordIndex = NumWritten >> 4; - unsigned WordOffset = NumWritten & 0xf; - unsigned AvailableThisWord = 16 - WordOffset; - unsigned ToWrite = std::min(AvailableThisWord, N); - - uint16_t WordMask = (1 << ToWrite) - 1; - uint16_t BitsToWrite = Bits & WordMask; - - Value[WordIndex] |= (BitsToWrite << WordOffset); - Mask[WordIndex] |= (WordMask << WordOffset); - - Bits >>= ToWrite; - N -= ToWrite; - NumWritten += ToWrite; - } +static DecodeStatus DecodeAR32RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeRegisterClass(Inst, RegNo | 8ULL, Address, Decoder); } -void M68kInstructionLookupBuilder::skipBits(unsigned N) { NumWritten += N; } - -// This is a bit of a hack: we can't generate this table at table-gen time -// because some of the definitions are in our platform. -void M68kDisassembler::buildBeadTable() { - const unsigned NumInstr = M68k::INSTRUCTION_LIST_END; - Lookups.reserve(NumInstr); - - for (unsigned I = 0; I < NumInstr; ++I) { - M68kInstructionLookupBuilder Builder; - - for (const uint8_t *PartPtr = M68k::getMCInstrBeads(I); *PartPtr; - ++PartPtr) { - uint8_t Bead = *PartPtr; - unsigned Ext = Bead >> 4; - unsigned Op = Bead & 0xf; - - switch (Op) { - case M68kBeads::Ctrl: - // Term will have already been skipped by the loop. - assert((Ext == M68kBeads::Ignore) && "unexpected command bead"); - break; - - case M68kBeads::Bits1: - Builder.addBits(1, Ext); - break; - - case M68kBeads::Bits2: - Builder.addBits(2, Ext); - break; - - case M68kBeads::Bits3: - Builder.addBits(3, Ext); - break; - - case M68kBeads::Bits4: - Builder.addBits(4, Ext); - break; - - case M68kBeads::DAReg: - case M68kBeads::DA: - case M68kBeads::DReg: - case M68kBeads::Reg: - if (Op != M68kBeads::DA) - Builder.skipBits(3); - - if (Op != M68kBeads::Reg && Op != M68kBeads::DReg) - Builder.skipBits(1); - - break; - - case M68kBeads::Disp8: - Builder.skipBits(8); - break; - - case M68kBeads::Imm8: - case M68kBeads::Imm16: - Builder.skipBits(16); - break; - - case M68kBeads::Imm32: - Builder.skipBits(32); - break; - - case M68kBeads::Imm3: - Builder.skipBits(3); - break; - - default: - llvm_unreachable("unhandled bead type"); - } - } - - // Ignore instructions which are unmatchable (usually pseudo instructions). - if (!Builder.isValid()) - continue; - - Lookups.push_back(Builder.build(I)); - } +static DecodeStatus DecodeAR16RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeRegisterClass(Inst, RegNo | 8ULL, Address, Decoder); } -unsigned M68kDisassembler::getRegOperandIndex(MCInst &Instr, - unsigned Bead) const { - unsigned Ext = Bead >> 4; - - const MCInstrDesc &Desc = MCII->get(Instr.getOpcode()); - auto MIOpIdx = M68k::getLogicalOperandIdx(Instr.getOpcode(), Ext & 7); - - if (M68kII::hasMultiMIOperands(Instr.getOpcode(), Ext & 7)) { - bool IsPCRel = Desc.OpInfo[MIOpIdx].OperandType == MCOI::OPERAND_PCREL; - if (IsPCRel) - MIOpIdx += M68k::PCRelIndex; - else if (Ext & 8) - MIOpIdx += M68k::MemIndex; - else - MIOpIdx += M68k::MemBase; - } - - return MIOpIdx; +static DecodeStatus DecodeXR32RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeRegisterClass(Inst, RegNo, Address, Decoder); } -unsigned M68kDisassembler::getImmOperandIndex(MCInst &Instr, - unsigned Bead) const { - unsigned Ext = Bead >> 4; - - const MCInstrDesc &Desc = MCII->get(Instr.getOpcode()); - auto MIOpIdx = M68k::getLogicalOperandIdx(Instr.getOpcode(), Ext & 7); - - if (M68kII::hasMultiMIOperands(Instr.getOpcode(), Ext & 7)) { - bool IsPCRel = Desc.OpInfo[MIOpIdx].OperandType == MCOI::OPERAND_PCREL; - if (IsPCRel) - MIOpIdx += M68k::PCRelDisp; - else if (Ext & 8) - MIOpIdx += M68k::MemOuter; - else - MIOpIdx += M68k::MemDisp; - } - - return MIOpIdx; +static DecodeStatus DecodeXR16RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeRegisterClass(Inst, RegNo, Address, Decoder); } -void M68kDisassembler::decodeReg(MCInst &Instr, unsigned Bead, - M68kInstructionReader &Reader, - unsigned &Scratch) const { - unsigned Op = Bead & 0xf; - LLVM_DEBUG(errs() << format("decodeReg %x\n", Bead)); - - if (Op != M68kBeads::DA) - Scratch = (Scratch & ~7) | Reader.readBits(3); - - if (Op != M68kBeads::Reg) { - bool DA = (Op != M68kBeads::DReg) && Reader.readBits(1); - if (!DA) - Scratch |= 8; - else - Scratch &= ~8; - } +static DecodeStatus DecodeCCRCRegisterClass(MCInst &Inst, APInt &Insn, + uint64_t Address, + const void *Decoder) { + llvm_unreachable("unimplemented"); } -void M68kDisassembler::decodeImm(MCInst &Instr, unsigned Bead, - M68kInstructionReader &Reader, - unsigned &Scratch) const { - unsigned Op = Bead & 0xf; - LLVM_DEBUG(errs() << format("decodeImm %x\n", Bead)); +#include "M68kGenDisassemblerTable.inc" - unsigned NumToRead; - switch (Op) { - case M68kBeads::Disp8: - NumToRead = 8; - break; - case M68kBeads::Imm8: - case M68kBeads::Imm16: - NumToRead = 16; - break; - case M68kBeads::Imm32: - NumToRead = 32; - break; - case M68kBeads::Imm3: - NumToRead = 3; - break; - default: - llvm_unreachable("invalid imm"); - } +/// A disassembler class for M68k. +struct M68kDisassembler : public MCDisassembler { + M68kDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) + : MCDisassembler(STI, Ctx) {} + virtual ~M68kDisassembler() {} - Scratch = (NumToRead < 32) ? (Scratch << NumToRead) : 0; - Scratch |= Reader.readBits(NumToRead); -} + DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef<uint8_t> Bytes, uint64_t Address, + raw_ostream &CStream) const override; +}; DecodeStatus M68kDisassembler::getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t Address, raw_ostream &CStream) const { - // Read and shift the input (fetch as much as we can for now). - auto Buffer = M68kInstructionBuffer::fill(Bytes); - if (Buffer.size() == 0) - return Fail; - - // Check through our lookup table. - bool Found = false; - for (unsigned I = 0, E = Lookups.size(); I < E; ++I) { - const M68kInstructionLookup &Lookup = Lookups[I]; - if (!Lookup.matches(Buffer)) - continue; - - Found = true; - Size = Lookup.size() * 2; - Buffer.truncate(Lookup.size()); - Instr.setOpcode(Lookup.OpCode); - LLVM_DEBUG(errs() << "decoding instruction " << MCII->getName(Lookup.OpCode) - << "\n"); - break; - } - - if (!Found) - return Fail; - - M68kInstructionReader Reader(Buffer); - const MCInstrDesc &Desc = MCII->get(Instr.getOpcode()); - unsigned NumOperands = Desc.NumOperands; - - // Now use the beads to decode the operands. - enum class OperandType { - Invalid, - Reg, - Imm, - }; - - SmallVector<OperandType, 6> OpType(NumOperands, OperandType::Invalid); - SmallVector<unsigned, 6> Scratch(NumOperands, 0); - for (const uint8_t *PartPtr = M68k::getMCInstrBeads(Instr.getOpcode()); - *PartPtr; ++PartPtr) { - uint8_t Bead = *PartPtr; - unsigned Ext = Bead >> 4; - unsigned Op = Bead & 0xf; - unsigned MIOpIdx; - - switch (Op) { - case M68kBeads::Ctrl: - // Term will have already been skipped by the loop. - assert((Ext == M68kBeads::Ignore) && "unexpected command bead"); - break; - - // These bits are constant - if we're here we've already matched them. - case M68kBeads::Bits1: - Reader.readBits(1); - break; - case M68kBeads::Bits2: - Reader.readBits(2); - break; - case M68kBeads::Bits3: - Reader.readBits(3); - break; - case M68kBeads::Bits4: - Reader.readBits(4); - break; - - case M68kBeads::DAReg: - case M68kBeads::DA: - case M68kBeads::DReg: - case M68kBeads::Reg: - MIOpIdx = getRegOperandIndex(Instr, Bead); - assert(((OpType[MIOpIdx] == OperandType::Invalid) || - (OpType[MIOpIdx] == OperandType::Reg)) && - "operands cannot change type"); - OpType[MIOpIdx] = OperandType::Reg; - decodeReg(Instr, Bead, Reader, Scratch[MIOpIdx]); - break; - - case M68kBeads::Disp8: - case M68kBeads::Imm8: - case M68kBeads::Imm16: - case M68kBeads::Imm32: - case M68kBeads::Imm3: - MIOpIdx = getImmOperandIndex(Instr, Bead); - assert(((OpType[MIOpIdx] == OperandType::Invalid) || - (OpType[MIOpIdx] == OperandType::Imm)) && - "operands cannot change type"); - OpType[MIOpIdx] = OperandType::Imm; - decodeImm(Instr, Bead, Reader, Scratch[MIOpIdx]); - break; - - default: - llvm_unreachable("unhandled bead type"); - } - } - - // Copy constrained operands. - for (unsigned DstMIOpIdx = 0; DstMIOpIdx < NumOperands; ++DstMIOpIdx) { - int TiedTo = Desc.getOperandConstraint(DstMIOpIdx, MCOI::TIED_TO); - if (TiedTo < 0) - continue; - - unsigned SrcMIOpIdx = TiedTo; - - unsigned OpCount = 0; - for (unsigned I = 0;; ++I) { - unsigned Offset = M68k::getLogicalOperandIdx(Instr.getOpcode(), I); - assert(Offset <= SrcMIOpIdx && "missing logical operand"); - if (Offset == SrcMIOpIdx) { - OpCount = M68k::getLogicalOperandSize(Instr.getOpcode(), I); - break; - } + DecodeStatus Result; + auto MakeUp = [&](APInt &Insn, unsigned InstrBits) { + unsigned Idx = Insn.getBitWidth() >> 3; + unsigned RoundUp = alignTo(InstrBits, Align(16)); + if (RoundUp > Insn.getBitWidth()) + Insn = Insn.zext(RoundUp); + RoundUp = RoundUp >> 3; + for (; Idx < RoundUp; Idx += 2) { + Insn.insertBits(support::endian::read16be(&Bytes[Idx]), Idx * 8, 16); } - assert(OpCount != 0 && "operand count not found"); - - for (unsigned I = 0; I < OpCount; ++I) { - assert(OpType[DstMIOpIdx + I] == OperandType::Invalid && - "tried to stomp over operand whilst applying constraints"); - OpType[DstMIOpIdx + I] = OpType[SrcMIOpIdx + I]; - Scratch[DstMIOpIdx + I] = Scratch[SrcMIOpIdx + I]; - } - } - - // Create the operands from our scratch space. - for (unsigned O = 0; O < NumOperands; ++O) { - switch (OpType[O]) { - case OperandType::Invalid: - assert(false && "operand not parsed"); - - case OperandType::Imm: - Instr.addOperand(MCOperand::createImm(Scratch[O])); - break; - - case OperandType::Reg: - Instr.addOperand(MCOperand::createReg(RegisterDecode[Scratch[O]])); - break; - } - } - - assert((Reader.size() == 0) && "wrong number of bits consumed"); - return Success; + }; + APInt Insn(16, support::endian::read16be(Bytes.data())); + // 2 bytes of data are consumed, so set Size to 2 + // If we don't do this, disassembler may generate result even + // the encoding is invalid. We need to let it fail correctly. + Size = 2; + Result = decodeInstruction(DecoderTable80, Instr, Insn, Address, this, STI, + MakeUp); + if (Result == DecodeStatus::Success) + Size = InstrLenTable[Instr.getOpcode()] >> 3; + return Result; } static MCDisassembler *createM68kDisassembler(const Target &T, const MCSubtargetInfo &STI, MCContext &Ctx) { - return new M68kDisassembler(STI, Ctx, T.createMCInstrInfo()); + return new M68kDisassembler(STI, Ctx); } extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeM68kDisassembler() { |