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/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 used
50 // for symbol assignment.
51 bool equalIsAsmAssignment() override { return false; }
52 // "*" is used for dereferencing memory that it will be the start of
53 // statement.
54 bool tokenIsStartOfStatement(AsmToken::TokenKind Token) override {
55 return Token == AsmToken::Star;
56 }
57
58#define GET_ASSEMBLER_HEADER
59#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_TYPES
69#include "BPFGenAsmMatcher.inc"
70#undef GET_OPERAND_DIAGNOSTIC_TYPES
71 };
72
73 BPFAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
74 const MCInstrInfo &MII, const MCTargetOptions &Options)
75 : MCTargetAsmParser(Options, STI, MII) {
76 setAvailableFeatures(ComputeAvailableFeatures(FB: STI.getFeatureBits()));
77 }
78};
79
80/// BPFOperand - Instances of this class represent a parsed machine
81/// instruction
82struct 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>(Val: 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>(x: getConstantImm()));
142 }
143
144 bool isSymbolRef() const { return isImm() && isa<MCSymbolRefExpr>(Val: getImm()); }
145
146 bool isBrTarget() const { return isSymbolRef() || isSImm16(); }
147
148 /// getStartLoc - Gets location of the first token of this operand
149 SMLoc getStartLoc() const override { return StartLoc; }
150 /// getEndLoc - Gets location of the last token of this operand
151 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>(Val: Expr))
187 Inst.addOperand(Op: MCOperand::createImm(Val: CE->getValue()));
188 else
189 Inst.addOperand(Op: MCOperand::createExpr(Val: Expr));
190 }
191
192 // Used by the TableGen Code
193 void addRegOperands(MCInst &Inst, unsigned N) const {
194 assert(N == 1 && "Invalid number of operands!");
195 Inst.addOperand(Op: MCOperand::createReg(Reg: getReg()));
196 }
197
198 void addImmOperands(MCInst &Inst, unsigned N) const {
199 assert(N == 1 && "Invalid number of operands!");
200 addExpr(Inst, Expr: getImm());
201 }
202
203 static std::unique_ptr<BPFOperand> createToken(StringRef Str, SMLoc S) {
204 auto Op = std::make_unique<BPFOperand>(args: 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>(args: 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>(args: 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(S: "if", Value: true)
233 .Case(S: "call", Value: true)
234 .Case(S: "callx", Value: true)
235 .Case(S: "goto", Value: true)
236 .Case(S: "gotol", Value: true)
237 .Case(S: "gotox", Value: true)
238 .Case(S: "may_goto", Value: true)
239 .Case(S: "*", Value: true)
240 .Case(S: "exit", Value: true)
241 .Case(S: "lock", Value: true)
242 .Case(S: "ld_pseudo", Value: true)
243 .Case(S: "store_release", Value: true)
244 .Default(Value: 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(S: "u64", Value: true)
251 .Case(S: "u32", Value: true)
252 .Case(S: "u16", Value: true)
253 .Case(S: "u8", Value: true)
254 .Case(S: "s32", Value: true)
255 .Case(S: "s16", Value: true)
256 .Case(S: "s8", Value: true)
257 .Case(S: "be64", Value: true)
258 .Case(S: "be32", Value: true)
259 .Case(S: "be16", Value: true)
260 .Case(S: "le64", Value: true)
261 .Case(S: "le32", Value: true)
262 .Case(S: "le16", Value: true)
263 .Case(S: "bswap16", Value: true)
264 .Case(S: "bswap32", Value: true)
265 .Case(S: "bswap64", Value: true)
266 .Case(S: "goto", Value: true)
267 .Case(S: "ll", Value: true)
268 .Case(S: "skb", Value: true)
269 .Case(S: "s", Value: true)
270 .Case(S: "atomic_fetch_add", Value: true)
271 .Case(S: "atomic_fetch_and", Value: true)
272 .Case(S: "atomic_fetch_or", Value: true)
273 .Case(S: "atomic_fetch_xor", Value: true)
274 .Case(S: "xchg_64", Value: true)
275 .Case(S: "xchg32_32", Value: true)
276 .Case(S: "cmpxchg_64", Value: true)
277 .Case(S: "cmpxchg32_32", Value: true)
278 .Case(S: "addr_space_cast", Value: true)
279 .Case(S: "load_acquire", Value: true)
280 .Default(Value: false);
281 }
282};
283} // end anonymous namespace.
284
285#define GET_REGISTER_MATCHER
286#define GET_MATCHER_IMPLEMENTATION
287#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 reg2
294 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(L: IDLoc, Msg: "additional inst constraint not met");
320
321 switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, matchingInlineAsm: MatchingInlineAsm)) {
322 default:
323 break;
324 case Match_Success:
325 Inst.setLoc(IDLoc);
326 Out.emitInstruction(Inst, STI: getSTI());
327 return false;
328 case Match_MissingFeature:
329 return Error(L: IDLoc, Msg: "instruction use requires an option to be enabled");
330 case Match_MnemonicFail:
331 return Error(L: IDLoc, Msg: "unrecognized instruction mnemonic");
332 case Match_InvalidOperand:
333 ErrorLoc = IDLoc;
334
335 if (ErrorInfo != ~0U) {
336 if (ErrorInfo >= Operands.size())
337 return Error(L: ErrorLoc, Msg: "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(L: ErrorLoc, Msg: "invalid operand for instruction");
346 case Match_InvalidBrTarget:
347 return Error(L: Operands[ErrorInfo]->getStartLoc(),
348 Msg: "operand is not an identifier or 16-bit signed integer");
349 case Match_InvalidSImm16:
350 return Error(L: Operands[ErrorInfo]->getStartLoc(),
351 Msg: "operand is not a 16-bit signed integer");
352 case Match_InvalidTiedOperand:
353 return Error(L: Operands[ErrorInfo]->getStartLoc(),
354 Msg: "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(L: StartLoc, Msg: "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(Elt: BPFOperand::createToken(Str: 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(K: 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(Elt: BPFOperand::createToken(Str: 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(Elt: BPFOperand::createToken(
433 Str: getLexer().getTok().getString().substr(Start: 0, N: 1), S));
434 Operands.push_back(Elt: BPFOperand::createToken(
435 Str: getLexer().getTok().getString().substr(Start: 1, N: 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(Ptr: 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(Elt: 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(Res&: IdVal))
485 return ParseStatus::Failure;
486
487 SMLoc E = SMLoc::getFromPointer(Ptr: S.getPointer() - 1);
488 Operands.push_back(Elt: BPFOperand::createImm(Val: 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(Ptr: NameLoc.getPointer() - 1);
501 Operands.push_back(Elt: BPFOperand::createReg(Reg, S: NameLoc, E));
502 } else if (BPFOperand::isValidIdAtStart(Name))
503 Operands.push_back(Elt: BPFOperand::createToken(Str: Name, S: NameLoc));
504 else
505 return Error(L: NameLoc, Msg: "invalid register/token name");
506
507 while (!getLexer().is(K: AsmToken::EndOfStatement)) {
508 // Attempt to parse token as operator
509 if (parseOperandAsOperator(Operands).isSuccess())
510 continue;
511
512 // Attempt to parse token as register
513 if (parseRegister(Operands).isSuccess())
514 continue;
515
516 if (getLexer().is(K: AsmToken::Comma)) {
517 getLexer().Lex();
518 continue;
519 }
520
521 // Attempt to parse token as an immediate
522 if (!parseImmediate(Operands).isSuccess()) {
523 SMLoc Loc = getLexer().getLoc();
524 return Error(L: Loc, Msg: "unexpected token");
525 }
526 }
527
528 if (getLexer().isNot(K: AsmToken::EndOfStatement)) {
529 SMLoc Loc = getLexer().getLoc();
530
531 getParser().eatToEndOfStatement();
532
533 return Error(L: Loc, Msg: "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