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