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("unwind_goto", true)
239 .Case("*", true)
240 .Case("exit", true)
241 .Case("unwind_exit", true)
242 .Case("lock", true)
243 .Case("ld_pseudo", true)
244 .Case("store_release", true)
245 .Default(false);
246 }
247
248 // Identifiers that can be used in the middle of a statment.
249 static bool isValidIdInMiddle(StringRef Name) {
250 return StringSwitch<bool>(Name.lower())
251 .Case("u64", true)
252 .Case("u32", true)
253 .Case("u16", true)
254 .Case("u8", true)
255 .Case("s32", true)
256 .Case("s16", true)
257 .Case("s8", true)
258 .Case("be64", true)
259 .Case("be32", true)
260 .Case("be16", true)
261 .Case("le64", true)
262 .Case("le32", true)
263 .Case("le16", true)
264 .Case("bswap16", true)
265 .Case("bswap32", true)
266 .Case("bswap64", true)
267 .Case("goto", true)
268 .Case("ll", true)
269 .Case("skb", true)
270 .Case("s", true)
271 .Case("uh", true)
272 .Case("sh", true)
273 .Case("atomic_fetch_add", true)
274 .Case("atomic_fetch_and", true)
275 .Case("atomic_fetch_or", true)
276 .Case("atomic_fetch_xor", true)
277 .Case("xchg_64", true)
278 .Case("xchg32_32", true)
279 .Case("cmpxchg_64", true)
280 .Case("cmpxchg32_32", true)
281 .Case("addr_space_cast", true)
282 .Case("load_acquire", true)
283 .Default(false);
284 }
285};
286} // end anonymous namespace.
287
288#define GET_REGISTER_MATCHER
289#define GET_MATCHER_IMPLEMENTATION
290#include "BPFGenAsmMatcher.inc"
291
292bool BPFAsmParser::PreMatchCheck(OperandVector &Operands) {
293
294 if (Operands.size() == 4) {
295 // check "reg1 = -reg2" and "reg1 = be16/be32/be64/le16/le32/le64 reg2",
296 // reg1 must be the same as reg2
297 BPFOperand &Op0 = (BPFOperand &)*Operands[0];
298 BPFOperand &Op1 = (BPFOperand &)*Operands[1];
299 BPFOperand &Op2 = (BPFOperand &)*Operands[2];
300 BPFOperand &Op3 = (BPFOperand &)*Operands[3];
301 if (Op0.isReg() && Op1.isToken() && Op2.isToken() && Op3.isReg()
302 && Op1.getToken() == "="
303 && (Op2.getToken() == "-" || Op2.getToken() == "be16"
304 || Op2.getToken() == "be32" || Op2.getToken() == "be64"
305 || Op2.getToken() == "le16" || Op2.getToken() == "le32"
306 || Op2.getToken() == "le64")
307 && Op0.getReg() != Op3.getReg())
308 return true;
309 }
310
311 return false;
312}
313
314bool BPFAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
316 MCStreamer &Out, uint64_t &ErrorInfo,
317 bool MatchingInlineAsm) {
318 MCInst Inst;
319 SMLoc ErrorLoc;
320
321 if (PreMatchCheck(Operands))
322 return Error(IDLoc, "additional inst constraint not met");
323
324 switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
325 default:
326 break;
327 case Match_Success:
328 Inst.setLoc(IDLoc);
329 Out.emitInstruction(Inst, getSTI());
330 return false;
331 case Match_MissingFeature:
332 return Error(IDLoc, "instruction use requires an option to be enabled");
333 case Match_MnemonicFail:
334 return Error(IDLoc, "unrecognized instruction mnemonic");
335 case Match_InvalidOperand:
336 ErrorLoc = IDLoc;
337
338 if (ErrorInfo != ~0U) {
339 if (ErrorInfo >= Operands.size())
340 return Error(ErrorLoc, "too few operands for instruction");
341
342 ErrorLoc = ((BPFOperand &)*Operands[ErrorInfo]).getStartLoc();
343
344 if (ErrorLoc == SMLoc())
345 ErrorLoc = IDLoc;
346 }
347
348 return Error(ErrorLoc, "invalid operand for instruction");
349 case Match_InvalidBrTarget:
350 return Error(Operands[ErrorInfo]->getStartLoc(),
351 "operand is not an identifier or 16-bit signed integer");
352 case Match_InvalidSImm16:
353 return Error(Operands[ErrorInfo]->getStartLoc(),
354 "operand is not a 16-bit signed integer");
355 case Match_InvalidTiedOperand:
356 return Error(Operands[ErrorInfo]->getStartLoc(),
357 "operand is not the same as the dst register");
358 }
359
360 llvm_unreachable("Unknown match type detected!");
361}
362
363bool BPFAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,
364 SMLoc &EndLoc) {
365 if (!tryParseRegister(Reg, StartLoc, EndLoc).isSuccess())
366 return Error(StartLoc, "invalid register name");
367 return false;
368}
369
370ParseStatus BPFAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
371 SMLoc &EndLoc) {
372 const AsmToken &Tok = getParser().getTok();
373 StartLoc = Tok.getLoc();
374 EndLoc = Tok.getEndLoc();
375 Reg = BPF::NoRegister;
376 StringRef Name = getLexer().getTok().getIdentifier();
377
378 if (!MatchRegisterName(Name)) {
379 getParser().Lex(); // Eat identifier token.
381 }
382
384}
385
386ParseStatus BPFAsmParser::parseOperandAsOperator(OperandVector &Operands) {
387 SMLoc S = getLoc();
388
389 if (getLexer().getKind() == AsmToken::Identifier) {
390 StringRef Name = getLexer().getTok().getIdentifier();
391
392 if (BPFOperand::isValidIdInMiddle(Name)) {
393 getLexer().Lex();
394 Operands.push_back(BPFOperand::createToken(Name, S));
396 }
397
399 }
400
401 switch (getLexer().getKind()) {
402 case AsmToken::Minus:
403 case AsmToken::Plus: {
404 if (getLexer().peekTok().is(AsmToken::Integer))
406 [[fallthrough]];
407 }
408
409 case AsmToken::Equal:
411 case AsmToken::Less:
412 case AsmToken::Pipe:
413 case AsmToken::Star:
414 case AsmToken::LParen:
415 case AsmToken::RParen:
416 case AsmToken::LBrac:
417 case AsmToken::RBrac:
418 case AsmToken::Slash:
419 case AsmToken::Amp:
421 case AsmToken::Caret: {
422 StringRef Name = getLexer().getTok().getString();
423 getLexer().Lex();
424 Operands.push_back(BPFOperand::createToken(Name, S));
425
427 }
428
434 case AsmToken::LessLess: {
435 Operands.push_back(BPFOperand::createToken(
436 getLexer().getTok().getString().substr(0, 1), S));
437 Operands.push_back(BPFOperand::createToken(
438 getLexer().getTok().getString().substr(1, 1), S));
439 getLexer().Lex();
440
442 }
443
444 default:
445 break;
446 }
447
449}
450
451ParseStatus BPFAsmParser::parseRegister(OperandVector &Operands) {
452 SMLoc S = getLoc();
453 SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
454
455 switch (getLexer().getKind()) {
456 default:
459 StringRef Name = getLexer().getTok().getIdentifier();
460 MCRegister Reg = MatchRegisterName(Name);
461
462 if (!Reg)
464
465 getLexer().Lex();
466 Operands.push_back(BPFOperand::createReg(Reg, S, E));
467 }
469}
470
471ParseStatus BPFAsmParser::parseImmediate(OperandVector &Operands) {
472 switch (getLexer().getKind()) {
473 default:
475 case AsmToken::LParen:
476 case AsmToken::Minus:
477 case AsmToken::Plus:
479 case AsmToken::String:
481 break;
482 }
483
484 const MCExpr *IdVal;
485 SMLoc S = getLoc();
486
487 if (getParser().parseExpression(IdVal))
489
490 SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
491 Operands.push_back(BPFOperand::createImm(IdVal, S, E));
492
494}
495
496/// Parse an BPF instruction which is in BPF verifier format.
497bool BPFAsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name,
498 SMLoc NameLoc, OperandVector &Operands) {
499 // The first operand could be either register or actually an operator.
500 MCRegister Reg = MatchRegisterName(Name);
501
502 if (Reg) {
503 SMLoc E = SMLoc::getFromPointer(NameLoc.getPointer() - 1);
504 Operands.push_back(BPFOperand::createReg(Reg, NameLoc, E));
505 } else if (BPFOperand::isValidIdAtStart(Name))
506 Operands.push_back(BPFOperand::createToken(Name, NameLoc));
507 else
508 return Error(NameLoc, "invalid register/token name");
509
510 while (!getLexer().is(AsmToken::EndOfStatement)) {
511 // Attempt to parse token as operator
512 if (parseOperandAsOperator(Operands).isSuccess())
513 continue;
514
515 // Attempt to parse token as register
516 if (parseRegister(Operands).isSuccess())
517 continue;
518
519 if (getLexer().is(AsmToken::Comma)) {
520 getLexer().Lex();
521 continue;
522 }
523
524 // Attempt to parse token as an immediate
525 if (!parseImmediate(Operands).isSuccess()) {
526 SMLoc Loc = getLexer().getLoc();
527 return Error(Loc, "unexpected token");
528 }
529 }
530
531 if (getLexer().isNot(AsmToken::EndOfStatement)) {
532 SMLoc Loc = getLexer().getLoc();
533
534 getParser().eatToEndOfStatement();
535
536 return Error(Loc, "unexpected token");
537 }
538
539 // Consume the EndOfStatement.
540 getParser().Lex();
541 return false;
542}
543
static MCRegister MatchRegisterName(StringRef Name)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
uint64_t Imm
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:211
#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
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,...