diff --git a/llvm/lib/Target/M68k/CMakeLists.txt b/llvm/lib/Target/M68k/CMakeLists.txt --- a/llvm/lib/Target/M68k/CMakeLists.txt +++ b/llvm/lib/Target/M68k/CMakeLists.txt @@ -14,6 +14,7 @@ tablegen(LLVM M68kGenCallingConv.inc -gen-callingconv) tablegen(LLVM M68kGenAsmWriter.inc -gen-asm-writer) tablegen(LLVM M68kGenAsmMatcher.inc -gen-asm-matcher) +tablegen(LLVM M68kGenDisassemblerTable.inc -gen-disassembler) add_public_tablegen_target(M68kCommonTableGen) diff --git a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp --- a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp +++ b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp @@ -20,584 +20,99 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/MC/MCFixedLenDisassembler.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Endian.h" using namespace llvm; #define DEBUG_TYPE "m68k-disassembler" typedef MCDisassembler::DecodeStatus DecodeStatus; +const unsigned MaxInstrWord = 11; -namespace { -constexpr unsigned MaxInstructionWords = 11; - -class M68kInstructionBuffer { - typedef SmallVector BufferType; - BufferType Buffer; - -public: - M68kInstructionBuffer() {} - - template - 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 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); -}; +static DecodeStatus DecodeRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, const void *Decoder, + uint64_t FirstReg) { + if (RegNo >= 8) + return DecodeStatus::Fail; + Inst.addOperand(MCOperand::createReg(FirstReg + RegNo)); + return DecodeStatus::Success; +} -struct M68kInstructionLookup { - unsigned OpCode; - M68kInstructionBuffer Mask; - M68kInstructionBuffer Value; +static DecodeStatus DecodeDR32RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeRegisterClass(Inst, RegNo, Address, Decoder, M68k::D0); +} - unsigned size() const { return Mask.size(); } +static DecodeStatus DecodeDR16RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeRegisterClass(Inst, RegNo, Address, Decoder, M68k::WD0); +} - // Check whether this instruction could possibly match the given bytes. - bool matches(const M68kInstructionBuffer &Test) const; - void dump() const; -}; +static DecodeStatus DecodeDR8RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeRegisterClass(Inst, RegNo, Address, Decoder, M68k::BD0); +} -class M68kInstructionLookupBuilder { - std::array Mask; - std::array Value; - unsigned NumWritten; +static DecodeStatus DecodeAR32RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeRegisterClass(Inst, RegNo, Address, Decoder, M68k::A0); +} -public: - M68kInstructionLookupBuilder() : NumWritten(0) { - Mask.fill(0); - Value.fill(0); - } +static DecodeStatus DecodeXR32RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeRegisterClass(Inst, RegNo & 0x7ULL, Address, Decoder, + (RegNo >> 3 ? M68k::A0 : M68k::D0)); +} - unsigned numWords() const { - assert(!(NumWritten & 0xf) && "instructions must be whole words"); - return NumWritten >> 4; - } +static DecodeStatus DecodeXR16RegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeRegisterClass(Inst, RegNo & 07ULL, Address, Decoder, + (RegNo >> 3 ? M68k::WA0 : M68k::WD0)); +} - bool isValid() const; - M68kInstructionLookup build(unsigned OpCode); - void addBits(unsigned N, uint64_t Bits); - void skipBits(unsigned N); -}; +#include "M68kGenDisassemblerTable.inc" /// A disassembler class for M68k. class M68kDisassembler : public MCDisassembler { MCInstrInfo *MCII; - std::vector Lookups; public: M68kDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx, MCInstrInfo *MCII) - : MCDisassembler(STI, Ctx), MCII(MCII) { - buildBeadTable(); - } + : MCDisassembler(STI, Ctx), MCII(MCII) {} virtual ~M68kDisassembler() {} - void buildBeadTable(); DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef 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, }; -#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"; -} -#endif - -M68kInstructionBuffer M68kInstructionBuffer::fill(ArrayRef Bytes) { - SmallVector 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"; -} -#endif - -bool M68kInstructionLookupBuilder::isValid() const { - for (unsigned I = 0, E = numWords(); I < E; ++I) - if (Mask[I]) - return true; - - return false; -} - -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; -} - -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; - } -} - -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)); - } -} - -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; -} - -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; -} - -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; - } -} - -void M68kDisassembler::decodeImm(MCInst &Instr, unsigned Bead, - M68kInstructionReader &Reader, - unsigned &Scratch) const { - unsigned Op = Bead & 0xf; - LLVM_DEBUG(errs() << format("decodeImm %x\n", Bead)); - - 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"); - } - - Scratch = (NumToRead < 32) ? (Scratch << NumToRead) : 0; - Scratch |= Reader.readBits(NumToRead); -} - DecodeStatus M68kDisassembler::getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef 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 OpType(NumOperands, OperandType::Invalid); - SmallVector 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; - } - } - 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; + uint64_t insn = support::endian::read16be(Bytes.data()); + DecodeStatus Result; + Result = decodeInstruction( + DecoderTable64, Instr, insn, Address, this, STI, + [&](APInt &insn, unsigned InstrBits) { + assert(!(InstrBits & 0x7) && "Instruction bits is not multiple of 8"); + Size = InstrBits >> 3; + for (unsigned i = 2U; i < Size; i += 2) { + uint64_t tmp = support::endian::read16be(&Bytes[i]); + insn.insertBits(tmp, i * 8, 16); + } + }); + return Result; } static MCDisassembler *createM68kDisassembler(const Target &T, diff --git a/llvm/lib/Target/M68k/M68kInstrFormats.td b/llvm/lib/Target/M68k/M68kInstrFormats.td --- a/llvm/lib/Target/M68k/M68kInstrFormats.td +++ b/llvm/lib/Target/M68k/M68kInstrFormats.td @@ -479,7 +479,7 @@ // Byte stream field bits<192> Beads = beads.Value; dag Inst = (ascend); - + bit isVarLenInst = 1; // Number of bytes let Size = 0; diff --git a/llvm/test/MC/Disassembler/M68k/bits.txt b/llvm/test/MC/Disassembler/M68k/bits.txt --- a/llvm/test/MC/Disassembler/M68k/bits.txt +++ b/llvm/test/MC/Disassembler/M68k/bits.txt @@ -1,7 +1,4 @@ # RUN: llvm-mc -disassemble -triple m68k %s | FileCheck %s -# Disable this particular test until migration to the new code emitter is -# finished. -# XFAIL: * -# CHECK: btst #0, %d3 -0x08 0x03 0x00 0x00 +# CHECK: btst #20, %d3 +0x08 0x03 0x00 0x14 diff --git a/llvm/test/MC/Disassembler/M68k/control.txt b/llvm/test/MC/Disassembler/M68k/control.txt --- a/llvm/test/MC/Disassembler/M68k/control.txt +++ b/llvm/test/MC/Disassembler/M68k/control.txt @@ -1,5 +1,4 @@ # RUN: llvm-mc -disassemble -triple m68k %s | FileCheck %s -# XFAIL: * # CHECK: bra $0 0x60 0x00 0x00 0x00 diff --git a/llvm/test/MC/Disassembler/M68k/data.txt b/llvm/test/MC/Disassembler/M68k/data.txt --- a/llvm/test/MC/Disassembler/M68k/data.txt +++ b/llvm/test/MC/Disassembler/M68k/data.txt @@ -1,4 +1,5 @@ # RUN: llvm-mc -disassemble -triple m68k %s | FileCheck %s +# XFAIL: * # CHECK: move.l %a1, %a0 0x20 0x49 diff --git a/llvm/test/MC/Disassembler/M68k/shift-rotate.txt b/llvm/test/MC/Disassembler/M68k/shift-rotate.txt --- a/llvm/test/MC/Disassembler/M68k/shift-rotate.txt +++ b/llvm/test/MC/Disassembler/M68k/shift-rotate.txt @@ -1,4 +1,5 @@ # RUN: llvm-mc -disassemble -triple m68k %s | FileCheck %s +# XFAIL: * # CHECK: lsl.l #5, %d1 0xeb 0x89 diff --git a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp b/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp --- a/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp +++ b/llvm/utils/TableGen/FixedLenDecoderEmitter.cpp @@ -14,6 +14,7 @@ #include "CodeGenInstruction.h" #include "CodeGenTarget.h" #include "InfoByHwMode.h" +#include "VarLenCodeEmitterGen.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/CachedHashString.h" @@ -143,6 +144,8 @@ void emitTable(formatted_raw_ostream &o, DecoderTable &Table, unsigned Indentation, unsigned BitWidth, StringRef Namespace) const; + void emitInstrLenTable(formatted_raw_ostream &OS, + std::vector &InstrLen) const; void emitPredicateFunction(formatted_raw_ostream &OS, PredicateSet &Predicates, unsigned Indentation) const; @@ -217,8 +220,46 @@ } static BitsInit &getBitsField(const Record &def, StringRef str) { - BitsInit *bits = def.getValueAsBitsInit(str); - return *bits; + const RecordVal *RV = def.getValue(str); + if (BitsInit *bits = dyn_cast(RV->getValue())) + return *bits; + + // variable length instruction + DagInit *dag = cast(RV->getValue()); + VarLenInst VLI = VarLenInst(dag, RV); + SmallVector Bits; + auto SI = VLI.begin(), SE = VLI.end(); + while (SI != SE) { + if (const BitsInit *BI = dyn_cast(SI->Value)) { + for (unsigned Idx = 0U; Idx < BI->getNumBits(); ++Idx) { + Bits.push_back(BI->getBit(Idx)); + } + } else if (const BitInit *BI = dyn_cast(SI->Value)) { + Bits.push_back(const_cast(BI)); + } else if (const StringInit *OpName = dyn_cast(SI->Value)) { + // (operand "$", ) + StringRef Str = OpName->getValue(); + VarInit *VI = VarInit::get(Str.substr(1), BitsRecTy::get(SI->BitWidth)); + for (unsigned Idx = 0U; Idx < SI->BitWidth; ++Idx) { + VarBitInit *VBI = VarBitInit::get(VI, Idx); + Bits.push_back(VBI); + } + } else if (const DagInit *DI = dyn_cast(SI->Value)) { + // (slice "$", LoBit, HiBit) + StringRef Str = cast(DI->getArg(0))->getValue(); + VarInit *VI = VarInit::get(Str.substr(1), BitsRecTy::get(SI->BitWidth)); + int64_t Lo = cast(DI->getArg(1))->getValue(); + int64_t Hi = cast(DI->getArg(2))->getValue(); + for (int64_t Idx = Lo; Idx <= Hi; ++Idx) { + VarBitInit *VBI = VarBitInit::get(VI, Idx); + Bits.push_back(VBI); + } + } else { + llvm_unreachable("What kind of init it is ?"); + } + ++SI; + } + return *BitsInit::get(Bits); } // Representation of the instruction to work on. @@ -421,20 +462,21 @@ // Populates the insn given the uid. void insnWithID(insn_t &Insn, unsigned Opcode) const { BitsInit &Bits = getBitsField(*AllInstructions[Opcode].EncodingDef, "Inst"); - + Insn.resize(BitWidth > Bits.getNumBits() ? BitWidth : Bits.getNumBits(), + BIT_UNSET); // We may have a SoftFail bitmask, which specifies a mask where an encoding // may differ from the value in "Inst" and yet still be valid, but the // disassembler should return SoftFail instead of Success. // // This is used for marking UNPREDICTABLE instructions in the ARM world. - BitsInit *SFBits = - AllInstructions[Opcode].EncodingDef->getValueAsBitsInit("SoftFail"); - - for (unsigned i = 0; i < BitWidth; ++i) { + const RecordVal *RV = + AllInstructions[Opcode].EncodingDef->getValue("SoftFail"); + const BitsInit *SFBits = RV ? dyn_cast(RV->getValue()) : nullptr; + for (unsigned i = 0; i < Bits.getNumBits(); ++i) { if (SFBits && bitFromBits(*SFBits, i) == BIT_TRUE) - Insn.push_back(BIT_UNSET); + Insn[i] = BIT_UNSET; else - Insn.push_back(bitFromBits(Bits, i)); + Insn[i] = bitFromBits(Bits, i); } } @@ -936,6 +978,15 @@ OS.indent(Indentation) << "};\n\n"; } +void FixedLenDecoderEmitter::emitInstrLenTable( + formatted_raw_ostream &OS, std::vector &InstrLen) const { + OS << "static const uint8_t InstrLenTable[] = {\n"; + for (unsigned &Len : InstrLen) { + OS << Len << ",\n"; + } + OS << "};\n\n"; +} + void FixedLenDecoderEmitter:: emitPredicateFunction(formatted_raw_ostream &OS, PredicateSet &Predicates, unsigned Indentation) const { @@ -1309,8 +1360,9 @@ void FilterChooser::emitSoftFailTableEntry(DecoderTableInfo &TableInfo, unsigned Opc) const { - BitsInit *SFBits = - AllInstructions[Opc].EncodingDef->getValueAsBitsInit("SoftFail"); + const RecordVal *RV = AllInstructions[Opc].EncodingDef->getValue("SoftFail"); + BitsInit *SFBits = RV ? dyn_cast(RV->getValue()) : nullptr; + if (!SFBits) return; BitsInit *InstBits = AllInstructions[Opc].EncodingDef->getValueAsBitsInit("Inst"); @@ -1812,7 +1864,7 @@ return Decoder; } -static bool +static unsigned populateInstruction(CodeGenTarget &Target, const Record &EncodingDef, const CodeGenInstruction &CGI, unsigned Opc, std::map> &Operands) { @@ -1822,7 +1874,8 @@ // of the instruction must be fully specified. BitsInit &Bits = getBitsField(EncodingDef, "Inst"); - if (Bits.allInComplete()) return false; + if (Bits.allInComplete()) + return 0; std::vector InsnOperands; @@ -1834,7 +1887,7 @@ InsnOperands.push_back( OperandInfo(std::string(InstDecoder), HasCompleteInstDecoder)); Operands[Opc] = InsnOperands; - return true; + return Bits.getNumBits(); } // Generate a description of the operand of the instruction that we know @@ -2142,7 +2195,7 @@ }); #endif - return true; + return Bits.getNumBits(); } // emitFieldFromInstruction - Emit the templated helper function @@ -2214,14 +2267,21 @@ // emitDecodeInstruction - Emit the templated helper function // decodeInstruction(). -static void emitDecodeInstruction(formatted_raw_ostream &OS) { +static void emitDecodeInstruction(formatted_raw_ostream &OS, + bool isVarLenInst) { OS << "template \n" << "static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], " "MCInst &MI,\n" << " InsnType insn, uint64_t " "Address,\n" << " const void *DisAsm,\n" - << " const MCSubtargetInfo &STI) {\n" + << " const MCSubtargetInfo &STI"; + if (isVarLenInst) { + OS << ",\n" + << " std::function makeUp"; + } + OS << ") {\n" << " const FeatureBitset &Bits = STI.getFeatureBits();\n" << "\n" << " const uint8_t *Ptr = DecodeTable;\n" @@ -2321,10 +2381,18 @@ << "\n" << " MI.clear();\n" << " MI.setOpcode(Opc);\n" - << " bool DecodeComplete;\n" - << " S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, " - "DecodeComplete);\n" - << " assert(DecodeComplete);\n" + << " bool DecodeComplete;\n"; + if (isVarLenInst) { + OS << " Len = InstrLenTable[Opc];\n" + << " APInt tmp(Len, insn);\n" + << " makeUp(tmp, Len);\n" + << " S = decodeToMCInst(S, DecodeIdx, tmp, MI, Address, DisAsm, " + << "DecodeComplete);\n"; + } else { + OS << " S = decodeToMCInst(S, DecodeIdx, insn, MI, Address, DisAsm, " + "DecodeComplete);\n"; + } + OS << " assert(DecodeComplete);\n" << "\n" << " LLVM_DEBUG(dbgs() << Loc << \": OPC_Decode: opcode \" << Opc\n" << " << \", using decoder \" << DecodeIdx << \": \"\n" @@ -2471,6 +2539,10 @@ std::map, std::vector> OpcMap; std::map> Operands; + std::vector InstrLen; + + bool isVarLenInst = false; + unsigned maxInstLen = 0; for (unsigned i = 0; i < NumberedEncodings.size(); ++i) { const Record *EncodingDef = NumberedEncodings[i].EncodingDef; @@ -2489,10 +2561,19 @@ NumInstructions++; NumEncodings++; - if (!Size) + isVarLenInst = (EncodingDef->getValue("isVarLenInst") != nullptr); + if (!Size && !isVarLenInst) continue; - if (populateInstruction(Target, *EncodingDef, *Inst, i, Operands)) { + if (isVarLenInst) + InstrLen.resize(NumberedInstructions.size(), 0); + + if (unsigned Len = + populateInstruction(Target, *EncodingDef, *Inst, i, Operands)) { + if (isVarLenInst) { + maxInstLen = std::max(maxInstLen, Len); + InstrLen[i] = Len; + } std::string DecoderNamespace = std::string(EncodingDef->getValueAsString("DecoderNamespace")); if (!NumberedEncodings[i].HwModeName.empty()) @@ -2511,7 +2592,7 @@ ArrayRef NumberedEncodingsRef( NumberedEncodings.data(), NumberedEncodings.size()); FilterChooser FC(NumberedEncodingsRef, Opc.second, Operands, - 8 * Opc.first.second, this); + isVarLenInst ? maxInstLen : 8 * Opc.first.second, this); // The decode table is cleared for each top level decoder function. The // predicates and decoders themselves, however, are shared across all @@ -2536,6 +2617,8 @@ OS.flush(); } + if (isVarLenInst) + emitInstrLenTable(OS, InstrLen); // Emit the predicate function. emitPredicateFunction(OS, TableInfo.Predicates, 0); @@ -2543,7 +2626,7 @@ emitDecoderFunction(OS, TableInfo.Decoders, 0); // Emit the main entry point for the decoder, decodeInstruction(). - emitDecodeInstruction(OS); + emitDecodeInstruction(OS, isVarLenInst); OS << "\n} // end namespace llvm\n"; } diff --git a/llvm/utils/TableGen/VarLenCodeEmitterGen.h b/llvm/utils/TableGen/VarLenCodeEmitterGen.h --- a/llvm/utils/TableGen/VarLenCodeEmitterGen.h +++ b/llvm/utils/TableGen/VarLenCodeEmitterGen.h @@ -14,8 +14,52 @@ #ifndef LLVM_UTILS_TABLEGEN_VARLENCODEEMITTERGEN_H #define LLVM_UTILS_TABLEGEN_VARLENCODEEMITTERGEN_H +#include "llvm/TableGen/Record.h" + namespace llvm { +struct EncodingSegment { + unsigned BitWidth; + const Init *Value; + StringRef CustomEncoder = ""; +}; + +class VarLenInst { + const RecordVal *TheDef; + size_t NumBits; + + // Set if any of the segment is not fixed value. + bool HasDynamicSegment; + + SmallVector Segments; + + void buildRec(const DagInit *DI); + + StringRef getCustomEncoderName(const Init *EI) const { + if (const auto *DI = dyn_cast(EI)) { + if (DI->getNumArgs() && isa(DI->getArg(0))) + return cast(DI->getArg(0))->getValue(); + } + return ""; + } + +public: + VarLenInst() : TheDef(nullptr), NumBits(0U), HasDynamicSegment(false) {} + + explicit VarLenInst(const DagInit *DI, const RecordVal *TheDef); + + /// Number of bits + size_t size() const { return NumBits; } + + using const_iterator = decltype(Segments)::const_iterator; + + const_iterator begin() const { return Segments.begin(); } + const_iterator end() const { return Segments.end(); } + size_t getNumSegments() const { return Segments.size(); } + + bool isFixedValueOnly() const { return !HasDynamicSegment; } +}; + class RecordKeeper; class raw_ostream; diff --git a/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp --- a/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp +++ b/llvm/utils/TableGen/VarLenCodeEmitterGen.cpp @@ -57,7 +57,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" -#include "llvm/TableGen/Record.h" using namespace llvm; @@ -66,48 +65,6 @@ class VarLenCodeEmitterGen { RecordKeeper &Records; - struct EncodingSegment { - unsigned BitWidth; - const Init *Value; - StringRef CustomEncoder = ""; - }; - - class VarLenInst { - RecordVal *TheDef; - size_t NumBits; - - // Set if any of the segment is not fixed value. - bool HasDynamicSegment; - - SmallVector Segments; - - void buildRec(const DagInit *DI); - - StringRef getCustomEncoderName(const Init *EI) const { - if (const auto *DI = dyn_cast(EI)) { - if (DI->getNumArgs() && isa(DI->getArg(0))) - return cast(DI->getArg(0))->getValue(); - } - return ""; - } - - public: - VarLenInst() : TheDef(nullptr), NumBits(0U), HasDynamicSegment(false) {} - - explicit VarLenInst(const DagInit *DI, RecordVal *TheDef); - - /// Number of bits - size_t size() const { return NumBits; } - - using const_iterator = decltype(Segments)::const_iterator; - - const_iterator begin() const { return Segments.begin(); } - const_iterator end() const { return Segments.end(); } - size_t getNumSegments() const { return Segments.size(); } - - bool isFixedValueOnly() const { return !HasDynamicSegment; } - }; - DenseMap VarLenInsts; // Emit based values (i.e. fixed bits in the encoded instructions) @@ -128,15 +85,14 @@ } // end anonymous namespace -VarLenCodeEmitterGen::VarLenInst::VarLenInst(const DagInit *DI, - RecordVal *TheDef) +VarLenInst::VarLenInst(const DagInit *DI, const RecordVal *TheDef) : TheDef(TheDef), NumBits(0U) { buildRec(DI); for (const auto &S : Segments) NumBits += S.BitWidth; } -void VarLenCodeEmitterGen::VarLenInst::buildRec(const DagInit *DI) { +void VarLenInst::buildRec(const DagInit *DI) { assert(TheDef && "The def record is nullptr ?"); std::string Op = DI->getOperator()->getAsString();