LLVM 24.0.0git
BPFAsmParser.cpp
Go to the documentation of this file.
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-exception
6//
7//===----------------------------------------------------------------------===//
8
12#include "llvm/MC/MCContext.h"
13#include "llvm/MC/MCExpr.h"
14#include "llvm/MC/MCInst.h"
15#include "llvm/MC/MCInstrInfo.h"
19#include "llvm/MC/MCStreamer.h"
24
25using namespace llvm;
26
27namespace {
28struct BPFOperand;
29
30class BPFAsmParser : public MCTargetAsmParser {
31
32 SMLoc getLoc() const { return getParser().getTok().getLoc(); }
33
34 bool PreMatchCheck(OperandVector &Operands);
35
36 bool matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
37 OperandVector &Operands, MCStreamer &Out,
38 uint64_t &ErrorInfo,
39 bool MatchingInlineAsm) override;
40
41 bool parseRegister(MCRegister &Reo, SMLoc &StartLoc, SMLoc &EndLoc) override;
42 ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
43 SMLoc &EndLoc) override;
44
45 bool parseInstruction(ParseInstructionInfo &Info, StringRef Name,
46 SMLoc NameLoc, OperandVector &Operands) override;
47
48 // "=" is used as assignment operator for assembly statment, so can't be used
49 // for symbol assignment.
50 bool equalIsAsmAssignment() override { return false; }
51 // "*" is used for dereferencing memory that it will be the start of
52 // statement.
53 bool tokenIsStartOfStatement(AsmToken::TokenKind Token) override {
54 return Token == AsmToken::Star;
55 }
56
57#define GET_ASSEMBLER_HEADER
58#include "BPFGenAsmMatcher.inc"
59
61 ParseStatus parseRegister(OperandVector &Operands);
62 ParseStatus parseOperandAsOperator(OperandVector &Operands);
63
64public:
65 enum BPFMatchResultTy {
66 Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
67#define GET_OPERAND_DIAGNOSTIC_TYPES
68#include "BPFGenAsmMatcher.inc"
69#undef GET_OPERAND_DIAGNOSTIC_TYPES
70 };
71
72 BPFAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
73 const MCInstrInfo &MII)
74 : MCTargetAsmParser(STI, MII) {
75 setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
76 }
77};
78
79/// BPFOperand - Instances of this class represent a parsed machine
80/// instruction
81struct BPFOperand : public MCParsedAsmOperand {
82
83 enum KindTy {
84 Token,
85 Register,
86 Immediate,
87 } Kind;
88
89 struct RegOp {
90 MCRegister RegNum;
91 };
92
93 struct ImmOp {
94 const MCExpr *Val;
95 };
96
97 SMLoc StartLoc, EndLoc;
98 union {
99 StringRef Tok;
100 RegOp Reg;
101 ImmOp Imm;
102 };
103
104 BPFOperand(KindTy K) : Kind(K) {}
105
106public:
107 BPFOperand(const BPFOperand &o) : MCParsedAsmOperand() {
108 Kind = o.Kind;
109 StartLoc = o.StartLoc;
110 EndLoc = o.EndLoc;
111
112 switch (Kind) {
113 case Register:
114 Reg = o.Reg;
115 break;
116 case Immediate:
117 Imm = o.Imm;
118 break;
119 case Token:
120 Tok = o.Tok;
121 break;
122 }
123 }
124
125 bool isToken() const override { return Kind == Token; }
126 bool isReg() const override { return Kind == Register; }
127 bool isImm() const override { return Kind == Immediate; }
128 bool isMem() const override { return false; }
129
130 bool isConstantImm() const {
131 return isImm() && isa<MCConstantExpr>(getImm());
132 }
133
134 int64_t getConstantImm() const {
135 const MCExpr *Val = getImm();
136 return static_cast<const MCConstantExpr *>(Val)->getValue();
137 }
138
139 bool isSImm16() const {
140 return (isConstantImm() && isInt<16>(getConstantImm()));
141 }
142
143 bool isSymbolRef() const { return isImm() && isa<MCSymbolRefExpr>(getImm()); }
144
145 bool isBrTarget() const { return isSymbolRef() || isSImm16(); }
146
147 /// getStartLoc - Gets location of the first token of this operand
148 SMLoc getStartLoc() const override { return StartLoc; }
149 /// getEndLoc - Gets location of the last token of this operand
150 SMLoc getEndLoc() const override { return EndLoc; }
151
152 MCRegister getReg() const override {
153 assert(Kind == Register && "Invalid type access!");
154 return Reg.RegNum;
155 }
156
157 const MCExpr *getImm() const {
158 assert(Kind == Immediate && "Invalid type access!");
159 return Imm.Val;
160 }
161
162 StringRef getToken() const {
163 assert(Kind == Token && "Invalid type access!");
164 return Tok;
165 }
166
167 void print(raw_ostream &OS, const MCAsmInfo &MAI) const override {
168 switch (Kind) {
169 case Immediate:
170 MAI.printExpr(OS, *getImm());
171 break;
172 case Register:
173 OS << "<register x";
174 OS << getReg().id() << ">";
175 break;
176 case Token:
177 OS << "'" << getToken() << "'";
178 break;
179 }
180 }
181
182 void addExpr(MCInst &Inst, const MCExpr *Expr) const {
183 assert(Expr && "Expr shouldn't be null!");
184
185 if (auto *CE = dyn_cast<MCConstantExpr>(Expr))
186 Inst.addOperand(MCOperand::createImm(CE->getValue()));
187 else
189 }
190
191 // Used by the TableGen Code
192 void addRegOperands(MCInst &Inst, unsigned N) const {
193 assert(N == 1 && "Invalid number of operands!");
195 }
196
197 void addImmOperands(MCInst &Inst, unsigned N) const {
198 assert(N == 1 && "Invalid number of operands!");
199 addExpr(Inst, getImm());
200 }
201
202 static std::unique_ptr<BPFOperand> createToken(StringRef Str, SMLoc S) {
203 auto Op = std::make_unique<BPFOperand>(Token);
204 Op->Tok = Str;
205 Op->StartLoc = S;
206 Op->EndLoc = S;
207 return Op;
208 }
209
210 static std::unique_ptr<BPFOperand> createReg(MCRegister Reg, SMLoc S,
211 SMLoc E) {
212 auto Op = std::make_unique<BPFOperand>(Register);
213 Op->Reg.RegNum = Reg;
214 Op->StartLoc = S;
215 Op->EndLoc = E;
216 return Op;
217 }
218
219 static std::unique_ptr<BPFOperand> createImm(const MCExpr *Val, SMLoc S,
220 SMLoc E) {
221 auto Op = std::make_unique<BPFOperand>(Immediate);
222 Op->Imm.Val = Val;
223 Op->StartLoc = S;
224 Op->EndLoc = E;
225 return Op;
226 }
227
228 // Identifiers that can be used at the start of a statment.
229 static bool isValidIdAtStart(StringRef Name) {
230 return StringSwitch<bool>(Name.lower())
231 .Case("if", true)
232 .Case("call", true)
233 .Case("callx", true)
234 .Case("goto", true)
235 .Case("gotol", true)
236 .Case("gotox", true)
237 .Case("may_goto", true)
238 .Case("*", true)
239 .Case("exit", true)
240 .Case("lock", true)
241 .Case("ld_pseudo", true)
242 .Case("store_release", true)
243 .Default(false);
244 }
245
246 // Identifiers that can be used in the middle of a statment.
247 static bool isValidIdInMiddle(StringRef Name) {
248 return StringSwitch<bool>(Name.lower())
249 .Case("u64", true)
250 .Case("u32", true)
251 .Case("u16", true)
252 .Case("u8", true)
253 .Case("s32", true)
254 .Case("s16", true)
255 .Case("s8", true)
256 .Case("be64", true)
257 .Case("be32", true)
258 .Case("be16", true)
259 .Case("le64", true)
260 .Case("le32", true)
261 .Case("le16", true)
262 .Case("bswap16", true)
263 .Case("bswap32", true)
264 .Case("bswap64", true)
265 .Case("goto", true)
266 .Case("ll", true)
267 .Case("skb", true)
268 .Case("s", true)
269 .Case("atomic_fetch_add", true)
270 .Case("atomic_fetch_and", true)
271 .Case("atomic_fetch_or", true)
272 .Case("atomic_fetch_xor", true)
273 .Case("xchg_64", true)
274 .Case("xchg32_32", true)
275 .Case("cmpxchg_64", true)
276 .Case("cmpxchg32_32", true)
277 .Case("addr_space_cast", true)
278 .Case("load_acquire", true)
279 .Default(false);
280 }
281};
282} // end anonymous namespace.
283
284#define GET_REGISTER_MATCHER
285#define GET_MATCHER_IMPLEMENTATION
286#include "BPFGenAsmMatcher.inc"
287
288bool BPFAsmParser::PreMatchCheck(OperandVector &Operands) {
289
290 if (Operands.size() == 4) {
291 // check "reg1 = -reg2" and "reg1 = be16/be32/be64/le16/le32/le64 reg2",
292 // reg1 must be the same as reg2
293 BPFOperand &Op0 = (BPFOperand &)*Operands[0];
294 BPFOperand &Op1 = (BPFOperand &)*Operands[1];
295 BPFOperand &Op2 = (BPFOperand &)*Operands[2];
296 BPFOperand &Op3 = (BPFOperand &)*Operands[3];
297 if (Op0.isReg() && Op1.isToken() && Op2.isToken() && Op3.isReg()
298 && Op1.getToken() == "="
299 && (Op2.getToken() == "-" || Op2.getToken() == "be16"
300 || Op2.getToken() == "be32" || Op2.getToken() == "be64"
301 || Op2.getToken() == "le16" || Op2.getToken() == "le32"
302 || Op2.getToken() == "le64")
303 && Op0.getReg() != Op3.getReg())
304 return true;
305 }
306
307 return false;
308}
309
310bool BPFAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
312 MCStreamer &Out, uint64_t &ErrorInfo,
313 bool MatchingInlineAsm) {
314 MCInst Inst;
315 SMLoc ErrorLoc;
316
317 if (PreMatchCheck(Operands))
318 return Error(IDLoc, "additional inst constraint not met");
319
320 switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
321 default:
322 break;
323 case Match_Success:
324 Inst.setLoc(IDLoc);
325 Out.emitInstruction(Inst, getSTI());
326 return false;
327 case Match_MissingFeature:
328 return Error(IDLoc, "instruction use requires an option to be enabled");
329 case Match_MnemonicFail:
330 return Error(IDLoc, "unrecognized instruction mnemonic");
331 case Match_InvalidOperand:
332 ErrorLoc = IDLoc;
333
334 if (ErrorInfo != ~0U) {
335 if (ErrorInfo >= Operands.size())
336 return Error(ErrorLoc, "too few operands for instruction");
337
338 ErrorLoc = ((BPFOperand &)*Operands[ErrorInfo]).getStartLoc();
339
340 if (ErrorLoc == SMLoc())
341 ErrorLoc = IDLoc;
342 }
343
344 return Error(ErrorLoc, "invalid operand for instruction");
345 case Match_InvalidBrTarget:
346 return Error(Operands[ErrorInfo]->getStartLoc(),
347 "operand is not an identifier or 16-bit signed integer");
348 case Match_InvalidSImm16:
349 return Error(Operands[ErrorInfo]->getStartLoc(),
350 "operand is not a 16-bit signed integer");
351 case Match_InvalidTiedOperand:
352 return Error(Operands[ErrorInfo]->getStartLoc(),
353 "operand is not the same as the dst register");
354 }
355
356 llvm_unreachable("Unknown match type detected!");
357}
358
359bool BPFAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,
360 SMLoc &EndLoc) {
361 if (!tryParseRegister(Reg, StartLoc, EndLoc).isSuccess())
362 return Error(StartLoc, "invalid register name");
363 return false;
364}
365
366ParseStatus BPFAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
367 SMLoc &EndLoc) {
368 const AsmToken &Tok = getParser().getTok();
369 StartLoc = Tok.getLoc();
370 EndLoc = Tok.getEndLoc();
371 Reg = BPF::NoRegister;
372 StringRef Name = getLexer().getTok().getIdentifier();
373
374 if (!MatchRegisterName(Name)) {
375 getParser().Lex(); // Eat identifier token.
377 }
378
380}
381
382ParseStatus BPFAsmParser::parseOperandAsOperator(OperandVector &Operands) {
383 SMLoc S = getLoc();
384
385 if (getLexer().getKind() == AsmToken::Identifier) {
386 StringRef Name = getLexer().getTok().getIdentifier();
387
388 if (BPFOperand::isValidIdInMiddle(Name)) {
389 getLexer().Lex();
390 Operands.push_back(BPFOperand::createToken(Name, S));
392 }
393
395 }
396
397 switch (getLexer().getKind()) {
398 case AsmToken::Minus:
399 case AsmToken::Plus: {
400 if (getLexer().peekTok().is(AsmToken::Integer))
402 [[fallthrough]];
403 }
404
405 case AsmToken::Equal:
407 case AsmToken::Less:
408 case AsmToken::Pipe:
409 case AsmToken::Star:
410 case AsmToken::LParen:
411 case AsmToken::RParen:
412 case AsmToken::LBrac:
413 case AsmToken::RBrac:
414 case AsmToken::Slash:
415 case AsmToken::Amp:
417 case AsmToken::Caret: {
418 StringRef Name = getLexer().getTok().getString();
419 getLexer().Lex();
420 Operands.push_back(BPFOperand::createToken(Name, S));
421
423 }
424
430 case AsmToken::LessLess: {
431 Operands.push_back(BPFOperand::createToken(
432 getLexer().getTok().getString().substr(0, 1), S));
433 Operands.push_back(BPFOperand::createToken(
434 getLexer().getTok().getString().substr(1, 1), S));
435 getLexer().Lex();
436
438 }
439
440 default:
441 break;
442 }
443
445}
446
447ParseStatus BPFAsmParser::parseRegister(OperandVector &Operands) {
448 SMLoc S = getLoc();
449 SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
450
451 switch (getLexer().getKind()) {
452 default:
455 StringRef Name = getLexer().getTok().getIdentifier();
456 MCRegister Reg = MatchRegisterName(Name);
457
458 if (!Reg)
460
461 getLexer().Lex();
462 Operands.push_back(BPFOperand::createReg(Reg, S, E));
463 }
465}
466
467ParseStatus BPFAsmParser::parseImmediate(OperandVector &Operands) {
468 switch (getLexer().getKind()) {
469 default:
471 case AsmToken::LParen:
472 case AsmToken::Minus:
473 case AsmToken::Plus:
475 case AsmToken::String:
477 break;
478 }
479
480 const MCExpr *IdVal;
481 SMLoc S = getLoc();
482
483 if (getParser().parseExpression(IdVal))
485
486 SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
487 Operands.push_back(BPFOperand::createImm(IdVal, S, E));
488
490}
491
492/// Parse an BPF instruction which is in BPF verifier format.
493bool BPFAsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name,
494 SMLoc NameLoc, OperandVector &Operands) {
495 // The first operand could be either register or actually an operator.
496 MCRegister Reg = MatchRegisterName(Name);
497
498 if (Reg) {
499 SMLoc E = SMLoc::getFromPointer(NameLoc.getPointer() - 1);
500 Operands.push_back(BPFOperand::createReg(Reg, NameLoc, E));
501 } else if (BPFOperand::isValidIdAtStart(Name))
502 Operands.push_back(BPFOperand::createToken(Name, NameLoc));
503 else
504 return Error(NameLoc, "invalid register/token name");
505
506 while (!getLexer().is(AsmToken::EndOfStatement)) {
507 // Attempt to parse token as operator
508 if (parseOperandAsOperator(Operands).isSuccess())
509 continue;
510
511 // Attempt to parse token as register
512 if (parseRegister(Operands).isSuccess())
513 continue;
514
515 if (getLexer().is(AsmToken::Comma)) {
516 getLexer().Lex();
517 continue;
518 }
519
520 // Attempt to parse token as an immediate
521 if (!parseImmediate(Operands).isSuccess()) {
522 SMLoc Loc = getLexer().getLoc();
523 return Error(Loc, "unexpected token");
524 }
525 }
526
527 if (getLexer().isNot(AsmToken::EndOfStatement)) {
528 SMLoc Loc = getLexer().getLoc();
529
530 getParser().eatToEndOfStatement();
531
532 return Error(Loc, "unexpected token");
533 }
534
535 // Consume the EndOfStatement.
536 getParser().Lex();
537 return false;
538}
539
static MCRegister MatchRegisterName(StringRef Name)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned Imm
unsigned uint64_t
static bool isNot(const MachineRegisterInfo &MRI, const MachineInstr &MI)
LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFAsmParser()
#define X(NUM, ENUM, NAME)
Definition ELF.h:857
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_ABI
Definition Compiler.h:215
#define LLVM_EXTERNAL_VISIBILITY
Definition Compiler.h:132
static constexpr Value * getValue(Ty &ValueOrUse)
Register Reg
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
static bool isReg(const MCInst &MI, unsigned OpNo)
SI Fold Operands
static StringRef substr(StringRef Str, uint64_t Len)
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef< uint8_t > Bytes)
LLVM_ABI SMLoc getLoc() const
Definition AsmLexer.cpp:31
LLVM_ABI SMLoc getEndLoc() const
Definition AsmLexer.cpp:33
void printExpr(raw_ostream &, const MCExpr &) const
void setLoc(SMLoc loc)
Definition MCInst.h:207
void addOperand(const MCOperand Op)
Definition MCInst.h:215
static MCOperand createExpr(const MCExpr *Val)
Definition MCInst.h:166
static MCOperand createReg(MCRegister Reg)
Definition MCInst.h:138
static MCOperand createImm(int64_t Val)
Definition MCInst.h:145
MCParsedAsmOperand - This abstract class represents a source-level assembly instruction operand.
constexpr unsigned id() const
Definition MCRegister.h:82
virtual void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI)
Emit the given Instruction into the current section.
const FeatureBitset & getFeatureBits() const
MCTargetAsmParser - Generic interface to target specific assembly parsers.
Ternary parse status returned by various parse* methods.
static constexpr StatusTy Failure
static constexpr StatusTy Success
static constexpr StatusTy NoMatch
static SMLoc getFromPointer(const char *Ptr)
Definition SMLoc.h:35
constexpr const char * getPointer() const
Definition SMLoc.h:33
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ CE
Windows NT (Windows on ARM)
Definition MCAsmInfo.h:51
This is an optimization pass for GlobalISel generic memory operations.
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:166
static bool isMem(const MachineInstr &MI, unsigned Op)
LLVM_ABI std::pair< StringRef, StringRef > getToken(StringRef Source, StringRef Delimiters=" \t\n\v\f\r")
getToken - This function extracts one token from source, ignoring any leading characters that appear ...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
Target & getTheBPFleTarget()
SmallVectorImpl< std::unique_ptr< MCParsedAsmOperand > > OperandVector
Target & getTheBPFbeTarget()
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
Target & getTheBPFTarget()
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
DWARFExpression::Operation Op
#define N
RegisterMCAsmParser - Helper template for registering a target specific assembly parser,...