diff --git a/debian/changelog b/debian/changelog index 2106a838..166a5278 100644 --- a/debian/changelog +++ b/debian/changelog @@ -15,6 +15,7 @@ llvm-toolchain-snapshot (1:13~++20210403031832+89afec348dbd-1~exp1) UNRELEASED; * Add upstream patch D98575 to fix 32-bit compiler-rt build on sparc64 * Enable building the new experimental M68k backend * Add upstream patch D98519 to add support for Motorola literal syntax to AsmParser + * Add upstream patch D98537 to implement AsmParser on m68k -- Sylvestre Ledru Sat, 03 Apr 2021 15:22:07 +0200 diff --git a/debian/patches/D98537.diff b/debian/patches/D98537.diff new file mode 100644 index 00000000..00217127 --- /dev/null +++ b/debian/patches/D98537.diff @@ -0,0 +1,1077 @@ +diff --git a/llvm/lib/Target/M68k/AsmParser/CMakeLists.txt b/llvm/lib/Target/M68k/AsmParser/CMakeLists.txt +new file mode 100644 +--- /dev/null ++++ b/llvm/lib/Target/M68k/AsmParser/CMakeLists.txt +@@ -0,0 +1,12 @@ ++add_llvm_component_library(LLVMM68kAsmParser ++ M68kAsmParser.cpp ++ ++ LINK_COMPONENTS ++ MC ++ MCParser ++ Support ++ M68kCodeGen ++ ++ ADD_TO_COMPONENT ++ M68k ++) +diff --git a/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp b/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp +new file mode 100644 +--- /dev/null ++++ b/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp +@@ -0,0 +1,865 @@ ++//===---- M68kAsmParser.cpp - Parse M68k assembly to MCInst instructions --===// ++// ++// 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 ++// ++//===----------------------------------------------------------------------===// ++ ++#include "M68kInstrInfo.h" ++#include "M68kRegisterInfo.h" ++#include "TargetInfo/M68kTargetInfo.h" ++ ++#include "llvm/MC/MCContext.h" ++#include "llvm/MC/MCParser/MCParsedAsmOperand.h" ++#include "llvm/MC/MCParser/MCTargetAsmParser.h" ++#include "llvm/MC/MCStreamer.h" ++#include "llvm/Support/TargetRegistry.h" ++ ++#include ++ ++#define DEBUG_TYPE "m68k-asm-parser" ++ ++using namespace llvm; ++ ++static cl::opt RegisterPrefixOptional( ++ "m68k-register-prefix-optional", cl::Hidden, ++ cl::desc("Enable specifying registers without the % prefix"), ++ cl::init(false)); ++ ++namespace { ++/// Parses M68k assembly from a stream. ++class M68kAsmParser : public MCTargetAsmParser { ++ const MCSubtargetInfo &STI; ++ MCAsmParser &Parser; ++ const MCRegisterInfo *MRI; ++ ++#define GET_ASSEMBLER_HEADER ++#include "M68kGenAsmMatcher.inc" ++ ++public: ++ M68kAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, ++ const MCInstrInfo &MII, const MCTargetOptions &Options) ++ : MCTargetAsmParser(Options, STI, MII), STI(STI), Parser(Parser) { ++ MCAsmParserExtension::Initialize(Parser); ++ MRI = getContext().getRegisterInfo(); ++ ++ setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); ++ } ++ ++ // Parser functions. ++ void eatComma(); ++ ++ bool isExpr() const; ++ OperandMatchResultTy parseImm(OperandVector &Operands); ++ OperandMatchResultTy parseMemOp(OperandVector &Operands); ++ ++ unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, ++ unsigned Kind) override; ++ bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; ++ OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc, ++ SMLoc &EndLoc) override; ++ bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, ++ SMLoc NameLoc, OperandVector &Operands) override; ++ bool ParseDirective(AsmToken DirectiveID) override; ++ bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, ++ OperandVector &Operands, MCStreamer &Out, ++ uint64_t &ErrorInfo, ++ bool MatchingInlineAsm) override; ++ ++ // Helpers for Match&Emit. ++ bool invalidOperand(const SMLoc &Loc, const OperandVector &Operands, ++ const uint64_t &ErrorInfo); ++ bool missingFeature(const SMLoc &Loc, const uint64_t &ErrorInfo); ++ bool emit(MCInst &Inst, SMLoc const &Loc, MCStreamer &Out) const; ++ bool parseRegisterName(unsigned int &RegNo, SMLoc Loc, ++ StringRef RegisterName); ++ OperandMatchResultTy parseRegister(unsigned int &RegNo); ++}; ++ ++struct M68kMemOp { ++ enum class Kind { ++ Addr, ++ Reg, ++ RegIndirect, ++ RegPostIncrement, ++ RegPreDecrement, ++ RegIndirectDisplacement, ++ RegIndirectDisplacementIndex, ++ }; ++ ++ // These variables are used for the following forms: ++ // Addr: (OuterDisp) ++ // Reg: %OuterReg ++ // RegIndirect: (%OuterReg) ++ // RegPostIncrement: (%OuterReg)+ ++ // RegPreDecrement: -(%OuterReg) ++ // RegIndirectDisplacement: OuterDisp(%OuterReg) ++ // RegIndirectDisplacementIndex: ++ // OuterDisp(%OuterReg, %InnerReg.Size * Scale, InnerDisp) ++ ++ Kind Op; ++ unsigned OuterReg; ++ unsigned InnerReg; ++ const MCExpr *OuterDisp; ++ const MCExpr *InnerDisp; ++ uint8_t Size : 4; ++ uint8_t Scale : 4; ++ const MCExpr *Expr; ++ ++ M68kMemOp() {} ++ M68kMemOp(Kind Op) : Op(Op) {} ++ ++ void print(raw_ostream &OS) const; ++}; ++ ++/// An parsed M68k assembly operand. ++class M68kOperand : public MCParsedAsmOperand { ++ typedef MCParsedAsmOperand Base; ++ ++ enum class Kind { ++ Invalid, ++ Token, ++ Imm, ++ MemOp, ++ }; ++ ++ Kind Kind; ++ SMLoc Start, End; ++ union { ++ StringRef Token; ++ int64_t Imm; ++ const MCExpr *Expr; ++ M68kMemOp MemOp; ++ }; ++ ++public: ++ M68kOperand(enum Kind Kind, SMLoc Start, SMLoc End) ++ : Base(), Kind(Kind), Start(Start), End(End) {} ++ ++ SMLoc getStartLoc() const override { return Start; } ++ SMLoc getEndLoc() const override { return End; } ++ ++ void print(raw_ostream &OS) const override; ++ ++ bool isMem() const override { return false; } ++ bool isMemOp() const { return Kind == Kind::MemOp; } ++ ++ static void addExpr(MCInst &Inst, const MCExpr *Expr); ++ ++ // Reg ++ bool isReg() const override; ++ unsigned getReg() const override; ++ void addRegOperands(MCInst &Inst, unsigned N) const; ++ ++ static std::unique_ptr createMemOp(M68kMemOp MemOp, SMLoc Start, ++ SMLoc End); ++ ++ // Token ++ bool isToken() const override; ++ StringRef getToken() const; ++ static std::unique_ptr createToken(StringRef Token, SMLoc Start, ++ SMLoc End); ++ ++ // Imm ++ bool isImm() const override; ++ void addImmOperands(MCInst &Inst, unsigned N) const; ++ ++ static std::unique_ptr createImm(const MCExpr *Expr, SMLoc Start, ++ SMLoc End); ++ ++ // Addr ++ bool isAddr() const; ++ void addAddrOperands(MCInst &Inst, unsigned N) const; ++ ++ // ARI ++ bool isARI() const; ++ void addARIOperands(MCInst &Inst, unsigned N) const; ++ ++ // ARID ++ bool isARID() const; ++ void addARIDOperands(MCInst &Inst, unsigned N) const; ++ ++ // ARII ++ bool isARII() const; ++ void addARIIOperands(MCInst &Inst, unsigned N) const; ++ ++ // ARIPD ++ bool isARIPD() const; ++ void addARIPDOperands(MCInst &Inst, unsigned N) const; ++ ++ // ARIPI ++ bool isARIPI() const; ++ void addARIPIOperands(MCInst &Inst, unsigned N) const; ++ ++ // PCD ++ bool isPCD() const; ++ void addPCDOperands(MCInst &Inst, unsigned N) const; ++ ++ // PCI ++ bool isPCI() const; ++ void addPCIOperands(MCInst &Inst, unsigned N) const; ++}; ++ ++} // end anonymous namespace. ++ ++extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeM68kAsmParser() { ++ RegisterMCAsmParser X(getTheM68kTarget()); ++} ++ ++#define GET_MATCHER_IMPLEMENTATION ++#include "M68kGenAsmMatcher.inc" ++ ++void M68kMemOp::print(raw_ostream &OS) const { ++ switch (Op) { ++ case Kind::Addr: ++ OS << OuterDisp; ++ break; ++ case Kind::Reg: ++ OS << '%' << OuterReg; ++ break; ++ case Kind::RegIndirect: ++ OS << "(%" << OuterReg << ')'; ++ break; ++ case Kind::RegPostIncrement: ++ OS << "(%" << OuterReg << ")+"; ++ break; ++ case Kind::RegPreDecrement: ++ OS << "-(%" << OuterReg << ")"; ++ break; ++ case Kind::RegIndirectDisplacement: ++ OS << OuterDisp << "(%" << OuterReg << ")"; ++ break; ++ case Kind::RegIndirectDisplacementIndex: ++ OS << OuterDisp << "(%" << OuterReg << ", " << InnerReg << "." << Size ++ << ", " << InnerDisp << ")"; ++ break; ++ default: ++ llvm_unreachable("unknown MemOp kind"); ++ } ++} ++ ++void M68kOperand::addExpr(MCInst &Inst, const MCExpr *Expr) { ++ if (auto Const = dyn_cast(Expr)) { ++ Inst.addOperand(MCOperand::createImm(Const->getValue())); ++ return; ++ } ++ ++ Inst.addOperand(MCOperand::createExpr(Expr)); ++} ++ ++// Reg ++bool M68kOperand::isReg() const { ++ return Kind == Kind::MemOp && MemOp.Op == M68kMemOp::Kind::Reg; ++} ++ ++unsigned M68kOperand::getReg() const { ++ assert(isReg()); ++ return MemOp.OuterReg; ++} ++ ++void M68kOperand::addRegOperands(MCInst &Inst, unsigned N) const { ++ assert(isReg() && "wrong operand kind"); ++ assert((N == 1) && "can only handle one register operand"); ++ ++ Inst.addOperand(MCOperand::createReg(getReg())); ++} ++ ++std::unique_ptr M68kOperand::createMemOp(M68kMemOp MemOp, ++ SMLoc Start, SMLoc End) { ++ auto Op = std::make_unique(Kind::MemOp, Start, End); ++ Op->MemOp = MemOp; ++ return Op; ++} ++ ++// Token ++bool M68kOperand::isToken() const { return Kind == Kind::Token; } ++StringRef M68kOperand::getToken() const { ++ assert(isToken()); ++ return Token; ++} ++ ++std::unique_ptr M68kOperand::createToken(StringRef Token, ++ SMLoc Start, SMLoc End) { ++ auto Op = std::make_unique(Kind::Token, Start, End); ++ Op->Token = Token; ++ return Op; ++} ++ ++// Imm ++bool M68kOperand::isImm() const { return Kind == Kind::Imm; } ++void M68kOperand::addImmOperands(MCInst &Inst, unsigned N) const { ++ assert(isImm() && "wrong oeprand kind"); ++ assert((N == 1) && "can only handle one register operand"); ++ ++ M68kOperand::addExpr(Inst, Expr); ++} ++ ++std::unique_ptr M68kOperand::createImm(const MCExpr *Expr, ++ SMLoc Start, SMLoc End) { ++ auto Op = std::make_unique(Kind::Imm, Start, End); ++ Op->Expr = Expr; ++ return Op; ++} ++ ++// Addr ++bool M68kOperand::isAddr() const { ++ return isMemOp() && MemOp.Op == M68kMemOp::Kind::Addr; ++} ++void M68kOperand::addAddrOperands(MCInst &Inst, unsigned N) const { ++ M68kOperand::addExpr(Inst, MemOp.OuterDisp); ++} ++ ++// ARI ++bool M68kOperand::isARI() const { ++ return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirect && ++ M68k::AR32RegClass.contains(MemOp.OuterReg); ++} ++void M68kOperand::addARIOperands(MCInst &Inst, unsigned N) const { ++ Inst.addOperand(MCOperand::createReg(MemOp.OuterReg)); ++} ++ ++// ARID ++bool M68kOperand::isARID() const { ++ return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacement && ++ M68k::AR32RegClass.contains(MemOp.OuterReg); ++} ++void M68kOperand::addARIDOperands(MCInst &Inst, unsigned N) const { ++ M68kOperand::addExpr(Inst, MemOp.OuterDisp); ++ Inst.addOperand(MCOperand::createReg(MemOp.OuterReg)); ++} ++ ++// ARII ++bool M68kOperand::isARII() const { ++ return isMemOp() && ++ MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacementIndex && ++ M68k::AR32RegClass.contains(MemOp.OuterReg); ++} ++void M68kOperand::addARIIOperands(MCInst &Inst, unsigned N) const { ++ M68kOperand::addExpr(Inst, MemOp.OuterDisp); ++ Inst.addOperand(MCOperand::createReg(MemOp.OuterReg)); ++ Inst.addOperand(MCOperand::createReg(MemOp.InnerReg)); ++} ++ ++// ARIPD ++bool M68kOperand::isARIPD() const { ++ return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegPreDecrement && ++ M68k::AR32RegClass.contains(MemOp.OuterReg); ++} ++void M68kOperand::addARIPDOperands(MCInst &Inst, unsigned N) const { ++ Inst.addOperand(MCOperand::createReg(MemOp.OuterReg)); ++} ++ ++// ARIPI ++bool M68kOperand::isARIPI() const { ++ return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegPostIncrement && ++ M68k::AR32RegClass.contains(MemOp.OuterReg); ++} ++void M68kOperand::addARIPIOperands(MCInst &Inst, unsigned N) const { ++ Inst.addOperand(MCOperand::createReg(MemOp.OuterReg)); ++} ++ ++// PCD ++bool M68kOperand::isPCD() const { ++ return isMemOp() && MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacement && ++ MemOp.OuterReg == M68k::PC; ++} ++void M68kOperand::addPCDOperands(MCInst &Inst, unsigned N) const { ++ M68kOperand::addExpr(Inst, MemOp.OuterDisp); ++} ++ ++// PCI ++bool M68kOperand::isPCI() const { ++ return isMemOp() && ++ MemOp.Op == M68kMemOp::Kind::RegIndirectDisplacementIndex && ++ MemOp.OuterReg == M68k::PC; ++} ++void M68kOperand::addPCIOperands(MCInst &Inst, unsigned N) const { ++ M68kOperand::addExpr(Inst, MemOp.OuterDisp); ++ Inst.addOperand(MCOperand::createReg(MemOp.InnerReg)); ++} ++ ++static inline bool checkRegisterClass(unsigned RegNo, bool Data, bool Address, ++ bool SP) { ++ switch (RegNo) { ++ case M68k::A0: ++ case M68k::A1: ++ case M68k::A2: ++ case M68k::A3: ++ case M68k::A4: ++ case M68k::A5: ++ case M68k::A6: ++ return Address; ++ ++ case M68k::SP: ++ return SP; ++ ++ case M68k::D0: ++ case M68k::D1: ++ case M68k::D2: ++ case M68k::D3: ++ case M68k::D4: ++ case M68k::D5: ++ case M68k::D6: ++ case M68k::D7: ++ return Data; ++ ++ case M68k::SR: ++ case M68k::CCR: ++ return false; ++ ++ default: ++ llvm_unreachable("unexpected register type"); ++ return false; ++ } ++} ++ ++unsigned M68kAsmParser::validateTargetOperandClass(MCParsedAsmOperand &Op, ++ unsigned Kind) { ++ M68kOperand &Operand = (M68kOperand &)Op; ++ ++ switch (Kind) { ++ case MCK_XR16: ++ case MCK_SPILL: ++ if (Operand.isReg() && ++ checkRegisterClass(Operand.getReg(), true, true, true)) { ++ return Match_Success; ++ } ++ break; ++ ++ case MCK_AR16: ++ case MCK_AR32: ++ if (Operand.isReg() && ++ checkRegisterClass(Operand.getReg(), false, true, true)) { ++ return Match_Success; ++ } ++ break; ++ ++ case MCK_AR32_NOSP: ++ if (Operand.isReg() && ++ checkRegisterClass(Operand.getReg(), false, true, false)) { ++ return Match_Success; ++ } ++ break; ++ ++ case MCK_DR8: ++ case MCK_DR16: ++ case MCK_DR32: ++ if (Operand.isReg() && ++ checkRegisterClass(Operand.getReg(), true, false, false)) { ++ return Match_Success; ++ } ++ break; ++ ++ case MCK_AR16_TC: ++ if (Operand.isReg() && ++ ((Operand.getReg() == M68k::A0) || (Operand.getReg() == M68k::A1))) { ++ return Match_Success; ++ } ++ break; ++ ++ case MCK_DR16_TC: ++ if (Operand.isReg() && ++ ((Operand.getReg() == M68k::D0) || (Operand.getReg() == M68k::D1))) { ++ return Match_Success; ++ } ++ break; ++ ++ case MCK_XR16_TC: ++ if (Operand.isReg() && ++ ((Operand.getReg() == M68k::D0) || (Operand.getReg() == M68k::D1) || ++ (Operand.getReg() == M68k::A0) || (Operand.getReg() == M68k::A1))) { ++ return Match_Success; ++ } ++ break; ++ } ++ ++ return Match_InvalidOperand; ++} ++ ++bool M68kAsmParser::parseRegisterName(unsigned &RegNo, SMLoc Loc, ++ StringRef RegisterName) { ++ auto RegisterNameLower = RegisterName.lower(); ++ ++ // Parse simple general-purpose registers. ++ if (RegisterNameLower.size() == 2) { ++ static unsigned RegistersByIndex[] = { ++ 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, ++ }; ++ ++ switch (RegisterNameLower[0]) { ++ case 'd': ++ case 'a': { ++ if (isdigit(RegisterNameLower[1])) { ++ unsigned IndexOffset = (RegisterNameLower[0] == 'a') ? 8 : 0; ++ unsigned RegIndex = (unsigned)(RegisterNameLower[1] - '0'); ++ if (RegIndex < 8) { ++ RegNo = RegistersByIndex[IndexOffset + RegIndex]; ++ return true; ++ } ++ } ++ break; ++ } ++ ++ case 'c': ++ if (RegisterNameLower[1] == 'c' && RegisterNameLower[2] == 'r') { ++ RegNo = M68k::CCR; ++ return true; ++ } ++ break; ++ ++ case 's': ++ if (RegisterNameLower[1] == 'p') { ++ RegNo = M68k::SP; ++ return true; ++ } else if (RegisterNameLower[1] == 'r') { ++ RegNo = M68k::SR; ++ return true; ++ } ++ break; ++ ++ case 'p': ++ if (RegisterNameLower[1] == 'c') { ++ RegNo = M68k::PC; ++ return true; ++ } ++ break; ++ } ++ } ++ ++ return false; ++} ++ ++OperandMatchResultTy M68kAsmParser::parseRegister(unsigned &RegNo) { ++ bool HasPercent = false; ++ AsmToken PercentToken; ++ ++ LLVM_DEBUG(dbgs() << "parseRegister "; getTok().dump(dbgs()); dbgs() << "\n"); ++ ++ if (getTok().is(AsmToken::Percent)) { ++ HasPercent = true; ++ PercentToken = Lex(); ++ } else if (!RegisterPrefixOptional.getValue()) { ++ return MatchOperand_NoMatch; ++ } ++ ++ if (!Parser.getTok().is(AsmToken::Identifier)) { ++ if (HasPercent) { ++ getLexer().UnLex(PercentToken); ++ } ++ return MatchOperand_NoMatch; ++ } ++ ++ auto RegisterName = Parser.getTok().getString(); ++ if (!parseRegisterName(RegNo, Parser.getLexer().getLoc(), RegisterName)) { ++ if (HasPercent) { ++ getLexer().UnLex(PercentToken); ++ } ++ return MatchOperand_NoMatch; ++ } ++ ++ Parser.Lex(); ++ return MatchOperand_Success; ++} ++ ++bool M68kAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, ++ SMLoc &EndLoc) { ++ auto Result = tryParseRegister(RegNo, StartLoc, EndLoc); ++ if (Result != MatchOperand_Success) { ++ return Error(StartLoc, "expected register"); ++ } ++ ++ return false; ++} ++ ++OperandMatchResultTy M68kAsmParser::tryParseRegister(unsigned &RegNo, ++ SMLoc &StartLoc, ++ SMLoc &EndLoc) { ++ StartLoc = getLexer().getLoc(); ++ auto Result = parseRegister(RegNo); ++ EndLoc = getLexer().getLoc(); ++ return Result; ++} ++ ++bool M68kAsmParser::isExpr() const { ++ switch (Parser.getTok().getKind()) { ++ case AsmToken::Identifier: ++ case AsmToken::Integer: ++ return true; ++ ++ default: ++ return false; ++ } ++} ++ ++OperandMatchResultTy M68kAsmParser::parseImm(OperandVector &Operands) { ++ if (getLexer().isNot(AsmToken::Hash)) { ++ return MatchOperand_NoMatch; ++ } ++ SMLoc Start = getLexer().getLoc(); ++ Parser.Lex(); ++ ++ SMLoc End; ++ const MCExpr *Expr; ++ ++ if (getParser().parseExpression(Expr, End)) { ++ return MatchOperand_ParseFail; ++ } ++ ++ Operands.push_back(M68kOperand::createImm(Expr, Start, End)); ++ return MatchOperand_Success; ++} ++ ++OperandMatchResultTy M68kAsmParser::parseMemOp(OperandVector &Operands) { ++ SMLoc Start = getLexer().getLoc(); ++ bool IsPD = false; ++ M68kMemOp MemOp; ++ ++ // Check for a plain register. ++ auto Result = parseRegister(MemOp.OuterReg); ++ if (Result == MatchOperand_Success) { ++ MemOp.Op = M68kMemOp::Kind::Reg; ++ Operands.push_back( ++ M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc())); ++ return MatchOperand_Success; ++ } ++ ++ if (Result == MatchOperand_ParseFail) { ++ return Result; ++ } ++ ++ // Check for pre-decrement & outer displacement. ++ bool HasDisplacement = false; ++ if (getLexer().is(AsmToken::Minus)) { ++ IsPD = true; ++ Parser.Lex(); ++ } else if (isExpr()) { ++ if (Parser.parseExpression(MemOp.OuterDisp)) { ++ return MatchOperand_ParseFail; ++ } ++ HasDisplacement = true; ++ } ++ ++ if (getLexer().isNot(AsmToken::LParen)) { ++ if (HasDisplacement) { ++ MemOp.Op = M68kMemOp::Kind::Addr; ++ Operands.push_back( ++ M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc())); ++ return MatchOperand_Success; ++ } else if (IsPD) { ++ Error(getLexer().getLoc(), "expected ("); ++ return MatchOperand_ParseFail; ++ } ++ ++ return MatchOperand_NoMatch; ++ } ++ Parser.Lex(); ++ ++ // Check for constant dereference & MIT-style displacement ++ if (!HasDisplacement && isExpr()) { ++ if (Parser.parseExpression(MemOp.OuterDisp)) { ++ return MatchOperand_ParseFail; ++ } ++ HasDisplacement = true; ++ ++ // If we're not followed by a comma, we're a constant dereference. ++ if (getLexer().isNot(AsmToken::Comma)) { ++ MemOp.Op = M68kMemOp::Kind::Addr; ++ Operands.push_back( ++ M68kOperand::createMemOp(MemOp, Start, getLexer().getLoc())); ++ return MatchOperand_Success; ++ } ++ ++ Parser.Lex(); ++ } ++ ++ Result = parseRegister(MemOp.OuterReg); ++ if (Result == MatchOperand_ParseFail) { ++ return MatchOperand_ParseFail; ++ } ++ ++ if (Result != MatchOperand_Success) { ++ Error(getLexer().getLoc(), "expected register"); ++ return MatchOperand_ParseFail; ++ } ++ ++ // Check for Index. ++ bool HasIndex = false; ++ if (Parser.getTok().is(AsmToken::Comma)) { ++ Parser.Lex(); ++ ++ Result = parseRegister(MemOp.InnerReg); ++ if (Result == MatchOperand_ParseFail) { ++ return Result; ++ } ++ ++ if (Result == MatchOperand_NoMatch) { ++ Error(getLexer().getLoc(), "expected register"); ++ return MatchOperand_ParseFail; ++ } ++ ++ // TODO: parse size, scale and inner displacement. ++ MemOp.Size = 4; ++ MemOp.Scale = 1; ++ MemOp.InnerDisp = MCConstantExpr::create(0, Parser.getContext(), true, 4); ++ HasIndex = true; ++ } ++ ++ if (Parser.getTok().isNot(AsmToken::RParen)) { ++ Error(getLexer().getLoc(), "expected )"); ++ return MatchOperand_ParseFail; ++ } ++ Parser.Lex(); ++ ++ bool IsPI = false; ++ if (!IsPD && Parser.getTok().is(AsmToken::Plus)) { ++ Parser.Lex(); ++ IsPI = true; ++ } ++ ++ SMLoc End = getLexer().getLoc(); ++ ++ unsigned OpCount = IsPD + IsPI + (HasIndex || HasDisplacement); ++ if (OpCount > 1) { ++ Error(Start, "only one of post-increment, pre-decrement or displacement " ++ "can be used"); ++ return MatchOperand_ParseFail; ++ } ++ ++ if (IsPD) { ++ MemOp.Op = M68kMemOp::Kind::RegPreDecrement; ++ } else if (IsPI) { ++ MemOp.Op = M68kMemOp::Kind::RegPostIncrement; ++ } else if (HasIndex) { ++ MemOp.Op = M68kMemOp::Kind::RegIndirectDisplacementIndex; ++ } else if (HasDisplacement) { ++ MemOp.Op = M68kMemOp::Kind::RegIndirectDisplacement; ++ } else { ++ MemOp.Op = M68kMemOp::Kind::RegIndirect; ++ } ++ ++ Operands.push_back(M68kOperand::createMemOp(MemOp, Start, End)); ++ return MatchOperand_Success; ++} ++ ++void M68kAsmParser::eatComma() { ++ if (Parser.getTok().is(AsmToken::Comma)) { ++ Parser.Lex(); ++ } ++} ++ ++bool M68kAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, ++ SMLoc NameLoc, OperandVector &Operands) { ++ SMLoc Start = getLexer().getLoc(); ++ Operands.push_back(M68kOperand::createToken(Name, Start, Start)); ++ ++ bool First = true; ++ while (Parser.getTok().isNot(AsmToken::EndOfStatement)) { ++ if (!First) { ++ eatComma(); ++ } else { ++ First = false; ++ } ++ ++ auto MatchResult = MatchOperandParserImpl(Operands, Name); ++ if (MatchResult == MatchOperand_Success) { ++ continue; ++ } ++ ++ // Add custom operand formats here... ++ SMLoc Loc = getLexer().getLoc(); ++ Parser.eatToEndOfStatement(); ++ return Error(Loc, "unexpected token parsing operands"); ++ } ++ ++ // Eat EndOfStatement. ++ Parser.Lex(); ++ return false; ++} ++ ++bool M68kAsmParser::ParseDirective(AsmToken DirectiveID) { return true; } ++ ++bool M68kAsmParser::invalidOperand(SMLoc const &Loc, ++ OperandVector const &Operands, ++ uint64_t const &ErrorInfo) { ++ SMLoc ErrorLoc = Loc; ++ char const *Diag = 0; ++ ++ if (ErrorInfo != ~0U) { ++ if (ErrorInfo >= Operands.size()) { ++ Diag = "too few operands for instruction."; ++ } else { ++ auto const &Op = (M68kOperand const &)*Operands[ErrorInfo]; ++ if (Op.getStartLoc() != SMLoc()) { ++ ErrorLoc = Op.getStartLoc(); ++ } ++ } ++ } ++ ++ if (!Diag) { ++ Diag = "invalid operand for instruction"; ++ } ++ ++ return Error(ErrorLoc, Diag); ++} ++ ++bool M68kAsmParser::missingFeature(llvm::SMLoc const &Loc, ++ uint64_t const &ErrorInfo) { ++ return Error(Loc, "instruction requires a CPU feature not currently enabled"); ++} ++ ++bool M68kAsmParser::emit(MCInst &Inst, SMLoc const &Loc, ++ MCStreamer &Out) const { ++ Inst.setLoc(Loc); ++ Out.emitInstruction(Inst, STI); ++ ++ return false; ++} ++ ++bool M68kAsmParser::MatchAndEmitInstruction(SMLoc Loc, unsigned &Opcode, ++ OperandVector &Operands, ++ MCStreamer &Out, ++ uint64_t &ErrorInfo, ++ bool MatchingInlineAsm) { ++ MCInst Inst; ++ unsigned MatchResult = ++ MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); ++ ++ switch (MatchResult) { ++ case Match_Success: ++ return emit(Inst, Loc, Out); ++ case Match_MissingFeature: ++ return missingFeature(Loc, ErrorInfo); ++ case Match_InvalidOperand: ++ return invalidOperand(Loc, Operands, ErrorInfo); ++ case Match_MnemonicFail: ++ return Error(Loc, "invalid instruction"); ++ default: ++ return true; ++ } ++} ++ ++void M68kOperand::print(raw_ostream &OS) const { ++ switch (Kind) { ++ case Kind::Invalid: ++ OS << "invalid"; ++ break; ++ ++ case Kind::Token: ++ OS << "token '" << Token << "'"; ++ break; ++ ++ case Kind::Imm: ++ OS << "immediate " << Imm; ++ break; ++ ++ case Kind::MemOp: ++ MemOp.print(OS); ++ break; ++ ++ default: ++ llvm_unreachable("unhandled operand kind"); ++ } ++} +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 +@@ -10,6 +10,7 @@ + tablegen(LLVM M68kGenDAGISel.inc -gen-dag-isel) + tablegen(LLVM M68kGenCallingConv.inc -gen-callingconv) + tablegen(LLVM M68kGenAsmWriter.inc -gen-asm-writer) ++tablegen(LLVM M68kGenAsmMatcher.inc -gen-asm-matcher) + + add_public_tablegen_target(M68kCommonTableGen) + +@@ -46,3 +47,4 @@ + + add_subdirectory(TargetInfo) + add_subdirectory(MCTargetDesc) ++add_subdirectory(AsmParser) +diff --git a/llvm/lib/Target/M68k/M68k.td b/llvm/lib/Target/M68k/M68k.td +--- a/llvm/lib/Target/M68k/M68k.td ++++ b/llvm/lib/Target/M68k/M68k.td +@@ -84,10 +84,34 @@ + + include "M68kCallingConv.td" + ++//===---------------------------------------------------------------------===// ++// Assembly Printers ++//===---------------------------------------------------------------------===// ++ ++def M68kAsmWriter : AsmWriter { ++ string AsmWriterClassName = "InstPrinter"; ++ bit isMCAsmWriter = 1; ++} ++ ++//===---------------------------------------------------------------------===// ++// Assembly Parsers ++//===---------------------------------------------------------------------===// ++ ++def M68kAsmParser : AsmParser { ++ let ShouldEmitMatchRegisterName = 0; ++ let ShouldEmitMatchRegisterAltName = 0; ++} ++ ++def M68kAsmParserVariant : AsmParserVariant { ++ int Variant = 0; ++} ++ + //===----------------------------------------------------------------------===// + // Target + //===----------------------------------------------------------------------===// + + def M68k : Target { + let InstructionSet = M68kInstrInfo; ++ let AssemblyParsers = [M68kAsmParser]; ++ let AssemblyWriters = [M68kAsmWriter]; + } +diff --git a/llvm/lib/Target/M68k/M68kInstrInfo.td b/llvm/lib/Target/M68k/M68kInstrInfo.td +--- a/llvm/lib/Target/M68k/M68kInstrInfo.td ++++ b/llvm/lib/Target/M68k/M68kInstrInfo.td +@@ -165,6 +165,13 @@ + def MxSize16 : MxSize<16, "w", "word">; + def MxSize32 : MxSize<32, "l", "long">; + ++class MxOpClass : AsmOperandClass { ++ let Name = name; ++ let ParserMethod = "parseMemOp"; ++} ++ ++def MxRegClass : MxOpClass<"Reg">; ++ + class MxOperand { + ValueType VT = vt; + string Letter = letter; +@@ -179,7 +186,9 @@ + string letter, + string pm = "printOperand"> + : RegisterOperand, +- MxOperand; ++ MxOperand { ++ let ParserMatchClass = MxRegClass; ++} + + // REGISTER DIRECT. The operand is in the data register specified by + // the effective address register field. +@@ -206,11 +215,6 @@ + def MxARD16_TC : MxRegOp; + def MxARD32_TC : MxRegOp; + +-class MxOpClass : AsmOperandClass { +- let Name = name; +- let ParserMethod = "parse"#name; +-} +- + class MxMemOp +@@ -338,7 +342,12 @@ + def MxPCI32 : MxMemOp<(ops i8imm, XR32), MxSize32, "k", "printPCI32Mem", MxPCI>; + } // OPERAND_PCREL + +-def MxImm : MxOpClass<"MxImm">; ++def MxImm : AsmOperandClass { ++ let Name = "MxImm"; ++ let PredicateMethod = "isImm"; ++ let RenderMethod = "addImmOperands"; ++ let ParserMethod = "parseImm"; ++} + + class MxOp + : Operand, +@@ -362,7 +371,7 @@ + } // OPERAND_IMMEDIATE + + let OperandType = "OPERAND_PCREL", +- ParserMatchClass = MxImm, ++ ParserMatchClass = MxAddr, + PrintMethod = "printPCRelImm" in { + + // Branch targets have OtherVT type and print as pc-relative values. +@@ -378,7 +387,6 @@ + let PrintMethod = "printMoveMask"; + } + +- + //===----------------------------------------------------------------------===// + // Predicates + //===----------------------------------------------------------------------===// +diff --git a/llvm/lib/Target/M68k/MCTargetDesc/M68kMCAsmInfo.cpp b/llvm/lib/Target/M68k/MCTargetDesc/M68kMCAsmInfo.cpp +--- a/llvm/lib/Target/M68k/MCTargetDesc/M68kMCAsmInfo.cpp ++++ b/llvm/lib/Target/M68k/MCTargetDesc/M68kMCAsmInfo.cpp +@@ -31,5 +31,6 @@ + // Exceptions handling + ExceptionsType = ExceptionHandling::DwarfCFI; + ++ UseMotorolaIntegers = true; + CommentString = ";"; + } +diff --git a/llvm/test/MC/M68k/instructions.s b/llvm/test/MC/M68k/instructions.s +new file mode 100644 +--- /dev/null ++++ b/llvm/test/MC/M68k/instructions.s +@@ -0,0 +1,42 @@ ++; RUN: llvm-mc -triple m68k -show-encoding -motorola-integers %s | FileCheck -check-prefixes=CHECK %s ++ ++.global ext_fn ++ ++// CHECK: move.l %a1, %a0 ++move.l %a1, %a0 ++// CHECK: add.l %a0, %a1 ++add.l %a0, %a1 ++// CHECK: addx.l %d1, %d2 ++addx.l %d1, %d2 ++// CHECK: sub.w #4, %d1 ++sub.w #4, %d1 ++// CHECK: cmp.w %a0, %d0 ++cmp.w %a0, %d0 ++// CHECK: neg.w %d0 ++neg.w %d0 ++// CHECK: btst #8, %d3 ++btst #$8, %d3 ++// CHECK: bra ext_fn ++bra ext_fn ++// CHECK: jsr ext_fn ++jsr ext_fn ++// CHECK: seq %d0 ++seq %d0 ++// CHECK: sgt %d0 ++sgt %d0 ++// CHECK: lea (80,%a0), %a1 ++lea $50(%a0), %a1 ++// CHECK: lsl.l #8, %a1 ++lsl.l #8, %a1 ++// CHECK: lsr.l #8, %a1 ++lsr.l #8, %a1 ++// CHECK: asr.l #8, %a1 ++asr.l #8, %a1 ++// CHECK: rol.l #8, %a1 ++rol.l #8, %a1 ++// CHECK: ror.l #8, %a1 ++ror.l #8, %a1 ++// CHECK: nop ++nop ++// CHECK: rts ++rts +diff --git a/llvm/test/MC/M68k/lit.local.cfg b/llvm/test/MC/M68k/lit.local.cfg +new file mode 100644 +--- /dev/null ++++ b/llvm/test/MC/M68k/lit.local.cfg +@@ -0,0 +1,2 @@ ++if not 'M68k' in config.root.targets: ++ config.unsupported = True + diff --git a/debian/patches/series b/debian/patches/series index 6f237ec3..ec5b279e 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -120,6 +120,7 @@ bootstrap-fix-include-next.diff # m68k D98519.diff +D98537.diff # riscv64 risc/clang-riscv64-multiarch.diff