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/BPFMCTargetDesc.h"
10 #include "TargetInfo/BPFTargetInfo.h"
11 #include "llvm/ADT/STLExtras.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/MCAsmLexer.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
26 using namespace llvm;
27
28 namespace {
29 struct BPFOperand;
30
31 class BPFAsmParser : public MCTargetAsmParser {
32
getLoc() const33 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 &RegNo, SMLoc &StartLoc,
43 SMLoc &EndLoc) override;
44 OperandMatchResultTy tryParseRegister(MCRegister &RegNo, SMLoc &StartLoc,
45 SMLoc &EndLoc) override;
46
47 bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
48 SMLoc NameLoc, OperandVector &Operands) override;
49
50 bool ParseDirective(AsmToken DirectiveID) override;
51
52 // "=" is used as assignment operator for assembly statment, so can't be used
53 // for symbol assignment.
equalIsAsmAssignment()54 bool equalIsAsmAssignment() override { return false; }
55 // "*" is used for dereferencing memory that it will be the start of
56 // statement.
starIsStartOfStatement()57 bool starIsStartOfStatement() override { return true; }
58
59 #define GET_ASSEMBLER_HEADER
60 #include "BPFGenAsmMatcher.inc"
61
62 OperandMatchResultTy parseImmediate(OperandVector &Operands);
63 OperandMatchResultTy parseRegister(OperandVector &Operands);
64 OperandMatchResultTy parseOperandAsOperator(OperandVector &Operands);
65
66 public:
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
BPFAsmParser(const MCSubtargetInfo & STI,MCAsmParser & Parser,const MCInstrInfo & MII,const MCTargetOptions & Options)74 BPFAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
75 const MCInstrInfo &MII, const MCTargetOptions &Options)
76 : MCTargetAsmParser(Options, STI, MII) {
77 setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
78 }
79 };
80
81 /// BPFOperand - Instances of this class represent a parsed machine
82 /// instruction
83 struct BPFOperand : public MCParsedAsmOperand {
84
85 enum KindTy {
86 Token,
87 Register,
88 Immediate,
89 } Kind;
90
91 struct RegOp {
92 unsigned 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
BPFOperand__anonbd5bb9870111::BPFOperand106 BPFOperand(KindTy K) : Kind(K) {}
107
108 public:
BPFOperand__anonbd5bb9870111::BPFOperand109 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
isToken__anonbd5bb9870111::BPFOperand127 bool isToken() const override { return Kind == Token; }
isReg__anonbd5bb9870111::BPFOperand128 bool isReg() const override { return Kind == Register; }
isImm__anonbd5bb9870111::BPFOperand129 bool isImm() const override { return Kind == Immediate; }
isMem__anonbd5bb9870111::BPFOperand130 bool isMem() const override { return false; }
131
isConstantImm__anonbd5bb9870111::BPFOperand132 bool isConstantImm() const {
133 return isImm() && isa<MCConstantExpr>(getImm());
134 }
135
getConstantImm__anonbd5bb9870111::BPFOperand136 int64_t getConstantImm() const {
137 const MCExpr *Val = getImm();
138 return static_cast<const MCConstantExpr *>(Val)->getValue();
139 }
140
isSImm12__anonbd5bb9870111::BPFOperand141 bool isSImm12() const {
142 return (isConstantImm() && isInt<12>(getConstantImm()));
143 }
144
145 /// getStartLoc - Gets location of the first token of this operand
getStartLoc__anonbd5bb9870111::BPFOperand146 SMLoc getStartLoc() const override { return StartLoc; }
147 /// getEndLoc - Gets location of the last token of this operand
getEndLoc__anonbd5bb9870111::BPFOperand148 SMLoc getEndLoc() const override { return EndLoc; }
149
getReg__anonbd5bb9870111::BPFOperand150 unsigned getReg() const override {
151 assert(Kind == Register && "Invalid type access!");
152 return Reg.RegNum;
153 }
154
getImm__anonbd5bb9870111::BPFOperand155 const MCExpr *getImm() const {
156 assert(Kind == Immediate && "Invalid type access!");
157 return Imm.Val;
158 }
159
getToken__anonbd5bb9870111::BPFOperand160 StringRef getToken() const {
161 assert(Kind == Token && "Invalid type access!");
162 return Tok;
163 }
164
print__anonbd5bb9870111::BPFOperand165 void print(raw_ostream &OS) const override {
166 switch (Kind) {
167 case Immediate:
168 OS << *getImm();
169 break;
170 case Register:
171 OS << "<register x";
172 OS << getReg() << ">";
173 break;
174 case Token:
175 OS << "'" << getToken() << "'";
176 break;
177 }
178 }
179
addExpr__anonbd5bb9870111::BPFOperand180 void addExpr(MCInst &Inst, const MCExpr *Expr) const {
181 assert(Expr && "Expr shouldn't be null!");
182
183 if (auto *CE = dyn_cast<MCConstantExpr>(Expr))
184 Inst.addOperand(MCOperand::createImm(CE->getValue()));
185 else
186 Inst.addOperand(MCOperand::createExpr(Expr));
187 }
188
189 // Used by the TableGen Code
addRegOperands__anonbd5bb9870111::BPFOperand190 void addRegOperands(MCInst &Inst, unsigned N) const {
191 assert(N == 1 && "Invalid number of operands!");
192 Inst.addOperand(MCOperand::createReg(getReg()));
193 }
194
addImmOperands__anonbd5bb9870111::BPFOperand195 void addImmOperands(MCInst &Inst, unsigned N) const {
196 assert(N == 1 && "Invalid number of operands!");
197 addExpr(Inst, getImm());
198 }
199
createToken__anonbd5bb9870111::BPFOperand200 static std::unique_ptr<BPFOperand> createToken(StringRef Str, SMLoc S) {
201 auto Op = std::make_unique<BPFOperand>(Token);
202 Op->Tok = Str;
203 Op->StartLoc = S;
204 Op->EndLoc = S;
205 return Op;
206 }
207
createReg__anonbd5bb9870111::BPFOperand208 static std::unique_ptr<BPFOperand> createReg(unsigned RegNo, SMLoc S,
209 SMLoc E) {
210 auto Op = std::make_unique<BPFOperand>(Register);
211 Op->Reg.RegNum = RegNo;
212 Op->StartLoc = S;
213 Op->EndLoc = E;
214 return Op;
215 }
216
createImm__anonbd5bb9870111::BPFOperand217 static std::unique_ptr<BPFOperand> createImm(const MCExpr *Val, SMLoc S,
218 SMLoc E) {
219 auto Op = std::make_unique<BPFOperand>(Immediate);
220 Op->Imm.Val = Val;
221 Op->StartLoc = S;
222 Op->EndLoc = E;
223 return Op;
224 }
225
226 // Identifiers that can be used at the start of a statment.
isValidIdAtStart__anonbd5bb9870111::BPFOperand227 static bool isValidIdAtStart(StringRef Name) {
228 return StringSwitch<bool>(Name.lower())
229 .Case("if", true)
230 .Case("call", true)
231 .Case("goto", true)
232 .Case("*", true)
233 .Case("exit", true)
234 .Case("lock", true)
235 .Case("ld_pseudo", true)
236 .Default(false);
237 }
238
239 // Identifiers that can be used in the middle of a statment.
isValidIdInMiddle__anonbd5bb9870111::BPFOperand240 static bool isValidIdInMiddle(StringRef Name) {
241 return StringSwitch<bool>(Name.lower())
242 .Case("u64", true)
243 .Case("u32", true)
244 .Case("u16", true)
245 .Case("u8", true)
246 .Case("be64", true)
247 .Case("be32", true)
248 .Case("be16", true)
249 .Case("le64", true)
250 .Case("le32", true)
251 .Case("le16", true)
252 .Case("goto", true)
253 .Case("ll", true)
254 .Case("skb", true)
255 .Case("s", true)
256 .Default(false);
257 }
258 };
259 } // end anonymous namespace.
260
261 #define GET_REGISTER_MATCHER
262 #define GET_MATCHER_IMPLEMENTATION
263 #include "BPFGenAsmMatcher.inc"
264
PreMatchCheck(OperandVector & Operands)265 bool BPFAsmParser::PreMatchCheck(OperandVector &Operands) {
266
267 if (Operands.size() == 4) {
268 // check "reg1 = -reg2" and "reg1 = be16/be32/be64/le16/le32/le64 reg2",
269 // reg1 must be the same as reg2
270 BPFOperand &Op0 = (BPFOperand &)*Operands[0];
271 BPFOperand &Op1 = (BPFOperand &)*Operands[1];
272 BPFOperand &Op2 = (BPFOperand &)*Operands[2];
273 BPFOperand &Op3 = (BPFOperand &)*Operands[3];
274 if (Op0.isReg() && Op1.isToken() && Op2.isToken() && Op3.isReg()
275 && Op1.getToken() == "="
276 && (Op2.getToken() == "-" || Op2.getToken() == "be16"
277 || Op2.getToken() == "be32" || Op2.getToken() == "be64"
278 || Op2.getToken() == "le16" || Op2.getToken() == "le32"
279 || Op2.getToken() == "le64")
280 && Op0.getReg() != Op3.getReg())
281 return true;
282 }
283
284 return false;
285 }
286
MatchAndEmitInstruction(SMLoc IDLoc,unsigned & Opcode,OperandVector & Operands,MCStreamer & Out,uint64_t & ErrorInfo,bool MatchingInlineAsm)287 bool BPFAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
288 OperandVector &Operands,
289 MCStreamer &Out, uint64_t &ErrorInfo,
290 bool MatchingInlineAsm) {
291 MCInst Inst;
292 SMLoc ErrorLoc;
293
294 if (PreMatchCheck(Operands))
295 return Error(IDLoc, "additional inst constraint not met");
296
297 switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) {
298 default:
299 break;
300 case Match_Success:
301 Inst.setLoc(IDLoc);
302 Out.emitInstruction(Inst, getSTI());
303 return false;
304 case Match_MissingFeature:
305 return Error(IDLoc, "instruction use requires an option to be enabled");
306 case Match_MnemonicFail:
307 return Error(IDLoc, "unrecognized instruction mnemonic");
308 case Match_InvalidOperand:
309 ErrorLoc = IDLoc;
310
311 if (ErrorInfo != ~0U) {
312 if (ErrorInfo >= Operands.size())
313 return Error(ErrorLoc, "too few operands for instruction");
314
315 ErrorLoc = ((BPFOperand &)*Operands[ErrorInfo]).getStartLoc();
316
317 if (ErrorLoc == SMLoc())
318 ErrorLoc = IDLoc;
319 }
320
321 return Error(ErrorLoc, "invalid operand for instruction");
322 }
323
324 llvm_unreachable("Unknown match type detected!");
325 }
326
parseRegister(MCRegister & RegNo,SMLoc & StartLoc,SMLoc & EndLoc)327 bool BPFAsmParser::parseRegister(MCRegister &RegNo, SMLoc &StartLoc,
328 SMLoc &EndLoc) {
329 if (tryParseRegister(RegNo, StartLoc, EndLoc) != MatchOperand_Success)
330 return Error(StartLoc, "invalid register name");
331 return false;
332 }
333
tryParseRegister(MCRegister & RegNo,SMLoc & StartLoc,SMLoc & EndLoc)334 OperandMatchResultTy BPFAsmParser::tryParseRegister(MCRegister &RegNo,
335 SMLoc &StartLoc,
336 SMLoc &EndLoc) {
337 const AsmToken &Tok = getParser().getTok();
338 StartLoc = Tok.getLoc();
339 EndLoc = Tok.getEndLoc();
340 RegNo = 0;
341 StringRef Name = getLexer().getTok().getIdentifier();
342
343 if (!MatchRegisterName(Name)) {
344 getParser().Lex(); // Eat identifier token.
345 return MatchOperand_Success;
346 }
347
348 return MatchOperand_NoMatch;
349 }
350
351 OperandMatchResultTy
parseOperandAsOperator(OperandVector & Operands)352 BPFAsmParser::parseOperandAsOperator(OperandVector &Operands) {
353 SMLoc S = getLoc();
354
355 if (getLexer().getKind() == AsmToken::Identifier) {
356 StringRef Name = getLexer().getTok().getIdentifier();
357
358 if (BPFOperand::isValidIdInMiddle(Name)) {
359 getLexer().Lex();
360 Operands.push_back(BPFOperand::createToken(Name, S));
361 return MatchOperand_Success;
362 }
363
364 return MatchOperand_NoMatch;
365 }
366
367 switch (getLexer().getKind()) {
368 case AsmToken::Minus:
369 case AsmToken::Plus: {
370 if (getLexer().peekTok().is(AsmToken::Integer))
371 return MatchOperand_NoMatch;
372 [[fallthrough]];
373 }
374
375 case AsmToken::Equal:
376 case AsmToken::Greater:
377 case AsmToken::Less:
378 case AsmToken::Pipe:
379 case AsmToken::Star:
380 case AsmToken::LParen:
381 case AsmToken::RParen:
382 case AsmToken::LBrac:
383 case AsmToken::RBrac:
384 case AsmToken::Slash:
385 case AsmToken::Amp:
386 case AsmToken::Percent:
387 case AsmToken::Caret: {
388 StringRef Name = getLexer().getTok().getString();
389 getLexer().Lex();
390 Operands.push_back(BPFOperand::createToken(Name, S));
391
392 return MatchOperand_Success;
393 }
394
395 case AsmToken::EqualEqual:
396 case AsmToken::ExclaimEqual:
397 case AsmToken::GreaterEqual:
398 case AsmToken::GreaterGreater:
399 case AsmToken::LessEqual:
400 case AsmToken::LessLess: {
401 Operands.push_back(BPFOperand::createToken(
402 getLexer().getTok().getString().substr(0, 1), S));
403 Operands.push_back(BPFOperand::createToken(
404 getLexer().getTok().getString().substr(1, 1), S));
405 getLexer().Lex();
406
407 return MatchOperand_Success;
408 }
409
410 default:
411 break;
412 }
413
414 return MatchOperand_NoMatch;
415 }
416
parseRegister(OperandVector & Operands)417 OperandMatchResultTy BPFAsmParser::parseRegister(OperandVector &Operands) {
418 SMLoc S = getLoc();
419 SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
420
421 switch (getLexer().getKind()) {
422 default:
423 return MatchOperand_NoMatch;
424 case AsmToken::Identifier:
425 StringRef Name = getLexer().getTok().getIdentifier();
426 unsigned RegNo = MatchRegisterName(Name);
427
428 if (RegNo == 0)
429 return MatchOperand_NoMatch;
430
431 getLexer().Lex();
432 Operands.push_back(BPFOperand::createReg(RegNo, S, E));
433 }
434 return MatchOperand_Success;
435 }
436
parseImmediate(OperandVector & Operands)437 OperandMatchResultTy BPFAsmParser::parseImmediate(OperandVector &Operands) {
438 switch (getLexer().getKind()) {
439 default:
440 return MatchOperand_NoMatch;
441 case AsmToken::LParen:
442 case AsmToken::Minus:
443 case AsmToken::Plus:
444 case AsmToken::Integer:
445 case AsmToken::String:
446 case AsmToken::Identifier:
447 break;
448 }
449
450 const MCExpr *IdVal;
451 SMLoc S = getLoc();
452
453 if (getParser().parseExpression(IdVal))
454 return MatchOperand_ParseFail;
455
456 SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
457 Operands.push_back(BPFOperand::createImm(IdVal, S, E));
458
459 return MatchOperand_Success;
460 }
461
462 /// ParseInstruction - Parse an BPF instruction which is in BPF verifier
463 /// format.
ParseInstruction(ParseInstructionInfo & Info,StringRef Name,SMLoc NameLoc,OperandVector & Operands)464 bool BPFAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
465 SMLoc NameLoc, OperandVector &Operands) {
466 // The first operand could be either register or actually an operator.
467 unsigned RegNo = MatchRegisterName(Name);
468
469 if (RegNo != 0) {
470 SMLoc E = SMLoc::getFromPointer(NameLoc.getPointer() - 1);
471 Operands.push_back(BPFOperand::createReg(RegNo, NameLoc, E));
472 } else if (BPFOperand::isValidIdAtStart (Name))
473 Operands.push_back(BPFOperand::createToken(Name, NameLoc));
474 else
475 return Error(NameLoc, "invalid register/token name");
476
477 while (!getLexer().is(AsmToken::EndOfStatement)) {
478 // Attempt to parse token as operator
479 if (parseOperandAsOperator(Operands) == MatchOperand_Success)
480 continue;
481
482 // Attempt to parse token as register
483 if (parseRegister(Operands) == MatchOperand_Success)
484 continue;
485
486 // Attempt to parse token as an immediate
487 if (parseImmediate(Operands) != MatchOperand_Success) {
488 SMLoc Loc = getLexer().getLoc();
489 return Error(Loc, "unexpected token");
490 }
491 }
492
493 if (getLexer().isNot(AsmToken::EndOfStatement)) {
494 SMLoc Loc = getLexer().getLoc();
495
496 getParser().eatToEndOfStatement();
497
498 return Error(Loc, "unexpected token");
499 }
500
501 // Consume the EndOfStatement.
502 getParser().Lex();
503 return false;
504 }
505
ParseDirective(AsmToken DirectiveID)506 bool BPFAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
507
LLVMInitializeBPFAsmParser()508 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFAsmParser() {
509 RegisterMCAsmParser<BPFAsmParser> X(getTheBPFTarget());
510 RegisterMCAsmParser<BPFAsmParser> Y(getTheBPFleTarget());
511 RegisterMCAsmParser<BPFAsmParser> Z(getTheBPFbeTarget());
512 }
513