Path: blob/main/contrib/llvm-project/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
35294 views
//===-- BPFAsmParser.cpp - Parse BPF assembly to MCInst instructions --===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "MCTargetDesc/BPFMCTargetDesc.h"9#include "TargetInfo/BPFTargetInfo.h"10#include "llvm/ADT/STLExtras.h"11#include "llvm/ADT/StringSwitch.h"12#include "llvm/MC/MCContext.h"13#include "llvm/MC/MCExpr.h"14#include "llvm/MC/MCInst.h"15#include "llvm/MC/MCInstrInfo.h"16#include "llvm/MC/MCParser/MCAsmLexer.h"17#include "llvm/MC/MCParser/MCParsedAsmOperand.h"18#include "llvm/MC/MCParser/MCTargetAsmParser.h"19#include "llvm/MC/MCRegisterInfo.h"20#include "llvm/MC/MCStreamer.h"21#include "llvm/MC/MCSubtargetInfo.h"22#include "llvm/MC/TargetRegistry.h"23#include "llvm/Support/Casting.h"2425using namespace llvm;2627namespace {28struct BPFOperand;2930class BPFAsmParser : public MCTargetAsmParser {3132SMLoc getLoc() const { return getParser().getTok().getLoc(); }3334bool PreMatchCheck(OperandVector &Operands);3536bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,37OperandVector &Operands, MCStreamer &Out,38uint64_t &ErrorInfo,39bool MatchingInlineAsm) override;4041bool parseRegister(MCRegister &Reo, SMLoc &StartLoc, SMLoc &EndLoc) override;42ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,43SMLoc &EndLoc) override;4445bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,46SMLoc NameLoc, OperandVector &Operands) override;4748// "=" is used as assignment operator for assembly statment, so can't be used49// for symbol assignment.50bool equalIsAsmAssignment() override { return false; }51// "*" is used for dereferencing memory that it will be the start of52// statement.53bool starIsStartOfStatement() override { return true; }5455#define GET_ASSEMBLER_HEADER56#include "BPFGenAsmMatcher.inc"5758ParseStatus parseImmediate(OperandVector &Operands);59ParseStatus parseRegister(OperandVector &Operands);60ParseStatus parseOperandAsOperator(OperandVector &Operands);6162public:63enum BPFMatchResultTy {64Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,65#define GET_OPERAND_DIAGNOSTIC_TYPES66#include "BPFGenAsmMatcher.inc"67#undef GET_OPERAND_DIAGNOSTIC_TYPES68};6970BPFAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,71const MCInstrInfo &MII, const MCTargetOptions &Options)72: MCTargetAsmParser(Options, STI, MII) {73setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));74}75};7677/// BPFOperand - Instances of this class represent a parsed machine78/// instruction79struct BPFOperand : public MCParsedAsmOperand {8081enum KindTy {82Token,83Register,84Immediate,85} Kind;8687struct RegOp {88unsigned RegNum;89};9091struct ImmOp {92const MCExpr *Val;93};9495SMLoc StartLoc, EndLoc;96union {97StringRef Tok;98RegOp Reg;99ImmOp Imm;100};101102BPFOperand(KindTy K) : Kind(K) {}103104public:105BPFOperand(const BPFOperand &o) : MCParsedAsmOperand() {106Kind = o.Kind;107StartLoc = o.StartLoc;108EndLoc = o.EndLoc;109110switch (Kind) {111case Register:112Reg = o.Reg;113break;114case Immediate:115Imm = o.Imm;116break;117case Token:118Tok = o.Tok;119break;120}121}122123bool isToken() const override { return Kind == Token; }124bool isReg() const override { return Kind == Register; }125bool isImm() const override { return Kind == Immediate; }126bool isMem() const override { return false; }127128bool isConstantImm() const {129return isImm() && isa<MCConstantExpr>(getImm());130}131132int64_t getConstantImm() const {133const MCExpr *Val = getImm();134return static_cast<const MCConstantExpr *>(Val)->getValue();135}136137bool isSImm16() const {138return (isConstantImm() && isInt<16>(getConstantImm()));139}140141bool isSymbolRef() const { return isImm() && isa<MCSymbolRefExpr>(getImm()); }142143bool isBrTarget() const { return isSymbolRef() || isSImm16(); }144145/// getStartLoc - Gets location of the first token of this operand146SMLoc getStartLoc() const override { return StartLoc; }147/// getEndLoc - Gets location of the last token of this operand148SMLoc getEndLoc() const override { return EndLoc; }149150MCRegister getReg() const override {151assert(Kind == Register && "Invalid type access!");152return Reg.RegNum;153}154155const MCExpr *getImm() const {156assert(Kind == Immediate && "Invalid type access!");157return Imm.Val;158}159160StringRef getToken() const {161assert(Kind == Token && "Invalid type access!");162return Tok;163}164165void print(raw_ostream &OS) const override {166switch (Kind) {167case Immediate:168OS << *getImm();169break;170case Register:171OS << "<register x";172OS << getReg() << ">";173break;174case Token:175OS << "'" << getToken() << "'";176break;177}178}179180void addExpr(MCInst &Inst, const MCExpr *Expr) const {181assert(Expr && "Expr shouldn't be null!");182183if (auto *CE = dyn_cast<MCConstantExpr>(Expr))184Inst.addOperand(MCOperand::createImm(CE->getValue()));185else186Inst.addOperand(MCOperand::createExpr(Expr));187}188189// Used by the TableGen Code190void addRegOperands(MCInst &Inst, unsigned N) const {191assert(N == 1 && "Invalid number of operands!");192Inst.addOperand(MCOperand::createReg(getReg()));193}194195void addImmOperands(MCInst &Inst, unsigned N) const {196assert(N == 1 && "Invalid number of operands!");197addExpr(Inst, getImm());198}199200static std::unique_ptr<BPFOperand> createToken(StringRef Str, SMLoc S) {201auto Op = std::make_unique<BPFOperand>(Token);202Op->Tok = Str;203Op->StartLoc = S;204Op->EndLoc = S;205return Op;206}207208static std::unique_ptr<BPFOperand> createReg(unsigned RegNo, SMLoc S,209SMLoc E) {210auto Op = std::make_unique<BPFOperand>(Register);211Op->Reg.RegNum = RegNo;212Op->StartLoc = S;213Op->EndLoc = E;214return Op;215}216217static std::unique_ptr<BPFOperand> createImm(const MCExpr *Val, SMLoc S,218SMLoc E) {219auto Op = std::make_unique<BPFOperand>(Immediate);220Op->Imm.Val = Val;221Op->StartLoc = S;222Op->EndLoc = E;223return Op;224}225226// Identifiers that can be used at the start of a statment.227static bool isValidIdAtStart(StringRef Name) {228return StringSwitch<bool>(Name.lower())229.Case("if", true)230.Case("call", true)231.Case("callx", true)232.Case("goto", true)233.Case("gotol", true)234.Case("may_goto", true)235.Case("*", true)236.Case("exit", true)237.Case("lock", true)238.Case("ld_pseudo", true)239.Default(false);240}241242// Identifiers that can be used in the middle of a statment.243static bool isValidIdInMiddle(StringRef Name) {244return StringSwitch<bool>(Name.lower())245.Case("u64", true)246.Case("u32", true)247.Case("u16", true)248.Case("u8", true)249.Case("s32", true)250.Case("s16", true)251.Case("s8", true)252.Case("be64", true)253.Case("be32", true)254.Case("be16", true)255.Case("le64", true)256.Case("le32", true)257.Case("le16", true)258.Case("bswap16", true)259.Case("bswap32", true)260.Case("bswap64", true)261.Case("goto", true)262.Case("gotol", true)263.Case("ll", true)264.Case("skb", true)265.Case("s", true)266.Case("atomic_fetch_add", true)267.Case("atomic_fetch_and", true)268.Case("atomic_fetch_or", true)269.Case("atomic_fetch_xor", true)270.Case("xchg_64", true)271.Case("xchg32_32", true)272.Case("cmpxchg_64", true)273.Case("cmpxchg32_32", true)274.Case("addr_space_cast", true)275.Default(false);276}277};278} // end anonymous namespace.279280#define GET_REGISTER_MATCHER281#define GET_MATCHER_IMPLEMENTATION282#include "BPFGenAsmMatcher.inc"283284bool BPFAsmParser::PreMatchCheck(OperandVector &Operands) {285286if (Operands.size() == 4) {287// check "reg1 = -reg2" and "reg1 = be16/be32/be64/le16/le32/le64 reg2",288// reg1 must be the same as reg2289BPFOperand &Op0 = (BPFOperand &)*Operands[0];290BPFOperand &Op1 = (BPFOperand &)*Operands[1];291BPFOperand &Op2 = (BPFOperand &)*Operands[2];292BPFOperand &Op3 = (BPFOperand &)*Operands[3];293if (Op0.isReg() && Op1.isToken() && Op2.isToken() && Op3.isReg()294&& Op1.getToken() == "="295&& (Op2.getToken() == "-" || Op2.getToken() == "be16"296|| Op2.getToken() == "be32" || Op2.getToken() == "be64"297|| Op2.getToken() == "le16" || Op2.getToken() == "le32"298|| Op2.getToken() == "le64")299&& Op0.getReg() != Op3.getReg())300return true;301}302303return false;304}305306bool BPFAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,307OperandVector &Operands,308MCStreamer &Out, uint64_t &ErrorInfo,309bool MatchingInlineAsm) {310MCInst Inst;311SMLoc ErrorLoc;312313if (PreMatchCheck(Operands))314return Error(IDLoc, "additional inst constraint not met");315316switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {317default:318break;319case Match_Success:320Inst.setLoc(IDLoc);321Out.emitInstruction(Inst, getSTI());322return false;323case Match_MissingFeature:324return Error(IDLoc, "instruction use requires an option to be enabled");325case Match_MnemonicFail:326return Error(IDLoc, "unrecognized instruction mnemonic");327case Match_InvalidOperand:328ErrorLoc = IDLoc;329330if (ErrorInfo != ~0U) {331if (ErrorInfo >= Operands.size())332return Error(ErrorLoc, "too few operands for instruction");333334ErrorLoc = ((BPFOperand &)*Operands[ErrorInfo]).getStartLoc();335336if (ErrorLoc == SMLoc())337ErrorLoc = IDLoc;338}339340return Error(ErrorLoc, "invalid operand for instruction");341case Match_InvalidBrTarget:342return Error(Operands[ErrorInfo]->getStartLoc(),343"operand is not an identifier or 16-bit signed integer");344case Match_InvalidSImm16:345return Error(Operands[ErrorInfo]->getStartLoc(),346"operand is not a 16-bit signed integer");347}348349llvm_unreachable("Unknown match type detected!");350}351352bool BPFAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,353SMLoc &EndLoc) {354if (!tryParseRegister(Reg, StartLoc, EndLoc).isSuccess())355return Error(StartLoc, "invalid register name");356return false;357}358359ParseStatus BPFAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,360SMLoc &EndLoc) {361const AsmToken &Tok = getParser().getTok();362StartLoc = Tok.getLoc();363EndLoc = Tok.getEndLoc();364Reg = BPF::NoRegister;365StringRef Name = getLexer().getTok().getIdentifier();366367if (!MatchRegisterName(Name)) {368getParser().Lex(); // Eat identifier token.369return ParseStatus::Success;370}371372return ParseStatus::NoMatch;373}374375ParseStatus BPFAsmParser::parseOperandAsOperator(OperandVector &Operands) {376SMLoc S = getLoc();377378if (getLexer().getKind() == AsmToken::Identifier) {379StringRef Name = getLexer().getTok().getIdentifier();380381if (BPFOperand::isValidIdInMiddle(Name)) {382getLexer().Lex();383Operands.push_back(BPFOperand::createToken(Name, S));384return ParseStatus::Success;385}386387return ParseStatus::NoMatch;388}389390switch (getLexer().getKind()) {391case AsmToken::Minus:392case AsmToken::Plus: {393if (getLexer().peekTok().is(AsmToken::Integer))394return ParseStatus::NoMatch;395[[fallthrough]];396}397398case AsmToken::Equal:399case AsmToken::Greater:400case AsmToken::Less:401case AsmToken::Pipe:402case AsmToken::Star:403case AsmToken::LParen:404case AsmToken::RParen:405case AsmToken::LBrac:406case AsmToken::RBrac:407case AsmToken::Slash:408case AsmToken::Amp:409case AsmToken::Percent:410case AsmToken::Caret: {411StringRef Name = getLexer().getTok().getString();412getLexer().Lex();413Operands.push_back(BPFOperand::createToken(Name, S));414415return ParseStatus::Success;416}417418case AsmToken::EqualEqual:419case AsmToken::ExclaimEqual:420case AsmToken::GreaterEqual:421case AsmToken::GreaterGreater:422case AsmToken::LessEqual:423case AsmToken::LessLess: {424Operands.push_back(BPFOperand::createToken(425getLexer().getTok().getString().substr(0, 1), S));426Operands.push_back(BPFOperand::createToken(427getLexer().getTok().getString().substr(1, 1), S));428getLexer().Lex();429430return ParseStatus::Success;431}432433default:434break;435}436437return ParseStatus::NoMatch;438}439440ParseStatus BPFAsmParser::parseRegister(OperandVector &Operands) {441SMLoc S = getLoc();442SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);443444switch (getLexer().getKind()) {445default:446return ParseStatus::NoMatch;447case AsmToken::Identifier:448StringRef Name = getLexer().getTok().getIdentifier();449unsigned RegNo = MatchRegisterName(Name);450451if (RegNo == 0)452return ParseStatus::NoMatch;453454getLexer().Lex();455Operands.push_back(BPFOperand::createReg(RegNo, S, E));456}457return ParseStatus::Success;458}459460ParseStatus BPFAsmParser::parseImmediate(OperandVector &Operands) {461switch (getLexer().getKind()) {462default:463return ParseStatus::NoMatch;464case AsmToken::LParen:465case AsmToken::Minus:466case AsmToken::Plus:467case AsmToken::Integer:468case AsmToken::String:469case AsmToken::Identifier:470break;471}472473const MCExpr *IdVal;474SMLoc S = getLoc();475476if (getParser().parseExpression(IdVal))477return ParseStatus::Failure;478479SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);480Operands.push_back(BPFOperand::createImm(IdVal, S, E));481482return ParseStatus::Success;483}484485/// ParseInstruction - Parse an BPF instruction which is in BPF verifier486/// format.487bool BPFAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,488SMLoc NameLoc, OperandVector &Operands) {489// The first operand could be either register or actually an operator.490unsigned RegNo = MatchRegisterName(Name);491492if (RegNo != 0) {493SMLoc E = SMLoc::getFromPointer(NameLoc.getPointer() - 1);494Operands.push_back(BPFOperand::createReg(RegNo, NameLoc, E));495} else if (BPFOperand::isValidIdAtStart (Name))496Operands.push_back(BPFOperand::createToken(Name, NameLoc));497else498return Error(NameLoc, "invalid register/token name");499500while (!getLexer().is(AsmToken::EndOfStatement)) {501// Attempt to parse token as operator502if (parseOperandAsOperator(Operands).isSuccess())503continue;504505// Attempt to parse token as register506if (parseRegister(Operands).isSuccess())507continue;508509if (getLexer().is(AsmToken::Comma)) {510getLexer().Lex();511continue;512}513514// Attempt to parse token as an immediate515if (!parseImmediate(Operands).isSuccess()) {516SMLoc Loc = getLexer().getLoc();517return Error(Loc, "unexpected token");518}519}520521if (getLexer().isNot(AsmToken::EndOfStatement)) {522SMLoc Loc = getLexer().getLoc();523524getParser().eatToEndOfStatement();525526return Error(Loc, "unexpected token");527}528529// Consume the EndOfStatement.530getParser().Lex();531return false;532}533534extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFAsmParser() {535RegisterMCAsmParser<BPFAsmParser> X(getTheBPFTarget());536RegisterMCAsmParser<BPFAsmParser> Y(getTheBPFleTarget());537RegisterMCAsmParser<BPFAsmParser> Z(getTheBPFbeTarget());538}539540541