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