[llvm] 52ecf02 - [Xtensa 6/10] Add Xtensa basic assembler parser

via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 26 04:38:56 PST 2022


Author: Andrei Safronov
Date: 2022-12-26T13:30:51+01:00
New Revision: 52ecf023ed2430ba6d6c9804869184458b01f4ce

URL: https://github.com/llvm/llvm-project/commit/52ecf023ed2430ba6d6c9804869184458b01f4ce
DIFF: https://github.com/llvm/llvm-project/commit/52ecf023ed2430ba6d6c9804869184458b01f4ce.diff

LOG: [Xtensa 6/10] Add Xtensa basic assembler parser

Currently parse just described in *.td files Xtensa instructions and operands subsets.

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

Added: 
    llvm/lib/Target/Xtensa/AsmParser/CMakeLists.txt
    llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp

Modified: 
    llvm/lib/Target/Xtensa/CMakeLists.txt
    llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h
    llvm/lib/Target/Xtensa/Xtensa.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/Xtensa/AsmParser/CMakeLists.txt b/llvm/lib/Target/Xtensa/AsmParser/CMakeLists.txt
new file mode 100644
index 000000000000..b6eb4fde47b9
--- /dev/null
+++ b/llvm/lib/Target/Xtensa/AsmParser/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_llvm_component_library(LLVMXtensaAsmParser
+  XtensaAsmParser.cpp
+
+  LINK_COMPONENTS
+  MC
+  MCParser
+  Support
+  XtensaDesc
+  XtensaInfo
+
+  ADD_TO_COMPONENT
+  Xtensa
+  )

diff  --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
new file mode 100644
index 000000000000..cb2a1c15b7e1
--- /dev/null
+++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
@@ -0,0 +1,461 @@
+//===- XtensaAsmParser.cpp - Parse Xtensa assembly to MCInst instructions -===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// 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 "MCTargetDesc/XtensaMCTargetDesc.h"
+#include "TargetInfo/XtensaTargetInfo.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.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/MC/TargetRegistry.h"
+#include "llvm/Support/Casting.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "xtensa-asm-parser"
+
+struct XtensaOperand;
+
+class XtensaAsmParser : public MCTargetAsmParser {
+
+  SMLoc getLoc() const { return getParser().getTok().getLoc(); }
+
+  // Override MCTargetAsmParser.
+  bool ParseDirective(AsmToken DirectiveID) override;
+  bool parseRegister(MCRegister &RegNo,
+                     SMLoc &StartLoc, SMLoc &EndLoc) override;
+  bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
+                        SMLoc NameLoc, OperandVector &Operands) override;
+  bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
+                               OperandVector &Operands, MCStreamer &Out,
+                               uint64_t &ErrorInfo,
+                               bool MatchingInlineAsm) override;
+  unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
+                                      unsigned Kind) override;
+
+// Auto-generated instruction matching functions
+#define GET_ASSEMBLER_HEADER
+#include "XtensaGenAsmMatcher.inc"
+
+  OperandMatchResultTy parseImmediate(OperandVector &Operands);
+  OperandMatchResultTy parseRegister(OperandVector &Operands,
+                                     bool AllowParens = false, bool SR = false);
+  OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands);
+  bool parseOperand(OperandVector &Operands);
+  OperandMatchResultTy tryParseRegister(MCRegister &RegNo, SMLoc &StartLoc,
+                                        SMLoc &EndLoc) override {
+    return MatchOperand_NoMatch;
+  }
+
+public:
+  enum XtensaMatchResultTy {
+    Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
+#define GET_OPERAND_DIAGNOSTIC_TYPES
+#include "XtensaGenAsmMatcher.inc"
+#undef GET_OPERAND_DIAGNOSTIC_TYPES
+  };
+
+  XtensaAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
+                  const MCInstrInfo &MII, const MCTargetOptions &Options)
+      : MCTargetAsmParser(Options, STI, MII) {
+    setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
+  }
+};
+
+// Return true if Expr is in the range [MinValue, MaxValue].
+static bool inRange(const MCExpr *Expr, int64_t MinValue, int64_t MaxValue) {
+  if (auto *CE = dyn_cast<MCConstantExpr>(Expr)) {
+    int64_t Value = CE->getValue();
+    return Value >= MinValue && Value <= MaxValue;
+  }
+  return false;
+}
+
+struct XtensaOperand : 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;
+  };
+
+  XtensaOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
+
+public:
+  XtensaOperand(const XtensaOperand &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; }
+
+  bool isImm(int64_t MinValue, int64_t MaxValue) const {
+    return Kind == Immediate && inRange(getImm(), MinValue, MaxValue);
+  }
+
+  bool isImm8() const { return isImm(-128, 127); }
+
+  bool isImm8_sh8() const {
+    return isImm(-32768, 32512) &&
+           ((dyn_cast<MCConstantExpr>(getImm())->getValue() & 0xFF) == 0);
+  }
+
+  /// getStartLoc - Gets location of the first token of this operand
+  SMLoc getStartLoc() const override { return StartLoc; }
+  /// getEndLoc - 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";
+      OS << getReg() << ">";
+      break;
+    case Token:
+      OS << "'" << getToken() << "'";
+      break;
+    }
+  }
+
+  static std::unique_ptr<XtensaOperand> createToken(StringRef Str, SMLoc S) {
+    auto Op = std::make_unique<XtensaOperand>(Token);
+    Op->Tok = Str;
+    Op->StartLoc = S;
+    Op->EndLoc = S;
+    return Op;
+  }
+
+  static std::unique_ptr<XtensaOperand> createReg(unsigned RegNo, SMLoc S,
+                                                  SMLoc E) {
+    auto Op = std::make_unique<XtensaOperand>(Register);
+    Op->Reg.RegNum = RegNo;
+    Op->StartLoc = S;
+    Op->EndLoc = E;
+    return Op;
+  }
+
+  static std::unique_ptr<XtensaOperand> createImm(const MCExpr *Val, SMLoc S,
+                                                  SMLoc E) {
+    auto Op = std::make_unique<XtensaOperand>(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!");
+    int64_t Imm = 0;
+    bool IsConstant = false;
+
+    if (auto *CE = dyn_cast<MCConstantExpr>(Expr)) {
+      IsConstant = true;
+      Imm = CE->getValue();
+    }
+
+    if (IsConstant)
+      Inst.addOperand(MCOperand::createImm(Imm));
+    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());
+  }
+};
+
+#define GET_REGISTER_MATCHER
+#define GET_MATCHER_IMPLEMENTATION
+#include "XtensaGenAsmMatcher.inc"
+
+unsigned XtensaAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
+                                                     unsigned Kind) {
+  return Match_InvalidOperand;
+}
+
+static SMLoc RefineErrorLoc(const SMLoc Loc, const OperandVector &Operands,
+                            uint64_t ErrorInfo) {
+  if (ErrorInfo != ~0ULL && ErrorInfo < Operands.size()) {
+    SMLoc ErrorLoc = Operands[ErrorInfo]->getStartLoc();
+    if (ErrorLoc == SMLoc())
+      return Loc;
+    return ErrorLoc;
+  }
+  return Loc;
+}
+
+bool XtensaAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
+                                              OperandVector &Operands,
+                                              MCStreamer &Out,
+                                              uint64_t &ErrorInfo,
+                                              bool MatchingInlineAsm) {
+  MCInst Inst;
+  auto Result =
+      MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
+
+  switch (Result) {
+  default:
+    break;
+  case Match_Success:
+    Inst.setLoc(IDLoc);
+    Out.emitInstruction(Inst, getSTI());
+    return false;
+  case Match_MissingFeature:
+    return Error(IDLoc, "instruction use requires an option to be enabled");
+  case Match_MnemonicFail:
+    return Error(IDLoc, "unrecognized instruction mnemonic");
+  case Match_InvalidOperand: {
+    SMLoc ErrorLoc = IDLoc;
+    if (ErrorInfo != ~0U) {
+      if (ErrorInfo >= Operands.size())
+        return Error(ErrorLoc, "too few operands for instruction");
+
+      ErrorLoc = ((XtensaOperand &)*Operands[ErrorInfo]).getStartLoc();
+      if (ErrorLoc == SMLoc())
+        ErrorLoc = IDLoc;
+    }
+    return Error(ErrorLoc, "invalid operand for instruction");
+  }
+  case Match_InvalidImm8:
+    return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+                 "expected immediate in range [-128, 127]");
+  case Match_InvalidImm8_sh8:
+    return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+                 "expected immediate in range [-32768, 32512], first 8 bits "
+                 "should be zero");
+  }
+
+  report_fatal_error("Unknown match type detected!");
+}
+
+bool XtensaAsmParser::parseRegister(MCRegister &RegNo, SMLoc &StartLoc,
+                                    SMLoc &EndLoc) {
+  const AsmToken &Tok = getParser().getTok();
+  StartLoc = Tok.getLoc();
+  EndLoc = Tok.getEndLoc();
+  RegNo = 0;
+  StringRef Name = getLexer().getTok().getIdentifier();
+
+  if (!MatchRegisterName(Name) && !MatchRegisterAltName(Name)) {
+    getParser().Lex(); // Eat identifier token.
+    return false;
+  }
+
+  return Error(StartLoc, "invalid register name");
+}
+
+OperandMatchResultTy XtensaAsmParser::parseRegister(OperandVector &Operands,
+                                                    bool AllowParens, bool SR) {
+  SMLoc FirstS = getLoc();
+  bool HadParens = false;
+  AsmToken Buf[2];
+  StringRef RegName;
+
+  // If this a parenthesised register name is allowed, parse it atomically
+  if (AllowParens && getLexer().is(AsmToken::LParen)) {
+    size_t ReadCount = getLexer().peekTokens(Buf);
+    if (ReadCount == 2 && Buf[1].getKind() == AsmToken::RParen) {
+      HadParens = true;
+      getParser().Lex(); // Eat '('
+    }
+  }
+
+  switch (getLexer().getKind()) {
+  default:
+    return MatchOperand_NoMatch;
+  case AsmToken::Identifier:
+    RegName = getLexer().getTok().getIdentifier();
+    break;
+  }
+
+  unsigned RegNo = MatchRegisterName(RegName);
+  if (RegNo == 0)
+    RegNo = MatchRegisterAltName(RegName);
+
+  if (RegNo == 0) {
+    if (HadParens)
+      getLexer().UnLex(Buf[0]);
+    return MatchOperand_NoMatch;
+  }
+  if (HadParens)
+    Operands.push_back(XtensaOperand::createToken("(", FirstS));
+  SMLoc S = getLoc();
+  SMLoc E = getParser().getTok().getEndLoc();
+  getLexer().Lex();
+  Operands.push_back(XtensaOperand::createReg(RegNo, S, E));
+
+  if (HadParens) {
+    getParser().Lex(); // Eat ')'
+    Operands.push_back(XtensaOperand::createToken(")", getLoc()));
+  }
+
+  return MatchOperand_Success;
+}
+
+OperandMatchResultTy XtensaAsmParser::parseImmediate(OperandVector &Operands) {
+  SMLoc S = getLoc();
+  SMLoc E;
+  const MCExpr *Res;
+
+  switch (getLexer().getKind()) {
+  default:
+    return MatchOperand_NoMatch;
+  case AsmToken::LParen:
+  case AsmToken::Minus:
+  case AsmToken::Plus:
+  case AsmToken::Tilde:
+  case AsmToken::Integer:
+  case AsmToken::String:
+    if (getParser().parseExpression(Res))
+      return MatchOperand_ParseFail;
+    break;
+  case AsmToken::Identifier: {
+    StringRef Identifier;
+    if (getParser().parseIdentifier(Identifier))
+      return MatchOperand_ParseFail;
+
+    MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
+    Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
+    break;
+  }
+  case AsmToken::Percent:
+    return parseOperandWithModifier(Operands);
+  }
+
+  E = SMLoc::getFromPointer(S.getPointer() - 1);
+  Operands.push_back(XtensaOperand::createImm(Res, S, E));
+  return MatchOperand_Success;
+}
+
+OperandMatchResultTy
+XtensaAsmParser::parseOperandWithModifier(OperandVector &Operands) {
+  return MatchOperand_ParseFail;
+}
+
+/// 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 XtensaAsmParser::parseOperand(OperandVector &Operands) {
+  // Attempt to parse token as register
+  if (parseRegister(Operands, true) == MatchOperand_Success)
+    return false;
+
+  // Attempt to parse token as an immediate
+  if (parseImmediate(Operands) == MatchOperand_Success) {
+    return false;
+  }
+
+  // Finally we have exhausted all options and must declare defeat.
+  Error(getLoc(), "unknown operand");
+  return true;
+}
+
+bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info,
+                                       StringRef Name, SMLoc NameLoc,
+                                       OperandVector &Operands) {
+  // First operand is token for instruction
+  Operands.push_back(XtensaOperand::createToken(Name, NameLoc));
+
+  // If there are no more operands, then finish
+  if (getLexer().is(AsmToken::EndOfStatement))
+    return false;
+
+  // Parse first operand
+  if (parseOperand(Operands))
+    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))
+      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;
+}
+
+bool XtensaAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
+
+// Force static initialization.
+extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaAsmParser() {
+  RegisterMCAsmParser<XtensaAsmParser> X(getTheXtensaTarget());
+}

diff  --git a/llvm/lib/Target/Xtensa/CMakeLists.txt b/llvm/lib/Target/Xtensa/CMakeLists.txt
index 17ef1f213ce9..c142cfb00144 100644
--- a/llvm/lib/Target/Xtensa/CMakeLists.txt
+++ b/llvm/lib/Target/Xtensa/CMakeLists.txt
@@ -2,9 +2,11 @@ add_llvm_component_group(Xtensa)
 
 set(LLVM_TARGET_DEFINITIONS Xtensa.td)
 
+tablegen(LLVM XtensaGenAsmMatcher.inc -gen-asm-matcher)
 tablegen(LLVM XtensaGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM XtensaGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM XtensaGenRegisterInfo.inc -gen-register-info)
+tablegen(LLVM XtensaGenSubtargetInfo.inc -gen-subtarget)
 
 add_public_tablegen_target(XtensaCommonTableGen)
 
@@ -22,5 +24,7 @@ add_llvm_target(XtensaCodeGen
   Xtensa
   )
 
+add_subdirectory(AsmParser)
 add_subdirectory(MCTargetDesc)
 add_subdirectory(TargetInfo)
+

diff  --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h
index f67f373530fc..0e075be0df07 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h
@@ -54,4 +54,7 @@ createXtensaObjectWriter(uint8_t OSABI, bool IsLittleEndian);
 #define GET_INSTRINFO_ENUM
 #include "XtensaGenInstrInfo.inc"
 
+#define GET_SUBTARGETINFO_ENUM
+#include "XtensaGenSubtargetInfo.inc"
+
 #endif // LLVM_LIB_TARGET_XTENSA_MCTARGETDESC_XTENSAMCTARGETDESC_H

diff  --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td
index 830fdec9860c..b1c436b1c5f3 100644
--- a/llvm/lib/Target/Xtensa/Xtensa.td
+++ b/llvm/lib/Target/Xtensa/Xtensa.td
@@ -47,6 +47,11 @@ def XtensaInstrInfo : InstrInfo;
 // Target Declaration
 //===----------------------------------------------------------------------===//
 
+def XtensaAsmParser : AsmParser {
+  let ShouldEmitMatchRegisterAltName = 1;
+}
+
 def Xtensa : Target {
   let InstructionSet = XtensaInstrInfo;
+  let AssemblyParsers = [XtensaAsmParser];
 }


        


More information about the llvm-commits mailing list