[CSKY 4/n] Add basic CSKYAsmParser and CSKYInstPrinter
authorZi Xuan Wu <zixuan.wu@linux.alibaba.com>
Tue, 20 Apr 2021 06:06:36 +0000 (14:06 +0800)
committerZi Xuan Wu <zixuan.wu@linux.alibaba.com>
Tue, 20 Apr 2021 07:36:49 +0000 (15:36 +0800)
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

llvm/lib/Target/CSKY/AsmParser/CMakeLists.txt [new file with mode: 0644]
llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp [new file with mode: 0644]
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/CSKYInstPrinter.cpp [new file with mode: 0644]
llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.h [new file with mode: 0644]
llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp
llvm/test/MC/CSKY/basic.s [new file with mode: 0644]
llvm/test/MC/CSKY/lit.local.cfg [new file with mode: 0644]

diff --git a/llvm/lib/Target/CSKY/AsmParser/CMakeLists.txt b/llvm/lib/Target/CSKY/AsmParser/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e7b5cdb
--- /dev/null
@@ -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 (file)
index 0000000..718b14c
--- /dev/null
@@ -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());
+}
index ec487ed..c49c2a0 100644 (file)
@@ -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)
index da6151b..854a8b5 100644 (file)
@@ -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;
 }
index 7add217..88985a9 100644 (file)
@@ -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))]>;
index f5d7df0..d084266 100644 (file)
@@ -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 (file)
index 0000000..c8920fb
--- /dev/null
@@ -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 (file)
index 0000000..a28791a
--- /dev/null
@@ -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
index 876000a..169e1e1 100644 (file)
@@ -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 (file)
index 0000000..17f6605
--- /dev/null
@@ -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 (file)
index 0000000..37335bd
--- /dev/null
@@ -0,0 +1,2 @@
+if not 'CSKY' in config.root.targets:
+    config.unsupported = True