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( + DecoderTable80, 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/test/MC/M68k/Relaxations/branch.s b/llvm/test/MC/M68k/Relaxations/branch.s --- a/llvm/test/MC/M68k/Relaxations/branch.s +++ b/llvm/test/MC/M68k/Relaxations/branch.s @@ -1,6 +1,5 @@ ; RUN: llvm-mc -triple=m68k -motorola-integers -filetype=obj < %s \ ; RUN: | llvm-objdump -d - | FileCheck %s -; XFAIL: * ; CHECK-LABEL: : TIGHT: