[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