[llvm] 2221185 - [M68k] Implement Disassembler

Ricky Taylor via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 19 14:28:40 PDT 2021


Author: Ricky Taylor
Date: 2021-04-19T22:24:12+01:00
New Revision: 2221185776c39aab7b49a141993fa9a0d752a8d5

URL: https://github.com/llvm/llvm-project/commit/2221185776c39aab7b49a141993fa9a0d752a8d5
DIFF: https://github.com/llvm/llvm-project/commit/2221185776c39aab7b49a141993fa9a0d752a8d5.diff

LOG: [M68k] Implement Disassembler

This is an implementation of a disassembler for M68k.

Differential Revision: https://reviews.llvm.org/D98540

Added: 
    llvm/lib/Target/M68k/Disassembler/CMakeLists.txt
    llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
    llvm/test/MC/Disassembler/M68k/instructions.txt
    llvm/test/MC/Disassembler/M68k/lit.local.cfg

Modified: 
    llvm/lib/Target/M68k/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/M68k/CMakeLists.txt b/llvm/lib/Target/M68k/CMakeLists.txt
index b6d7810d87a36..9511cd8195afd 100644
--- a/llvm/lib/Target/M68k/CMakeLists.txt
+++ b/llvm/lib/Target/M68k/CMakeLists.txt
@@ -48,3 +48,4 @@ add_llvm_target(M68kCodeGen
 add_subdirectory(TargetInfo)
 add_subdirectory(MCTargetDesc)
 add_subdirectory(AsmParser)
+add_subdirectory(Disassembler)

diff  --git a/llvm/lib/Target/M68k/Disassembler/CMakeLists.txt b/llvm/lib/Target/M68k/Disassembler/CMakeLists.txt
new file mode 100644
index 0000000000000..69f9e8be24b87
--- /dev/null
+++ b/llvm/lib/Target/M68k/Disassembler/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_llvm_component_library(LLVMM68kDisassembler
+        M68kDisassembler.cpp
+
+  LINK_COMPONENTS
+  M68kInfo
+  MCDisassembler
+  Support
+
+  ADD_TO_COMPONENT
+  M68k
+)
+

diff  --git a/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
new file mode 100644
index 0000000000000..8045251c30ef8
--- /dev/null
+++ b/llvm/lib/Target/M68k/Disassembler/M68kDisassembler.cpp
@@ -0,0 +1,606 @@
+//===- M68kDisassembler.cpp - Disassembler for M68k -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the M68k Disassembler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "M68k.h"
+#include "M68kRegisterInfo.h"
+#include "M68kSubtarget.h"
+#include "MCTargetDesc/M68kMCCodeEmitter.h"
+#include "MCTargetDesc/M68kMCTargetDesc.h"
+#include "TargetInfo/M68kTargetInfo.h"
+
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "m68k-disassembler"
+
+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,
+};
+
+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";
+}
+
+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;
+}
+
+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";
+}
+
+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 = (Scratch << NumToRead) | Reader.readBits(NumToRead);
+}
+
+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;
+      }
+    }
+    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;
+}
+
+static MCDisassembler *createM68kDisassembler(const Target &T,
+                                              const MCSubtargetInfo &STI,
+                                              MCContext &Ctx) {
+  return new M68kDisassembler(STI, Ctx, T.createMCInstrInfo());
+}
+
+extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeM68kDisassembler() {
+  // Register the disassembler.
+  TargetRegistry::RegisterMCDisassembler(getTheM68kTarget(),
+                                         createM68kDisassembler);
+}

diff  --git a/llvm/test/MC/Disassembler/M68k/instructions.txt b/llvm/test/MC/Disassembler/M68k/instructions.txt
new file mode 100644
index 0000000000000..20fe80315afbe
--- /dev/null
+++ b/llvm/test/MC/Disassembler/M68k/instructions.txt
@@ -0,0 +1,38 @@
+# RUN: llvm-mc -disassemble -triple m68k %s | FileCheck %s
+
+# CHECK: move.l %a1, %a0
+0x20 0x49
+# CHECK: add.l %a0, %a1
+0xd3 0xc8
+# CHECK: sub.w %d3, %d1
+0x92 0x43
+# CHECK: cmp.w %d1, %d0
+0xb0 0x41
+# CHECK: neg.w %d0
+0x44 0x40
+# CHECK: btst #0, %d3
+0x08 0x03 0x00 0x00
+# CHECK: bra $0
+0x60 0x00 0x00 0x00
+# CHECK: jsr $0
+0x4e 0xb9 0x00 0x00 0x00 0x00
+# CHECK: seq %d0
+0x57 0xc0
+# CHECK: sgt %d0
+0x5e 0xc0
+# CHECK: lea (50,%a0), %a1
+0x43 0xe8 0x00 0x32
+# CHECK: lsl.l #5, %d1
+0xeb 0x89
+# CHECK: lsr.l #5, %d1
+0xea 0x89
+# CHECK: asr.l #5, %d1
+0xea 0x81
+# CHECK: rol.l #5, %d1
+0xeb 0x99
+# CHECK: ror.l #5, %d1
+0xea 0x99
+# CHECK: nop
+0x4e 0x71
+# CHECK: rts
+0x4e 0x75

diff  --git a/llvm/test/MC/Disassembler/M68k/lit.local.cfg b/llvm/test/MC/Disassembler/M68k/lit.local.cfg
new file mode 100644
index 0000000000000..a0faa52ae52ba
--- /dev/null
+++ b/llvm/test/MC/Disassembler/M68k/lit.local.cfg
@@ -0,0 +1,2 @@
+if not 'M68k' in config.root.targets:
+    config.unsupported = True


        


More information about the llvm-commits mailing list