123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 |
- //===-- BPFAsmParser.cpp - Parse BPF assembly to MCInst instructions --===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "MCTargetDesc/BPFMCTargetDesc.h"
- #include "TargetInfo/BPFTargetInfo.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/MCInstrInfo.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;
- namespace {
- struct BPFOperand;
- class BPFAsmParser : public MCTargetAsmParser {
- SMLoc getLoc() const { return getParser().getTok().getLoc(); }
- bool PreMatchCheck(OperandVector &Operands);
- bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
- OperandVector &Operands, MCStreamer &Out,
- uint64_t &ErrorInfo,
- bool MatchingInlineAsm) override;
- bool parseRegister(MCRegister &RegNo, SMLoc &StartLoc,
- SMLoc &EndLoc) override;
- OperandMatchResultTy tryParseRegister(MCRegister &RegNo, SMLoc &StartLoc,
- SMLoc &EndLoc) override;
- bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
- SMLoc NameLoc, OperandVector &Operands) override;
- bool ParseDirective(AsmToken DirectiveID) override;
- // "=" is used as assignment operator for assembly statment, so can't be used
- // for symbol assignment.
- bool equalIsAsmAssignment() override { return false; }
- // "*" is used for dereferencing memory that it will be the start of
- // statement.
- bool starIsStartOfStatement() override { return true; }
- #define GET_ASSEMBLER_HEADER
- #include "BPFGenAsmMatcher.inc"
- OperandMatchResultTy parseImmediate(OperandVector &Operands);
- OperandMatchResultTy parseRegister(OperandVector &Operands);
- OperandMatchResultTy parseOperandAsOperator(OperandVector &Operands);
- public:
- enum BPFMatchResultTy {
- Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
- #define GET_OPERAND_DIAGNOSTIC_TYPES
- #include "BPFGenAsmMatcher.inc"
- #undef GET_OPERAND_DIAGNOSTIC_TYPES
- };
- BPFAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
- const MCInstrInfo &MII, const MCTargetOptions &Options)
- : MCTargetAsmParser(Options, STI, MII) {
- setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
- }
- };
- /// BPFOperand - Instances of this class represent a parsed machine
- /// instruction
- struct BPFOperand : 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;
- };
- BPFOperand(KindTy K) : Kind(K) {}
- public:
- BPFOperand(const BPFOperand &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 isConstantImm() const {
- return isImm() && isa<MCConstantExpr>(getImm());
- }
- int64_t getConstantImm() const {
- const MCExpr *Val = getImm();
- return static_cast<const MCConstantExpr *>(Val)->getValue();
- }
- bool isSImm12() const {
- return (isConstantImm() && isInt<12>(getConstantImm()));
- }
- /// 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;
- }
- }
- 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());
- }
- static std::unique_ptr<BPFOperand> createToken(StringRef Str, SMLoc S) {
- auto Op = std::make_unique<BPFOperand>(Token);
- Op->Tok = Str;
- Op->StartLoc = S;
- Op->EndLoc = S;
- return Op;
- }
- static std::unique_ptr<BPFOperand> createReg(unsigned RegNo, SMLoc S,
- SMLoc E) {
- auto Op = std::make_unique<BPFOperand>(Register);
- Op->Reg.RegNum = RegNo;
- Op->StartLoc = S;
- Op->EndLoc = E;
- return Op;
- }
- static std::unique_ptr<BPFOperand> createImm(const MCExpr *Val, SMLoc S,
- SMLoc E) {
- auto Op = std::make_unique<BPFOperand>(Immediate);
- Op->Imm.Val = Val;
- Op->StartLoc = S;
- Op->EndLoc = E;
- return Op;
- }
- // Identifiers that can be used at the start of a statment.
- static bool isValidIdAtStart(StringRef Name) {
- return StringSwitch<bool>(Name.lower())
- .Case("if", true)
- .Case("call", true)
- .Case("goto", true)
- .Case("*", true)
- .Case("exit", true)
- .Case("lock", true)
- .Case("ld_pseudo", true)
- .Default(false);
- }
- // Identifiers that can be used in the middle of a statment.
- static bool isValidIdInMiddle(StringRef Name) {
- return StringSwitch<bool>(Name.lower())
- .Case("u64", true)
- .Case("u32", true)
- .Case("u16", true)
- .Case("u8", true)
- .Case("be64", true)
- .Case("be32", true)
- .Case("be16", true)
- .Case("le64", true)
- .Case("le32", true)
- .Case("le16", true)
- .Case("goto", true)
- .Case("ll", true)
- .Case("skb", true)
- .Case("s", true)
- .Default(false);
- }
- };
- } // end anonymous namespace.
- #define GET_REGISTER_MATCHER
- #define GET_MATCHER_IMPLEMENTATION
- #include "BPFGenAsmMatcher.inc"
- bool BPFAsmParser::PreMatchCheck(OperandVector &Operands) {
- if (Operands.size() == 4) {
- // check "reg1 = -reg2" and "reg1 = be16/be32/be64/le16/le32/le64 reg2",
- // reg1 must be the same as reg2
- BPFOperand &Op0 = (BPFOperand &)*Operands[0];
- BPFOperand &Op1 = (BPFOperand &)*Operands[1];
- BPFOperand &Op2 = (BPFOperand &)*Operands[2];
- BPFOperand &Op3 = (BPFOperand &)*Operands[3];
- if (Op0.isReg() && Op1.isToken() && Op2.isToken() && Op3.isReg()
- && Op1.getToken() == "="
- && (Op2.getToken() == "-" || Op2.getToken() == "be16"
- || Op2.getToken() == "be32" || Op2.getToken() == "be64"
- || Op2.getToken() == "le16" || Op2.getToken() == "le32"
- || Op2.getToken() == "le64")
- && Op0.getReg() != Op3.getReg())
- return true;
- }
- return false;
- }
- bool BPFAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
- OperandVector &Operands,
- MCStreamer &Out, uint64_t &ErrorInfo,
- bool MatchingInlineAsm) {
- MCInst Inst;
- SMLoc ErrorLoc;
- if (PreMatchCheck(Operands))
- return Error(IDLoc, "additional inst constraint not met");
- switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
- 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:
- ErrorLoc = IDLoc;
- if (ErrorInfo != ~0U) {
- if (ErrorInfo >= Operands.size())
- return Error(ErrorLoc, "too few operands for instruction");
- ErrorLoc = ((BPFOperand &)*Operands[ErrorInfo]).getStartLoc();
- if (ErrorLoc == SMLoc())
- ErrorLoc = IDLoc;
- }
- return Error(ErrorLoc, "invalid operand for instruction");
- }
- llvm_unreachable("Unknown match type detected!");
- }
- bool BPFAsmParser::parseRegister(MCRegister &RegNo, SMLoc &StartLoc,
- SMLoc &EndLoc) {
- if (tryParseRegister(RegNo, StartLoc, EndLoc) != MatchOperand_Success)
- return Error(StartLoc, "invalid register name");
- return false;
- }
- OperandMatchResultTy BPFAsmParser::tryParseRegister(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)) {
- getParser().Lex(); // Eat identifier token.
- return MatchOperand_Success;
- }
- return MatchOperand_NoMatch;
- }
- OperandMatchResultTy
- BPFAsmParser::parseOperandAsOperator(OperandVector &Operands) {
- SMLoc S = getLoc();
- if (getLexer().getKind() == AsmToken::Identifier) {
- StringRef Name = getLexer().getTok().getIdentifier();
- if (BPFOperand::isValidIdInMiddle(Name)) {
- getLexer().Lex();
- Operands.push_back(BPFOperand::createToken(Name, S));
- return MatchOperand_Success;
- }
- return MatchOperand_NoMatch;
- }
- switch (getLexer().getKind()) {
- case AsmToken::Minus:
- case AsmToken::Plus: {
- if (getLexer().peekTok().is(AsmToken::Integer))
- return MatchOperand_NoMatch;
- [[fallthrough]];
- }
- case AsmToken::Equal:
- case AsmToken::Greater:
- case AsmToken::Less:
- case AsmToken::Pipe:
- case AsmToken::Star:
- case AsmToken::LParen:
- case AsmToken::RParen:
- case AsmToken::LBrac:
- case AsmToken::RBrac:
- case AsmToken::Slash:
- case AsmToken::Amp:
- case AsmToken::Percent:
- case AsmToken::Caret: {
- StringRef Name = getLexer().getTok().getString();
- getLexer().Lex();
- Operands.push_back(BPFOperand::createToken(Name, S));
- return MatchOperand_Success;
- }
- case AsmToken::EqualEqual:
- case AsmToken::ExclaimEqual:
- case AsmToken::GreaterEqual:
- case AsmToken::GreaterGreater:
- case AsmToken::LessEqual:
- case AsmToken::LessLess: {
- Operands.push_back(BPFOperand::createToken(
- getLexer().getTok().getString().substr(0, 1), S));
- Operands.push_back(BPFOperand::createToken(
- getLexer().getTok().getString().substr(1, 1), S));
- getLexer().Lex();
- return MatchOperand_Success;
- }
- default:
- break;
- }
- return MatchOperand_NoMatch;
- }
- OperandMatchResultTy BPFAsmParser::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();
- unsigned RegNo = MatchRegisterName(Name);
- if (RegNo == 0)
- return MatchOperand_NoMatch;
- getLexer().Lex();
- Operands.push_back(BPFOperand::createReg(RegNo, S, E));
- }
- return MatchOperand_Success;
- }
- OperandMatchResultTy BPFAsmParser::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:
- case AsmToken::Identifier:
- break;
- }
- const MCExpr *IdVal;
- SMLoc S = getLoc();
- if (getParser().parseExpression(IdVal))
- return MatchOperand_ParseFail;
- SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
- Operands.push_back(BPFOperand::createImm(IdVal, S, E));
- return MatchOperand_Success;
- }
- /// ParseInstruction - Parse an BPF instruction which is in BPF verifier
- /// format.
- bool BPFAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
- SMLoc NameLoc, OperandVector &Operands) {
- // The first operand could be either register or actually an operator.
- unsigned RegNo = MatchRegisterName(Name);
- if (RegNo != 0) {
- SMLoc E = SMLoc::getFromPointer(NameLoc.getPointer() - 1);
- Operands.push_back(BPFOperand::createReg(RegNo, NameLoc, E));
- } else if (BPFOperand::isValidIdAtStart (Name))
- Operands.push_back(BPFOperand::createToken(Name, NameLoc));
- else
- return Error(NameLoc, "invalid register/token name");
- while (!getLexer().is(AsmToken::EndOfStatement)) {
- // Attempt to parse token as operator
- if (parseOperandAsOperator(Operands) == MatchOperand_Success)
- continue;
- // Attempt to parse token as register
- if (parseRegister(Operands) == MatchOperand_Success)
- continue;
- // Attempt to parse token as an immediate
- if (parseImmediate(Operands) != MatchOperand_Success) {
- SMLoc Loc = getLexer().getLoc();
- return Error(Loc, "unexpected token");
- }
- }
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- SMLoc Loc = getLexer().getLoc();
- getParser().eatToEndOfStatement();
- return Error(Loc, "unexpected token");
- }
- // Consume the EndOfStatement.
- getParser().Lex();
- return false;
- }
- bool BPFAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
- extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFAsmParser() {
- RegisterMCAsmParser<BPFAsmParser> X(getTheBPFTarget());
- RegisterMCAsmParser<BPFAsmParser> Y(getTheBPFleTarget());
- RegisterMCAsmParser<BPFAsmParser> Z(getTheBPFbeTarget());
- }
|