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
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/MCRegisterInfo.h"
21#include "llvm/MC/MCStreamer.h"
22#include "llvm/MC/MCSubtargetInfo.h"
23#include "llvm/MC/TargetRegistry.h"
24#include "llvm/Support/Casting.h"
25#include "llvm/Support/Compiler.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
62 ParseStatus parseImmediate(OperandVector &Operands);
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(FB: 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>(Val: 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>(x: getConstantImm()));
143 }
144
145 bool isSymbolRef() const { return isImm() && isa<MCSymbolRefExpr>(Val: 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>(Val: Expr))
188 Inst.addOperand(Op: MCOperand::createImm(Val: CE->getValue()));
189 else
190 Inst.addOperand(Op: MCOperand::createExpr(Val: Expr));
191 }
192
193 // Used by the TableGen Code
194 void addRegOperands(MCInst &Inst, unsigned N) const {
195 assert(N == 1 && "Invalid number of operands!");
196 Inst.addOperand(Op: MCOperand::createReg(Reg: getReg()));
197 }
198
199 void addImmOperands(MCInst &Inst, unsigned N) const {
200 assert(N == 1 && "Invalid number of operands!");
201 addExpr(Inst, Expr: getImm());
202 }
203
204 static std::unique_ptr<BPFOperand> createToken(StringRef Str, SMLoc S) {
205 auto Op = std::make_unique<BPFOperand>(args: 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>(args: 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>(args: 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(S: "if", Value: true)
234 .Case(S: "call", Value: true)
235 .Case(S: "callx", Value: true)
236 .Case(S: "goto", Value: true)
237 .Case(S: "gotol", Value: true)
238 .Case(S: "gotox", Value: true)
239 .Case(S: "may_goto", Value: true)
240 .Case(S: "*", Value: true)
241 .Case(S: "exit", Value: true)
242 .Case(S: "lock", Value: true)
243 .Case(S: "ld_pseudo", Value: true)
244 .Case(S: "store_release", Value: true)
245 .Default(Value: 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(S: "u64", Value: true)
252 .Case(S: "u32", Value: true)
253 .Case(S: "u16", Value: true)
254 .Case(S: "u8", Value: true)
255 .Case(S: "s32", Value: true)
256 .Case(S: "s16", Value: true)
257 .Case(S: "s8", Value: true)
258 .Case(S: "be64", Value: true)
259 .Case(S: "be32", Value: true)
260 .Case(S: "be16", Value: true)
261 .Case(S: "le64", Value: true)
262 .Case(S: "le32", Value: true)
263 .Case(S: "le16", Value: true)
264 .Case(S: "bswap16", Value: true)
265 .Case(S: "bswap32", Value: true)
266 .Case(S: "bswap64", Value: true)
267 .Case(S: "goto", Value: true)
268 .Case(S: "ll", Value: true)
269 .Case(S: "skb", Value: true)
270 .Case(S: "s", Value: true)
271 .Case(S: "atomic_fetch_add", Value: true)
272 .Case(S: "atomic_fetch_and", Value: true)
273 .Case(S: "atomic_fetch_or", Value: true)
274 .Case(S: "atomic_fetch_xor", Value: true)
275 .Case(S: "xchg_64", Value: true)
276 .Case(S: "xchg32_32", Value: true)
277 .Case(S: "cmpxchg_64", Value: true)
278 .Case(S: "cmpxchg32_32", Value: true)
279 .Case(S: "addr_space_cast", Value: true)
280 .Case(S: "load_acquire", Value: true)
281 .Default(Value: 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,
313 OperandVector &Operands,
314 MCStreamer &Out, uint64_t &ErrorInfo,
315 bool MatchingInlineAsm) {
316 MCInst Inst;
317 SMLoc ErrorLoc;
318
319 if (PreMatchCheck(Operands))
320 return Error(L: IDLoc, Msg: "additional inst constraint not met");
321
322 switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, matchingInlineAsm: MatchingInlineAsm)) {
323 default:
324 break;
325 case Match_Success:
326 Inst.setLoc(IDLoc);
327 Out.emitInstruction(Inst, STI: getSTI());
328 return false;
329 case Match_MissingFeature:
330 return Error(L: IDLoc, Msg: "instruction use requires an option to be enabled");
331 case Match_MnemonicFail:
332 return Error(L: IDLoc, Msg: "unrecognized instruction mnemonic");
333 case Match_InvalidOperand:
334 ErrorLoc = IDLoc;
335
336 if (ErrorInfo != ~0U) {
337 if (ErrorInfo >= Operands.size())
338 return Error(L: ErrorLoc, Msg: "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(L: ErrorLoc, Msg: "invalid operand for instruction");
347 case Match_InvalidBrTarget:
348 return Error(L: Operands[ErrorInfo]->getStartLoc(),
349 Msg: "operand is not an identifier or 16-bit signed integer");
350 case Match_InvalidSImm16:
351 return Error(L: Operands[ErrorInfo]->getStartLoc(),
352 Msg: "operand is not a 16-bit signed integer");
353 case Match_InvalidTiedOperand:
354 return Error(L: Operands[ErrorInfo]->getStartLoc(),
355 Msg: "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(L: StartLoc, Msg: "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.
378 return ParseStatus::Success;
379 }
380
381 return ParseStatus::NoMatch;
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(Elt: BPFOperand::createToken(Str: Name, S));
393 return ParseStatus::Success;
394 }
395
396 return ParseStatus::NoMatch;
397 }
398
399 switch (getLexer().getKind()) {
400 case AsmToken::Minus:
401 case AsmToken::Plus: {
402 if (getLexer().peekTok().is(K: AsmToken::Integer))
403 return ParseStatus::NoMatch;
404 [[fallthrough]];
405 }
406
407 case AsmToken::Equal:
408 case AsmToken::Greater:
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:
418 case AsmToken::Percent:
419 case AsmToken::Caret: {
420 StringRef Name = getLexer().getTok().getString();
421 getLexer().Lex();
422 Operands.push_back(Elt: BPFOperand::createToken(Str: Name, S));
423
424 return ParseStatus::Success;
425 }
426
427 case AsmToken::EqualEqual:
428 case AsmToken::ExclaimEqual:
429 case AsmToken::GreaterEqual:
430 case AsmToken::GreaterGreater:
431 case AsmToken::LessEqual:
432 case AsmToken::LessLess: {
433 Operands.push_back(Elt: BPFOperand::createToken(
434 Str: getLexer().getTok().getString().substr(Start: 0, N: 1), S));
435 Operands.push_back(Elt: BPFOperand::createToken(
436 Str: getLexer().getTok().getString().substr(Start: 1, N: 1), S));
437 getLexer().Lex();
438
439 return ParseStatus::Success;
440 }
441
442 default:
443 break;
444 }
445
446 return ParseStatus::NoMatch;
447}
448
449ParseStatus BPFAsmParser::parseRegister(OperandVector &Operands) {
450 SMLoc S = getLoc();
451 SMLoc E = SMLoc::getFromPointer(Ptr: S.getPointer() - 1);
452
453 switch (getLexer().getKind()) {
454 default:
455 return ParseStatus::NoMatch;
456 case AsmToken::Identifier:
457 StringRef Name = getLexer().getTok().getIdentifier();
458 MCRegister Reg = MatchRegisterName(Name);
459
460 if (!Reg)
461 return ParseStatus::NoMatch;
462
463 getLexer().Lex();
464 Operands.push_back(Elt: BPFOperand::createReg(Reg, S, E));
465 }
466 return ParseStatus::Success;
467}
468
469ParseStatus BPFAsmParser::parseImmediate(OperandVector &Operands) {
470 switch (getLexer().getKind()) {
471 default:
472 return ParseStatus::NoMatch;
473 case AsmToken::LParen:
474 case AsmToken::Minus:
475 case AsmToken::Plus:
476 case AsmToken::Integer:
477 case AsmToken::String:
478 case AsmToken::Identifier:
479 break;
480 }
481
482 const MCExpr *IdVal;
483 SMLoc S = getLoc();
484
485 if (getParser().parseExpression(Res&: IdVal))
486 return ParseStatus::Failure;
487
488 SMLoc E = SMLoc::getFromPointer(Ptr: S.getPointer() - 1);
489 Operands.push_back(Elt: BPFOperand::createImm(Val: IdVal, S, E));
490
491 return ParseStatus::Success;
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(Ptr: NameLoc.getPointer() - 1);
502 Operands.push_back(Elt: BPFOperand::createReg(Reg, S: NameLoc, E));
503 } else if (BPFOperand::isValidIdAtStart(Name))
504 Operands.push_back(Elt: BPFOperand::createToken(Str: Name, S: NameLoc));
505 else
506 return Error(L: NameLoc, Msg: "invalid register/token name");
507
508 while (!getLexer().is(K: 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(K: 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(L: Loc, Msg: "unexpected token");
526 }
527 }
528
529 if (getLexer().isNot(K: AsmToken::EndOfStatement)) {
530 SMLoc Loc = getLexer().getLoc();
531
532 getParser().eatToEndOfStatement();
533
534 return Error(L: Loc, Msg: "unexpected token");
535 }
536
537 // Consume the EndOfStatement.
538 getParser().Lex();
539 return false;
540}
541
542extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFAsmParser() {
543 RegisterMCAsmParser<BPFAsmParser> X(getTheBPFTarget());
544 RegisterMCAsmParser<BPFAsmParser> Y(getTheBPFleTarget());
545 RegisterMCAsmParser<BPFAsmParser> Z(getTheBPFbeTarget());
546}
547