[llvm] 8ba622b - [CSKY 4/n] Add basic CSKYAsmParser and CSKYInstPrinter

Zi Xuan Wu via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 20 00:38:45 PDT 2021


Author: Zi Xuan Wu
Date: 2021-04-20T15:36:49+08:00
New Revision: 8ba622bae114960ca9b09cd5bd65a921ea99657c

URL: https://github.com/llvm/llvm-project/commit/8ba622bae114960ca9b09cd5bd65a921ea99657c
DIFF: https://github.com/llvm/llvm-project/commit/8ba622bae114960ca9b09cd5bd65a921ea99657c.diff

LOG: [CSKY 4/n] Add basic CSKYAsmParser and CSKYInstPrinter

This basic parser will handle basic instructions with register or immediate operands.
With the addition of CSKYInstPrinter, we can now make use of lit tests.

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

Added: 
    llvm/lib/Target/CSKY/AsmParser/CMakeLists.txt
    llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
    llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.cpp
    llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.h
    llvm/test/MC/CSKY/basic.s
    llvm/test/MC/CSKY/lit.local.cfg

Modified: 
    llvm/lib/Target/CSKY/CMakeLists.txt
    llvm/lib/Target/CSKY/CSKY.td
    llvm/lib/Target/CSKY/CSKYInstrInfo.td
    llvm/lib/Target/CSKY/MCTargetDesc/CMakeLists.txt
    llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/CSKY/AsmParser/CMakeLists.txt b/llvm/lib/Target/CSKY/AsmParser/CMakeLists.txt
new file mode 100644
index 0000000000000..e7b5cdbdec712
--- /dev/null
+++ b/llvm/lib/Target/CSKY/AsmParser/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_llvm_component_library(LLVMCSKYAsmParser
+  CSKYAsmParser.cpp
+
+  LINK_COMPONENTS
+  CSKYDesc
+  CSKYInfo
+  MC
+  MCParser
+  Support
+
+  ADD_TO_COMPONENT
+  CSKY
+  )

diff  --git a/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp b/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
new file mode 100644
index 0000000000000..718b14cc523fc
--- /dev/null
+++ b/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
@@ -0,0 +1,476 @@
+//===-- CSKYAsmParser.cpp - Parse CSKY assembly to MCInst instructions --===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/CSKYMCTargetDesc.h"
+#include "TargetInfo/CSKYTargetInfo.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/CodeGen/Register.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+namespace {
+struct CSKYOperand;
+
+class CSKYAsmParser : public MCTargetAsmParser {
+
+  bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo,
+                                  int64_t Lower, int64_t Upper, Twine Msg);
+
+  SMLoc getLoc() const { return getParser().getTok().getLoc(); }
+
+  bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
+                               OperandVector &Operands, MCStreamer &Out,
+                               uint64_t &ErrorInfo,
+                               bool MatchingInlineAsm) override;
+
+  bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
+
+  bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
+                        SMLoc NameLoc, OperandVector &Operands) override;
+
+  bool ParseDirective(AsmToken DirectiveID) override;
+
+  OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc,
+                                        SMLoc &EndLoc) override;
+
+// Auto-generated instruction matching functions
+#define GET_ASSEMBLER_HEADER
+#include "CSKYGenAsmMatcher.inc"
+
+  OperandMatchResultTy parseImmediate(OperandVector &Operands);
+  OperandMatchResultTy parseRegister(OperandVector &Operands);
+
+  bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
+
+public:
+  enum CSKYMatchResultTy {
+    Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
+#define GET_OPERAND_DIAGNOSTIC_TYPES
+#include "CSKYGenAsmMatcher.inc"
+#undef GET_OPERAND_DIAGNOSTIC_TYPES
+  };
+
+  CSKYAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
+                const MCInstrInfo &MII, const MCTargetOptions &Options)
+      : MCTargetAsmParser(Options, STI, MII) {
+    setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
+  }
+};
+
+/// Instances of this class represent a parsed machine instruction.
+struct CSKYOperand : public MCParsedAsmOperand {
+  enum KindTy {
+    Token,
+    Register,
+    Immediate,
+  } Kind;
+
+  struct RegOp {
+    unsigned RegNum;
+  };
+
+  struct ImmOp {
+    const MCExpr *Val;
+  };
+
+  SMLoc StartLoc, EndLoc;
+  union {
+    StringRef Tok;
+    RegOp Reg;
+    ImmOp Imm;
+  };
+
+  CSKYOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
+
+public:
+  CSKYOperand(const CSKYOperand &o) : MCParsedAsmOperand() {
+    Kind = o.Kind;
+    StartLoc = o.StartLoc;
+    EndLoc = o.EndLoc;
+    switch (Kind) {
+    case Register:
+      Reg = o.Reg;
+      break;
+    case Immediate:
+      Imm = o.Imm;
+      break;
+    case Token:
+      Tok = o.Tok;
+      break;
+    }
+  }
+
+  bool isToken() const override { return Kind == Token; }
+  bool isReg() const override { return Kind == Register; }
+  bool isImm() const override { return Kind == Immediate; }
+  bool isMem() const override { return false; }
+
+  static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm) {
+    if (auto CE = dyn_cast<MCConstantExpr>(Expr)) {
+      Imm = CE->getValue();
+      return true;
+    }
+
+    return false;
+  }
+
+  template <unsigned num> bool isUImm() const {
+    if (!isImm())
+      return false;
+
+    int64_t Imm;
+    bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
+    return IsConstantImm && isUInt<num>(Imm);
+  }
+
+  template <unsigned num> bool isOImm() const {
+    if (!isImm())
+      return false;
+
+    int64_t Imm;
+    bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
+    return IsConstantImm && isUInt<num>(Imm - 1);
+  }
+
+  template <unsigned num> bool isSImm() const {
+    if (!isImm())
+      return false;
+
+    int64_t Imm;
+    bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
+    return IsConstantImm && isInt<num>(Imm);
+  }
+
+  bool isUImm5() const { return isUImm<5>(); }
+  bool isUImm12() const { return isUImm<12>(); }
+  bool isOImm12() const { return isOImm<12>(); }
+
+  /// Gets location of the first token of this operand.
+  SMLoc getStartLoc() const override { return StartLoc; }
+  /// Gets location of the last token of this operand.
+  SMLoc getEndLoc() const override { return EndLoc; }
+
+  unsigned getReg() const override {
+    assert(Kind == Register && "Invalid type access!");
+    return Reg.RegNum;
+  }
+
+  const MCExpr *getImm() const {
+    assert(Kind == Immediate && "Invalid type access!");
+    return Imm.Val;
+  }
+
+  StringRef getToken() const {
+    assert(Kind == Token && "Invalid type access!");
+    return Tok;
+  }
+
+  void print(raw_ostream &OS) const override {
+    switch (Kind) {
+    case Immediate:
+      OS << *getImm();
+      break;
+    case Register:
+      OS << "<register x" << getReg() << ">";
+      break;
+    case Token:
+      OS << "'" << getToken() << "'";
+      break;
+    }
+  }
+
+  static std::unique_ptr<CSKYOperand> createToken(StringRef Str, SMLoc S) {
+    auto Op = std::make_unique<CSKYOperand>(Token);
+    Op->Tok = Str;
+    Op->StartLoc = S;
+    Op->EndLoc = S;
+    return Op;
+  }
+
+  static std::unique_ptr<CSKYOperand> createReg(unsigned RegNo, SMLoc S,
+                                                SMLoc E) {
+    auto Op = std::make_unique<CSKYOperand>(Register);
+    Op->Reg.RegNum = RegNo;
+    Op->StartLoc = S;
+    Op->EndLoc = E;
+    return Op;
+  }
+
+  static std::unique_ptr<CSKYOperand> createImm(const MCExpr *Val, SMLoc S,
+                                                SMLoc E) {
+    auto Op = std::make_unique<CSKYOperand>(Immediate);
+    Op->Imm.Val = Val;
+    Op->StartLoc = S;
+    Op->EndLoc = E;
+    return Op;
+  }
+
+  void addExpr(MCInst &Inst, const MCExpr *Expr) const {
+    assert(Expr && "Expr shouldn't be null!");
+    if (auto *CE = dyn_cast<MCConstantExpr>(Expr))
+      Inst.addOperand(MCOperand::createImm(CE->getValue()));
+    else
+      Inst.addOperand(MCOperand::createExpr(Expr));
+  }
+
+  // Used by the TableGen Code.
+  void addRegOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    Inst.addOperand(MCOperand::createReg(getReg()));
+  }
+
+  void addImmOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    addExpr(Inst, getImm());
+  }
+};
+} // end anonymous namespace.
+
+#define GET_REGISTER_MATCHER
+#define GET_SUBTARGET_FEATURE_NAME
+#define GET_MATCHER_IMPLEMENTATION
+#define GET_MNEMONIC_SPELL_CHECKER
+#include "CSKYGenAsmMatcher.inc"
+
+static std::string CSKYMnemonicSpellCheck(StringRef S, const FeatureBitset &FBS,
+                                          unsigned VariantID = 0);
+
+bool CSKYAsmParser::generateImmOutOfRangeError(
+    OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper,
+    Twine Msg = "immediate must be an integer in the range") {
+  SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc();
+  return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]");
+}
+
+bool CSKYAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
+                                            OperandVector &Operands,
+                                            MCStreamer &Out,
+                                            uint64_t &ErrorInfo,
+                                            bool MatchingInlineAsm) {
+  MCInst Inst;
+  FeatureBitset MissingFeatures;
+
+  auto Result = MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
+                                     MatchingInlineAsm);
+  switch (Result) {
+  default:
+    break;
+  case Match_Success:
+    Inst.setLoc(IDLoc);
+    Out.emitInstruction(Inst, getSTI());
+    return false;
+  case Match_MissingFeature: {
+    assert(MissingFeatures.any() && "Unknown missing features!");
+    ListSeparator LS;
+    std::string Msg = "instruction requires the following: ";
+    for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
+      if (MissingFeatures[i]) {
+        Msg += LS;
+        Msg += getSubtargetFeatureName(i);
+      }
+    }
+    return Error(IDLoc, Msg);
+  }
+  case Match_MnemonicFail: {
+    FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
+    std::string Suggestion =
+        CSKYMnemonicSpellCheck(((CSKYOperand &)*Operands[0]).getToken(), FBS);
+    return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion);
+  }
+  case Match_InvalidOperand: {
+    SMLoc ErrorLoc = IDLoc;
+    if (ErrorInfo != ~0U) {
+      if (ErrorInfo >= Operands.size())
+        return Error(ErrorLoc, "too few operands for instruction");
+
+      ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc();
+      if (ErrorLoc == SMLoc())
+        ErrorLoc = IDLoc;
+    }
+    return Error(ErrorLoc, "invalid operand for instruction");
+  }
+  }
+
+  // Handle the case when the error message is of specific type
+  // other than the generic Match_InvalidOperand, and the
+  // corresponding operand is missing.
+  if (Result > FIRST_TARGET_MATCH_RESULT_TY) {
+    SMLoc ErrorLoc = IDLoc;
+    if (ErrorInfo != ~0U && ErrorInfo >= Operands.size())
+      return Error(ErrorLoc, "too few operands for instruction");
+  }
+
+  switch (Result) {
+  default:
+    break;
+  case Match_InvalidOImm12:
+    return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 12));
+  case Match_InvalidUImm12:
+    return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 12) - 1);
+  case Match_InvalidUImm5:
+    return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1);
+  }
+
+  llvm_unreachable("Unknown match type detected!");
+}
+
+// Attempts to match Name as a register (either using the default name or
+// alternative ABI names), setting RegNo to the matching register. Upon
+// failure, returns true and sets RegNo to 0.
+static bool matchRegisterNameHelper(MCRegister &RegNo, StringRef Name) {
+  RegNo = MatchRegisterName(Name);
+
+  if (RegNo == CSKY::NoRegister)
+    RegNo = MatchRegisterAltName(Name);
+
+  return RegNo == CSKY::NoRegister;
+}
+
+bool CSKYAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
+                                  SMLoc &EndLoc) {
+  const AsmToken &Tok = getParser().getTok();
+  StartLoc = Tok.getLoc();
+  EndLoc = Tok.getEndLoc();
+  StringRef Name = getLexer().getTok().getIdentifier();
+
+  if (!matchRegisterNameHelper((MCRegister &)RegNo, Name)) {
+    getParser().Lex(); // Eat identifier token.
+    return false;
+  }
+
+  return Error(StartLoc, "invalid register name");
+}
+
+OperandMatchResultTy CSKYAsmParser::parseRegister(OperandVector &Operands) {
+  SMLoc S = getLoc();
+  SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
+
+  switch (getLexer().getKind()) {
+  default:
+    return MatchOperand_NoMatch;
+  case AsmToken::Identifier: {
+    StringRef Name = getLexer().getTok().getIdentifier();
+    MCRegister RegNo;
+
+    if (matchRegisterNameHelper((MCRegister &)RegNo, Name))
+      return MatchOperand_NoMatch;
+
+    getLexer().Lex();
+    Operands.push_back(CSKYOperand::createReg(RegNo, S, E));
+
+    return MatchOperand_Success;
+  }
+  }
+}
+
+OperandMatchResultTy CSKYAsmParser::parseImmediate(OperandVector &Operands) {
+  switch (getLexer().getKind()) {
+  default:
+    return MatchOperand_NoMatch;
+  case AsmToken::LParen:
+  case AsmToken::Minus:
+  case AsmToken::Plus:
+  case AsmToken::Integer:
+  case AsmToken::String:
+    break;
+  }
+
+  const MCExpr *IdVal;
+  SMLoc S = getLoc();
+  if (getParser().parseExpression(IdVal))
+    return MatchOperand_ParseFail;
+
+  SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
+  Operands.push_back(CSKYOperand::createImm(IdVal, S, E));
+  return MatchOperand_Success;
+}
+
+/// Looks at a token type and creates the relevant operand from this
+/// information, adding to Operands. If operand was parsed, returns false, else
+/// true.
+bool CSKYAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
+  // Attempt to parse token as register
+  if (parseRegister(Operands) == MatchOperand_Success)
+    return false;
+
+  // Attempt to parse token as a imm.
+  if (parseImmediate(Operands) == MatchOperand_Success)
+    return false;
+
+  // Finally we have exhausted all options and must declare defeat.
+  Error(getLoc(), "unknown operand");
+  return true;
+}
+
+bool CSKYAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
+                                     SMLoc NameLoc, OperandVector &Operands) {
+  // First operand is token for instruction.
+  Operands.push_back(CSKYOperand::createToken(Name, NameLoc));
+
+  // If there are no more operands, then finish.
+  if (getLexer().is(AsmToken::EndOfStatement))
+    return false;
+
+  // Parse first operand.
+  if (parseOperand(Operands, Name))
+    return true;
+
+  // Parse until end of statement, consuming commas between operands.
+  while (getLexer().is(AsmToken::Comma)) {
+    // Consume comma token.
+    getLexer().Lex();
+
+    // Parse next operand.
+    if (parseOperand(Operands, Name))
+      return true;
+  }
+
+  if (getLexer().isNot(AsmToken::EndOfStatement)) {
+    SMLoc Loc = getLexer().getLoc();
+    getParser().eatToEndOfStatement();
+    return Error(Loc, "unexpected token");
+  }
+
+  getParser().Lex(); // Consume the EndOfStatement.
+  return false;
+}
+
+OperandMatchResultTy CSKYAsmParser::tryParseRegister(unsigned &RegNo,
+                                                     SMLoc &StartLoc,
+                                                     SMLoc &EndLoc) {
+  const AsmToken &Tok = getParser().getTok();
+  StartLoc = Tok.getLoc();
+  EndLoc = Tok.getEndLoc();
+
+  StringRef Name = getLexer().getTok().getIdentifier();
+
+  if (matchRegisterNameHelper((MCRegister &)RegNo, Name))
+    return MatchOperand_NoMatch;
+
+  getParser().Lex(); // Eat identifier token.
+  return MatchOperand_Success;
+}
+
+bool CSKYAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
+
+extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmParser() {
+  RegisterMCAsmParser<CSKYAsmParser> X(getTheCSKYTarget());
+}

diff  --git a/llvm/lib/Target/CSKY/CMakeLists.txt b/llvm/lib/Target/CSKY/CMakeLists.txt
index ec487ed34bbf9..c49c2a02e7f04 100644
--- a/llvm/lib/Target/CSKY/CMakeLists.txt
+++ b/llvm/lib/Target/CSKY/CMakeLists.txt
@@ -2,9 +2,12 @@ add_llvm_component_group(CSKY)
 
 set(LLVM_TARGET_DEFINITIONS CSKY.td)
 
-tablegen(LLVM CSKYGenRegisterInfo.inc -gen-register-info)
+tablegen(LLVM CSKYGenAsmMatcher.inc -gen-asm-matcher)
+tablegen(LLVM CSKYGenAsmWriter.inc -gen-asm-writer)
 tablegen(LLVM CSKYGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM CSKYGenMCCodeEmitter.inc -gen-emitter)
+tablegen(LLVM CSKYGenRegisterInfo.inc -gen-register-info)
+tablegen(LLVM CSKYGenSubtargetInfo.inc -gen-subtarget)
 
 add_public_tablegen_target(CSKYCommonTableGen)
 
@@ -22,5 +25,6 @@ add_llvm_target(CSKYCodeGen
   CSKY
   )
 
-add_subdirectory(TargetInfo)
+add_subdirectory(AsmParser)
 add_subdirectory(MCTargetDesc)
+add_subdirectory(TargetInfo)

diff  --git a/llvm/lib/Target/CSKY/CSKY.td b/llvm/lib/Target/CSKY/CSKY.td
index da6151befa1b3..854a8b5f22a21 100644
--- a/llvm/lib/Target/CSKY/CSKY.td
+++ b/llvm/lib/Target/CSKY/CSKY.td
@@ -19,7 +19,7 @@ include "CSKYInstrInfo.td"
 // CSKY processors supported.
 //===----------------------------------------------------------------------===//
 
-def : ProcessorModel<"generic-csky", NoSchedModel, []>;
+def : ProcessorModel<"generic", NoSchedModel, []>;
 
 //===----------------------------------------------------------------------===//
 // Define the CSKY target.
@@ -27,6 +27,19 @@ def : ProcessorModel<"generic-csky", NoSchedModel, []>;
 
 def CSKYInstrInfo : InstrInfo;
 
+
+def CSKYAsmParser : AsmParser {
+  let ShouldEmitMatchRegisterAltName = 1;
+  let AllowDuplicateRegisterNames = 1;
+}
+
+def CSKYAsmWriter : AsmWriter {
+  int PassSubtarget = 1;
+}
+
 def CSKY : Target {
   let InstructionSet = CSKYInstrInfo;
+  let AssemblyParsers = [CSKYAsmParser];
+  let AssemblyWriters = [CSKYAsmWriter];
+  let AllowRegisterRenaming = 1;
 }

diff  --git a/llvm/lib/Target/CSKY/CSKYInstrInfo.td b/llvm/lib/Target/CSKY/CSKYInstrInfo.td
index 7add217530e19..88985a968c902 100644
--- a/llvm/lib/Target/CSKY/CSKYInstrInfo.td
+++ b/llvm/lib/Target/CSKY/CSKYInstrInfo.td
@@ -21,20 +21,40 @@ include "CSKYInstrFormats.td"
 //===----------------------------------------------------------------------===//
 // Operand and SDNode transformation definitions.
 //===----------------------------------------------------------------------===//
+class ImmAsmOperand<string prefix, int width, string suffix> : AsmOperandClass {
+  let Name = prefix # "Imm" # width # suffix;
+  let RenderMethod = "addImmOperands";
+  let DiagnosticType = !strconcat("Invalid", Name);
+}
+
+class SImmAsmOperand<int width, string suffix = "">
+    : ImmAsmOperand<"S", width, suffix> {
+}
+
+class UImmAsmOperand<int width, string suffix = "">
+    : ImmAsmOperand<"U", width, suffix> {
+}
+
+class OImmAsmOperand<int width, string suffix = "">
+    : ImmAsmOperand<"O", width, suffix> {
+}
 
 class oimm<int num> : Operand<i32>,
   ImmLeaf<i32, "return isUInt<"#num#">(Imm - 1);"> {
   let EncoderMethod = "getOImmOpValue";
+  let ParserMatchClass = OImmAsmOperand<num>;
 }
 
 class uimm<int num, int shift = 0> : Operand<i32>,
   ImmLeaf<i32, "return isShiftedUInt<"#num#", "#shift#">(Imm);"> {
   let EncoderMethod = "getImmOpValue<"#shift#">";
+  let ParserMatchClass = UImmAsmOperand<num>;
 }
 
 class simm<int num, int shift = 0> : Operand<i32>,
   ImmLeaf<i32, "return isShiftedInt<"#num#", "#shift#">(Imm);"> {
   let EncoderMethod = "getImmOpValue<"#shift#">";
+  let ParserMatchClass = SImmAsmOperand<num>;
 }
 
 def nimm_XFORM : SDNodeXForm<imm, [{
@@ -42,6 +62,7 @@ def nimm_XFORM : SDNodeXForm<imm, [{
 }]>;
 class nimm<int num> : Operand<i32>,
   ImmLeaf<i32, "return isUInt<"#num#">(~Imm);", nimm_XFORM> {
+  let ParserMatchClass = UImmAsmOperand<num>;
 }
 
 
@@ -105,4 +126,4 @@ def DIVU32 : R_YXZ_SP_F1<0x20, 0x1,
   BinOpFrag<(udiv node:$LHS, node:$RHS)>, "divu32">;
 
 def NOT32 : R_XXZ<0b001001, 0b00100, (outs GPR:$rz), (ins GPR:$rx),
-  "not", [(set GPR:$rz, (not GPR:$rx))]>;
+  "not32", [(set GPR:$rz, (not GPR:$rx))]>;

diff  --git a/llvm/lib/Target/CSKY/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/CSKY/MCTargetDesc/CMakeLists.txt
index f5d7df002a881..d084266dd0b23 100644
--- a/llvm/lib/Target/CSKY/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CMakeLists.txt
@@ -1,13 +1,14 @@
 add_llvm_component_library(LLVMCSKYDesc
   CSKYAsmBackend.cpp
   CSKYELFObjectWriter.cpp
+  CSKYInstPrinter.cpp
   CSKYMCAsmInfo.cpp
   CSKYMCTargetDesc.cpp
   CSKYMCCodeEmitter.cpp
 
   LINK_COMPONENTS
-  MC
   CSKYInfo
+  MC
   Support
 
   ADD_TO_COMPONENT

diff  --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.cpp b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.cpp
new file mode 100644
index 0000000000000..c8920fbb4b4c1
--- /dev/null
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.cpp
@@ -0,0 +1,101 @@
+//===-- CSKYInstPrinter.cpp - Convert CSKY MCInst to asm syntax ---------===//
+//
+// 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 class prints an CSKY MCInst to a .s file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CSKYInstPrinter.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormattedStream.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "csky-asm-printer"
+
+// Include the auto-generated portion of the assembly writer.
+#define PRINT_ALIAS_INSTR
+#include "CSKYGenAsmWriter.inc"
+
+static cl::opt<bool>
+    NoAliases("csky-no-aliases",
+              cl::desc("Disable the emission of assembler pseudo instructions"),
+              cl::init(false), cl::Hidden);
+
+static cl::opt<bool>
+    ArchRegNames("csky-arch-reg-names",
+                 cl::desc("Print architectural register names rather than the "
+                          "ABI names (such as r14 instead of sp)"),
+                 cl::init(false), cl::Hidden);
+
+// The command-line flags above are used by llvm-mc and llc. They can be used by
+// `llvm-objdump`, but we override their values here to handle options passed to
+// `llvm-objdump` with `-M` (which matches GNU objdump). There did not seem to
+// be an easier way to allow these options in all these tools, without doing it
+// this way.
+bool CSKYInstPrinter::applyTargetSpecificCLOption(StringRef Opt) {
+  if (Opt == "no-aliases") {
+    NoAliases = true;
+    return true;
+  }
+  if (Opt == "numeric") {
+    ArchRegNames = true;
+    return true;
+  }
+
+  return false;
+}
+
+void CSKYInstPrinter::printInst(const MCInst *MI, uint64_t Address,
+                                StringRef Annot, const MCSubtargetInfo &STI,
+                                raw_ostream &O) {
+  const MCInst *NewMI = MI;
+
+  if (NoAliases || !printAliasInstr(NewMI, Address, STI, O))
+    printInstruction(NewMI, Address, STI, O);
+  printAnnotation(O, Annot);
+}
+
+void CSKYInstPrinter::printRegName(raw_ostream &O, unsigned RegNo) const {
+  O << getRegisterName(RegNo);
+}
+
+void CSKYInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
+                                   const MCSubtargetInfo &STI, raw_ostream &O,
+                                   const char *Modifier) {
+  assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
+  const MCOperand &MO = MI->getOperand(OpNo);
+
+  if (MO.isReg()) {
+    if (MO.getReg() == CSKY::C)
+      O << "";
+    else
+      printRegName(O, MO.getReg());
+    return;
+  }
+
+  if (MO.isImm()) {
+    O << formatImm(MO.getImm());
+    return;
+  }
+
+  assert(MO.isExpr() && "Unknown operand kind in printOperand");
+  MO.getExpr()->print(O, &MAI);
+}
+
+const char *CSKYInstPrinter::getRegisterName(unsigned RegNo) {
+  return getRegisterName(RegNo, ArchRegNames ? CSKY::NoRegAltName
+                                             : CSKY::ABIRegAltName);
+}

diff  --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.h b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.h
new file mode 100644
index 0000000000000..a28791a6d8e90
--- /dev/null
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.h
@@ -0,0 +1,52 @@
+//===-- CSKYInstPrinter.h - Convert CSKY MCInst to asm syntax ---*- 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 class prints a CSKY MCInst to a .s file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYINSTPRINTER_H
+#define LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYINSTPRINTER_H
+
+#include "MCTargetDesc/CSKYMCTargetDesc.h"
+#include "llvm/MC/MCInstPrinter.h"
+
+namespace llvm {
+
+class CSKYInstPrinter : public MCInstPrinter {
+public:
+  CSKYInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
+                  const MCRegisterInfo &MRI)
+      : MCInstPrinter(MAI, MII, MRI) {}
+
+  bool applyTargetSpecificCLOption(StringRef Opt) override;
+
+  void printInst(const MCInst *MI, uint64_t Address, StringRef Annot,
+                 const MCSubtargetInfo &STI, raw_ostream &O) override;
+  void printRegName(raw_ostream &O, unsigned RegNo) const override;
+
+  void printOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+                    raw_ostream &O, const char *Modifier = nullptr);
+
+  // Autogenerated by tblgen.
+  std::pair<const char *, uint64_t> getMnemonic(const MCInst *MI) override;
+  void printInstruction(const MCInst *MI, uint64_t Address,
+                        const MCSubtargetInfo &STI, raw_ostream &O);
+  bool printAliasInstr(const MCInst *MI, uint64_t Address,
+                       const MCSubtargetInfo &STI, raw_ostream &O);
+  void printCustomAliasOperand(const MCInst *MI, uint64_t Address,
+                               unsigned OpIdx, unsigned PrintMethodIdx,
+                               const MCSubtargetInfo &STI, raw_ostream &O);
+
+  static const char *getRegisterName(unsigned RegNo);
+  static const char *getRegisterName(unsigned RegNo, unsigned AltIdx);
+};
+
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYINSTPRINTER_H

diff  --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp
index 876000a370047..169e1e14eb0a4 100644
--- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp
@@ -12,6 +12,7 @@
 
 #include "CSKYMCTargetDesc.h"
 #include "CSKYAsmBackend.h"
+#include "CSKYInstPrinter.h"
 #include "CSKYMCAsmInfo.h"
 #include "CSKYMCCodeEmitter.h"
 #include "TargetInfo/CSKYTargetInfo.h"
@@ -26,6 +27,9 @@
 #define GET_REGINFO_MC_DESC
 #include "CSKYGenRegisterInfo.inc"
 
+#define GET_SUBTARGETINFO_MC_DESC
+#include "CSKYGenSubtargetInfo.inc"
+
 using namespace llvm;
 
 static MCAsmInfo *createCSKYMCAsmInfo(const MCRegisterInfo &MRI,
@@ -46,12 +50,28 @@ static MCInstrInfo *createCSKYMCInstrInfo() {
   return Info;
 }
 
+static MCInstPrinter *createCSKYMCInstPrinter(const Triple &T,
+                                              unsigned SyntaxVariant,
+                                              const MCAsmInfo &MAI,
+                                              const MCInstrInfo &MII,
+                                              const MCRegisterInfo &MRI) {
+  return new CSKYInstPrinter(MAI, MII, MRI);
+}
+
 static MCRegisterInfo *createCSKYMCRegisterInfo(const Triple &TT) {
   MCRegisterInfo *Info = new MCRegisterInfo();
   InitCSKYMCRegisterInfo(Info, CSKY::R15);
   return Info;
 }
 
+static MCSubtargetInfo *createCSKYMCSubtargetInfo(const Triple &TT,
+                                                  StringRef CPU, StringRef FS) {
+  std::string CPUName = std::string(CPU);
+  if (CPUName.empty())
+    CPUName = "generic";
+  return createCSKYMCSubtargetInfoImpl(TT, CPUName, /*TuneCPU=*/CPUName, FS);
+}
+
 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYTargetMC() {
   auto &CSKYTarget = getTheCSKYTarget();
   TargetRegistry::RegisterMCAsmBackend(CSKYTarget, createCSKYAsmBackend);
@@ -59,4 +79,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYTargetMC() {
   TargetRegistry::RegisterMCInstrInfo(CSKYTarget, createCSKYMCInstrInfo);
   TargetRegistry::RegisterMCRegInfo(CSKYTarget, createCSKYMCRegisterInfo);
   TargetRegistry::RegisterMCCodeEmitter(CSKYTarget, createCSKYMCCodeEmitter);
+  TargetRegistry::RegisterMCInstPrinter(CSKYTarget, createCSKYMCInstPrinter);
+  TargetRegistry::RegisterMCSubtargetInfo(CSKYTarget,
+                                          createCSKYMCSubtargetInfo);
 }

diff  --git a/llvm/test/MC/CSKY/basic.s b/llvm/test/MC/CSKY/basic.s
new file mode 100644
index 0000000000000..17f6605c240fd
--- /dev/null
+++ b/llvm/test/MC/CSKY/basic.s
@@ -0,0 +1,131 @@
+# RUN: llvm-mc %s -triple=csky -show-encoding | FileCheck -check-prefixes=CHECK-ASM %s
+
+# CHECK-ASM: addi32 a0, sp, 2
+# CHECK-ASM: encoding: [0x0e,0xe4,0x01,0x00]
+addi32 a0, sp, 2
+
+# CHECK-ASM: subi32 a0, sp, 2
+# CHECK-ASM: encoding: [0x0e,0xe4,0x01,0x10]
+subi32 a0, sp, 2
+
+# CHECK-ASM: andi32 a0, sp, 2
+# CHECK-ASM: encoding: [0x0e,0xe4,0x02,0x20]
+andi32 a0, sp, 2
+
+# CHECK-ASM: andni32 a0, sp, 2
+# CHECK-ASM: encoding: [0x0e,0xe4,0x02,0x30]
+andni32 a0, sp, 2
+
+# CHECK-ASM: xori32 a0, sp, 2
+# CHECK-ASM: encoding: [0x0e,0xe4,0x02,0x40]
+xori32 a0, sp, 2
+
+# CHECK-ASM: lsli32 a0, sp, 2
+# CHECK-ASM: encoding: [0x4e,0xc4,0x20,0x48]
+lsli32 a0, sp, 2
+
+# CHECK-ASM: lsri32 a0, sp, 2
+# CHECK-ASM: encoding: [0x4e,0xc4,0x40,0x48]
+lsri32 a0, sp, 2
+
+# CHECK-ASM: asri32 a0, sp, 2
+# CHECK-ASM: encoding: [0x4e,0xc4,0x80,0x48]
+asri32 a0, sp, 2
+
+
+# CHECK-ASM: addu32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x23,0x00]
+addu32 a3, l0, l1
+
+# CHECK-ASM: subu32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x83,0x00]
+subu32 a3, l0, l1
+
+# CHECK-ASM: and32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x23,0x20]
+and32 a3, l0, l1
+
+# CHECK-ASM: andn32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x43,0x20]
+andn32 a3, l0, l1
+
+# CHECK-ASM: or32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x23,0x24]
+or32 a3, l0, l1
+
+# CHECK-ASM: xor32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x43,0x24]
+xor32 a3, l0, l1
+
+# CHECK-ASM: nor32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x83,0x24]
+nor32 a3, l0, l1
+
+# CHECK-ASM: lsl32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x23,0x40]
+lsl32 a3, l0, l1
+
+# CHECK-ASM: lsr32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x43,0x40]
+lsr32 a3, l0, l1
+
+# CHECK-ASM: asr32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x83,0x40]
+asr32 a3, l0, l1
+
+# CHECK-ASM: mult32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x23,0x84]
+mult32 a3, l0, l1
+
+# CHECK-ASM: divs32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x43,0x80]
+divs32 a3, l0, l1
+
+# CHECK-ASM: divu32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x23,0x80]
+divu32 a3, l0, l1
+
+# CHECK-ASM: not32 a3, l0
+# CHECK-ASM: encoding: [0x84,0xc4,0x83,0x24]
+not32 a3, l0
+
+
+# RUN: not llvm-mc -triple csky --defsym=ERR=1 < %s 2>&1 | FileCheck %s
+
+.ifdef ERR
+
+# uimm12/oimm12/nimm12
+addi32 a0, a0, 0 # CHECK: :[[#@LINE]]:16: error: immediate must be an integer in the range [1, 4096]
+subi32 a0, a0, 4097 # CHECK: :[[#@LINE]]:16: error: immediate must be an integer in the range [1, 4096]
+andi32 a0, a0, 4096 # CHECK: :[[#@LINE]]:16: error: immediate must be an integer in the range [0, 4095]
+andni32 a0, a0, 4096 # CHECK: :[[#@LINE]]:17: error: immediate must be an integer in the range [0, 4095]
+xori32 a0, a0, 4096 # CHECK: :[[#@LINE]]:16: error: immediate must be an integer in the range [0, 4095]
+
+
+# uimm5
+lsli32 a0, a0, 32 # CHECK: :[[#@LINE]]:16: error: immediate must be an integer in the range [0, 31]
+lsri32 a0, a0, 32 # CHECK: :[[#@LINE]]:16: error: immediate must be an integer in the range [0, 31]
+asri32 a0, a0, 32 # CHECK: :[[#@LINE]]:16: error: immediate must be an integer in the range [0, 31]
+
+
+# Invalid mnemonics
+subs t0, t2, t1 # CHECK: :[[#@LINE]]:1: error: unrecognized instruction mnemonic
+nandi t0, t2, 0 # CHECK: :[[#@LINE]]:1: error: unrecognized instruction mnemonic
+
+# Invalid register names
+addi32 foo, sp, 10 # CHECK: :[[#@LINE]]:8: error: unknown operand
+lsli32 a10, a2, 0x20 # CHECK: :[[#@LINE]]:8: error: unknown operand
+asri32 x32, s0, s0 # CHECK: :[[#@LINE]]:8: error: unknown operand
+
+# Invalid operand types
+xori32 sp, 22, 220 # CHECK: :[[#@LINE]]:12: error: invalid operand for instruction
+subu32 t0, t2, 1 # CHECK: :[[#@LINE]]:16: error: invalid operand for instruction
+
+# Too many operands
+subu32 t2, t3, 0x50, 0x60 # CHECK: :[[#@LINE]]:22: error: invalid operand for instruction
+
+# Too few operands
+xori32 a0, a1 # CHECK: :[[#@LINE]]:1: error: too few operands for instruction
+xor32 a0, a2 # CHECK: :[[#@LINE]]:1: error: too few operands for instruction
+
+.endif

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


        


More information about the llvm-commits mailing list