546 lines · cpp
1//===-- BPFAsmParser.cpp - Parse BPF assembly to MCInst instructions --===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "MCTargetDesc/BPFMCAsmInfo.h"10#include "MCTargetDesc/BPFMCTargetDesc.h"11#include "TargetInfo/BPFTargetInfo.h"12#include "llvm/ADT/StringSwitch.h"13#include "llvm/MC/MCContext.h"14#include "llvm/MC/MCExpr.h"15#include "llvm/MC/MCInst.h"16#include "llvm/MC/MCInstrInfo.h"17#include "llvm/MC/MCParser/AsmLexer.h"18#include "llvm/MC/MCParser/MCParsedAsmOperand.h"19#include "llvm/MC/MCParser/MCTargetAsmParser.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"24#include "llvm/Support/Compiler.h"25 26using namespace llvm;27 28namespace {29struct BPFOperand;30 31class BPFAsmParser : public MCTargetAsmParser {32 33 SMLoc getLoc() const { return getParser().getTok().getLoc(); }34 35 bool PreMatchCheck(OperandVector &Operands);36 37 bool matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,38 OperandVector &Operands, MCStreamer &Out,39 uint64_t &ErrorInfo,40 bool MatchingInlineAsm) override;41 42 bool parseRegister(MCRegister &Reo, SMLoc &StartLoc, SMLoc &EndLoc) override;43 ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,44 SMLoc &EndLoc) override;45 46 bool parseInstruction(ParseInstructionInfo &Info, StringRef Name,47 SMLoc NameLoc, OperandVector &Operands) override;48 49 // "=" is used as assignment operator for assembly statment, so can't be used50 // for symbol assignment.51 bool equalIsAsmAssignment() override { return false; }52 // "*" is used for dereferencing memory that it will be the start of53 // statement.54 bool tokenIsStartOfStatement(AsmToken::TokenKind Token) override {55 return Token == AsmToken::Star;56 }57 58#define GET_ASSEMBLER_HEADER59#include "BPFGenAsmMatcher.inc"60 61 ParseStatus parseImmediate(OperandVector &Operands);62 ParseStatus parseRegister(OperandVector &Operands);63 ParseStatus parseOperandAsOperator(OperandVector &Operands);64 65public:66 enum BPFMatchResultTy {67 Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,68#define GET_OPERAND_DIAGNOSTIC_TYPES69#include "BPFGenAsmMatcher.inc"70#undef GET_OPERAND_DIAGNOSTIC_TYPES71 };72 73 BPFAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,74 const MCInstrInfo &MII, const MCTargetOptions &Options)75 : MCTargetAsmParser(Options, STI, MII) {76 setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));77 }78};79 80/// BPFOperand - Instances of this class represent a parsed machine81/// instruction82struct BPFOperand : public MCParsedAsmOperand {83 84 enum KindTy {85 Token,86 Register,87 Immediate,88 } Kind;89 90 struct RegOp {91 MCRegister RegNum;92 };93 94 struct ImmOp {95 const MCExpr *Val;96 };97 98 SMLoc StartLoc, EndLoc;99 union {100 StringRef Tok;101 RegOp Reg;102 ImmOp Imm;103 };104 105 BPFOperand(KindTy K) : Kind(K) {}106 107public:108 BPFOperand(const BPFOperand &o) : MCParsedAsmOperand() {109 Kind = o.Kind;110 StartLoc = o.StartLoc;111 EndLoc = o.EndLoc;112 113 switch (Kind) {114 case Register:115 Reg = o.Reg;116 break;117 case Immediate:118 Imm = o.Imm;119 break;120 case Token:121 Tok = o.Tok;122 break;123 }124 }125 126 bool isToken() const override { return Kind == Token; }127 bool isReg() const override { return Kind == Register; }128 bool isImm() const override { return Kind == Immediate; }129 bool isMem() const override { return false; }130 131 bool isConstantImm() const {132 return isImm() && isa<MCConstantExpr>(getImm());133 }134 135 int64_t getConstantImm() const {136 const MCExpr *Val = getImm();137 return static_cast<const MCConstantExpr *>(Val)->getValue();138 }139 140 bool isSImm16() const {141 return (isConstantImm() && isInt<16>(getConstantImm()));142 }143 144 bool isSymbolRef() const { return isImm() && isa<MCSymbolRefExpr>(getImm()); }145 146 bool isBrTarget() const { return isSymbolRef() || isSImm16(); }147 148 /// getStartLoc - Gets location of the first token of this operand149 SMLoc getStartLoc() const override { return StartLoc; }150 /// getEndLoc - Gets location of the last token of this operand151 SMLoc getEndLoc() const override { return EndLoc; }152 153 MCRegister getReg() const override {154 assert(Kind == Register && "Invalid type access!");155 return Reg.RegNum;156 }157 158 const MCExpr *getImm() const {159 assert(Kind == Immediate && "Invalid type access!");160 return Imm.Val;161 }162 163 StringRef getToken() const {164 assert(Kind == Token && "Invalid type access!");165 return Tok;166 }167 168 void print(raw_ostream &OS, const MCAsmInfo &MAI) const override {169 switch (Kind) {170 case Immediate:171 MAI.printExpr(OS, *getImm());172 break;173 case Register:174 OS << "<register x";175 OS << getReg().id() << ">";176 break;177 case Token:178 OS << "'" << getToken() << "'";179 break;180 }181 }182 183 void addExpr(MCInst &Inst, const MCExpr *Expr) const {184 assert(Expr && "Expr shouldn't be null!");185 186 if (auto *CE = dyn_cast<MCConstantExpr>(Expr))187 Inst.addOperand(MCOperand::createImm(CE->getValue()));188 else189 Inst.addOperand(MCOperand::createExpr(Expr));190 }191 192 // Used by the TableGen Code193 void addRegOperands(MCInst &Inst, unsigned N) const {194 assert(N == 1 && "Invalid number of operands!");195 Inst.addOperand(MCOperand::createReg(getReg()));196 }197 198 void addImmOperands(MCInst &Inst, unsigned N) const {199 assert(N == 1 && "Invalid number of operands!");200 addExpr(Inst, getImm());201 }202 203 static std::unique_ptr<BPFOperand> createToken(StringRef Str, SMLoc S) {204 auto Op = std::make_unique<BPFOperand>(Token);205 Op->Tok = Str;206 Op->StartLoc = S;207 Op->EndLoc = S;208 return Op;209 }210 211 static std::unique_ptr<BPFOperand> createReg(MCRegister Reg, SMLoc S,212 SMLoc E) {213 auto Op = std::make_unique<BPFOperand>(Register);214 Op->Reg.RegNum = Reg;215 Op->StartLoc = S;216 Op->EndLoc = E;217 return Op;218 }219 220 static std::unique_ptr<BPFOperand> createImm(const MCExpr *Val, SMLoc S,221 SMLoc E) {222 auto Op = std::make_unique<BPFOperand>(Immediate);223 Op->Imm.Val = Val;224 Op->StartLoc = S;225 Op->EndLoc = E;226 return Op;227 }228 229 // Identifiers that can be used at the start of a statment.230 static bool isValidIdAtStart(StringRef Name) {231 return StringSwitch<bool>(Name.lower())232 .Case("if", true)233 .Case("call", true)234 .Case("callx", true)235 .Case("goto", true)236 .Case("gotol", true)237 .Case("gotox", true)238 .Case("may_goto", true)239 .Case("*", true)240 .Case("exit", true)241 .Case("lock", true)242 .Case("ld_pseudo", true)243 .Case("store_release", true)244 .Default(false);245 }246 247 // Identifiers that can be used in the middle of a statment.248 static bool isValidIdInMiddle(StringRef Name) {249 return StringSwitch<bool>(Name.lower())250 .Case("u64", true)251 .Case("u32", true)252 .Case("u16", true)253 .Case("u8", true)254 .Case("s32", true)255 .Case("s16", true)256 .Case("s8", true)257 .Case("be64", true)258 .Case("be32", true)259 .Case("be16", true)260 .Case("le64", true)261 .Case("le32", true)262 .Case("le16", true)263 .Case("bswap16", true)264 .Case("bswap32", true)265 .Case("bswap64", true)266 .Case("goto", true)267 .Case("ll", true)268 .Case("skb", true)269 .Case("s", true)270 .Case("atomic_fetch_add", true)271 .Case("atomic_fetch_and", true)272 .Case("atomic_fetch_or", true)273 .Case("atomic_fetch_xor", true)274 .Case("xchg_64", true)275 .Case("xchg32_32", true)276 .Case("cmpxchg_64", true)277 .Case("cmpxchg32_32", true)278 .Case("addr_space_cast", true)279 .Case("load_acquire", true)280 .Default(false);281 }282};283} // end anonymous namespace.284 285#define GET_REGISTER_MATCHER286#define GET_MATCHER_IMPLEMENTATION287#include "BPFGenAsmMatcher.inc"288 289bool BPFAsmParser::PreMatchCheck(OperandVector &Operands) {290 291 if (Operands.size() == 4) {292 // check "reg1 = -reg2" and "reg1 = be16/be32/be64/le16/le32/le64 reg2",293 // reg1 must be the same as reg2294 BPFOperand &Op0 = (BPFOperand &)*Operands[0];295 BPFOperand &Op1 = (BPFOperand &)*Operands[1];296 BPFOperand &Op2 = (BPFOperand &)*Operands[2];297 BPFOperand &Op3 = (BPFOperand &)*Operands[3];298 if (Op0.isReg() && Op1.isToken() && Op2.isToken() && Op3.isReg()299 && Op1.getToken() == "="300 && (Op2.getToken() == "-" || Op2.getToken() == "be16"301 || Op2.getToken() == "be32" || Op2.getToken() == "be64"302 || Op2.getToken() == "le16" || Op2.getToken() == "le32"303 || Op2.getToken() == "le64")304 && Op0.getReg() != Op3.getReg())305 return true;306 }307 308 return false;309}310 311bool BPFAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,312 OperandVector &Operands,313 MCStreamer &Out, uint64_t &ErrorInfo,314 bool MatchingInlineAsm) {315 MCInst Inst;316 SMLoc ErrorLoc;317 318 if (PreMatchCheck(Operands))319 return Error(IDLoc, "additional inst constraint not met");320 321 switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {322 default:323 break;324 case Match_Success:325 Inst.setLoc(IDLoc);326 Out.emitInstruction(Inst, getSTI());327 return false;328 case Match_MissingFeature:329 return Error(IDLoc, "instruction use requires an option to be enabled");330 case Match_MnemonicFail:331 return Error(IDLoc, "unrecognized instruction mnemonic");332 case Match_InvalidOperand:333 ErrorLoc = IDLoc;334 335 if (ErrorInfo != ~0U) {336 if (ErrorInfo >= Operands.size())337 return Error(ErrorLoc, "too few operands for instruction");338 339 ErrorLoc = ((BPFOperand &)*Operands[ErrorInfo]).getStartLoc();340 341 if (ErrorLoc == SMLoc())342 ErrorLoc = IDLoc;343 }344 345 return Error(ErrorLoc, "invalid operand for instruction");346 case Match_InvalidBrTarget:347 return Error(Operands[ErrorInfo]->getStartLoc(),348 "operand is not an identifier or 16-bit signed integer");349 case Match_InvalidSImm16:350 return Error(Operands[ErrorInfo]->getStartLoc(),351 "operand is not a 16-bit signed integer");352 case Match_InvalidTiedOperand:353 return Error(Operands[ErrorInfo]->getStartLoc(),354 "operand is not the same as the dst register");355 }356 357 llvm_unreachable("Unknown match type detected!");358}359 360bool BPFAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,361 SMLoc &EndLoc) {362 if (!tryParseRegister(Reg, StartLoc, EndLoc).isSuccess())363 return Error(StartLoc, "invalid register name");364 return false;365}366 367ParseStatus BPFAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,368 SMLoc &EndLoc) {369 const AsmToken &Tok = getParser().getTok();370 StartLoc = Tok.getLoc();371 EndLoc = Tok.getEndLoc();372 Reg = BPF::NoRegister;373 StringRef Name = getLexer().getTok().getIdentifier();374 375 if (!MatchRegisterName(Name)) {376 getParser().Lex(); // Eat identifier token.377 return ParseStatus::Success;378 }379 380 return ParseStatus::NoMatch;381}382 383ParseStatus BPFAsmParser::parseOperandAsOperator(OperandVector &Operands) {384 SMLoc S = getLoc();385 386 if (getLexer().getKind() == AsmToken::Identifier) {387 StringRef Name = getLexer().getTok().getIdentifier();388 389 if (BPFOperand::isValidIdInMiddle(Name)) {390 getLexer().Lex();391 Operands.push_back(BPFOperand::createToken(Name, S));392 return ParseStatus::Success;393 }394 395 return ParseStatus::NoMatch;396 }397 398 switch (getLexer().getKind()) {399 case AsmToken::Minus:400 case AsmToken::Plus: {401 if (getLexer().peekTok().is(AsmToken::Integer))402 return ParseStatus::NoMatch;403 [[fallthrough]];404 }405 406 case AsmToken::Equal:407 case AsmToken::Greater:408 case AsmToken::Less:409 case AsmToken::Pipe:410 case AsmToken::Star:411 case AsmToken::LParen:412 case AsmToken::RParen:413 case AsmToken::LBrac:414 case AsmToken::RBrac:415 case AsmToken::Slash:416 case AsmToken::Amp:417 case AsmToken::Percent:418 case AsmToken::Caret: {419 StringRef Name = getLexer().getTok().getString();420 getLexer().Lex();421 Operands.push_back(BPFOperand::createToken(Name, S));422 423 return ParseStatus::Success;424 }425 426 case AsmToken::EqualEqual:427 case AsmToken::ExclaimEqual:428 case AsmToken::GreaterEqual:429 case AsmToken::GreaterGreater:430 case AsmToken::LessEqual:431 case AsmToken::LessLess: {432 Operands.push_back(BPFOperand::createToken(433 getLexer().getTok().getString().substr(0, 1), S));434 Operands.push_back(BPFOperand::createToken(435 getLexer().getTok().getString().substr(1, 1), S));436 getLexer().Lex();437 438 return ParseStatus::Success;439 }440 441 default:442 break;443 }444 445 return ParseStatus::NoMatch;446}447 448ParseStatus BPFAsmParser::parseRegister(OperandVector &Operands) {449 SMLoc S = getLoc();450 SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);451 452 switch (getLexer().getKind()) {453 default:454 return ParseStatus::NoMatch;455 case AsmToken::Identifier:456 StringRef Name = getLexer().getTok().getIdentifier();457 MCRegister Reg = MatchRegisterName(Name);458 459 if (!Reg)460 return ParseStatus::NoMatch;461 462 getLexer().Lex();463 Operands.push_back(BPFOperand::createReg(Reg, S, E));464 }465 return ParseStatus::Success;466}467 468ParseStatus BPFAsmParser::parseImmediate(OperandVector &Operands) {469 switch (getLexer().getKind()) {470 default:471 return ParseStatus::NoMatch;472 case AsmToken::LParen:473 case AsmToken::Minus:474 case AsmToken::Plus:475 case AsmToken::Integer:476 case AsmToken::String:477 case AsmToken::Identifier:478 break;479 }480 481 const MCExpr *IdVal;482 SMLoc S = getLoc();483 484 if (getParser().parseExpression(IdVal))485 return ParseStatus::Failure;486 487 SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);488 Operands.push_back(BPFOperand::createImm(IdVal, S, E));489 490 return ParseStatus::Success;491}492 493/// Parse an BPF instruction which is in BPF verifier format.494bool BPFAsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name,495 SMLoc NameLoc, OperandVector &Operands) {496 // The first operand could be either register or actually an operator.497 MCRegister Reg = MatchRegisterName(Name);498 499 if (Reg) {500 SMLoc E = SMLoc::getFromPointer(NameLoc.getPointer() - 1);501 Operands.push_back(BPFOperand::createReg(Reg, NameLoc, E));502 } else if (BPFOperand::isValidIdAtStart(Name))503 Operands.push_back(BPFOperand::createToken(Name, NameLoc));504 else505 return Error(NameLoc, "invalid register/token name");506 507 while (!getLexer().is(AsmToken::EndOfStatement)) {508 // Attempt to parse token as operator509 if (parseOperandAsOperator(Operands).isSuccess())510 continue;511 512 // Attempt to parse token as register513 if (parseRegister(Operands).isSuccess())514 continue;515 516 if (getLexer().is(AsmToken::Comma)) {517 getLexer().Lex();518 continue;519 }520 521 // Attempt to parse token as an immediate522 if (!parseImmediate(Operands).isSuccess()) {523 SMLoc Loc = getLexer().getLoc();524 return Error(Loc, "unexpected token");525 }526 }527 528 if (getLexer().isNot(AsmToken::EndOfStatement)) {529 SMLoc Loc = getLexer().getLoc();530 531 getParser().eatToEndOfStatement();532 533 return Error(Loc, "unexpected token");534 }535 536 // Consume the EndOfStatement.537 getParser().Lex();538 return false;539}540 541extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFAsmParser() {542 RegisterMCAsmParser<BPFAsmParser> X(getTheBPFTarget());543 RegisterMCAsmParser<BPFAsmParser> Y(getTheBPFleTarget());544 RegisterMCAsmParser<BPFAsmParser> Z(getTheBPFbeTarget());545}546