xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp (revision cfd6422a5217410fbd66f7a7a8a64d9d85e61229)
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 
32   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.
52   bool equalIsAsmAssignment() override { return false; }
53   // "*" is used for dereferencing memory that it will be the start of
54   // statement.
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 
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 
104   BPFOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
105 
106 public:
107   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 
125   bool isToken() const override { return Kind == Token; }
126   bool isReg() const override { return Kind == Register; }
127   bool isImm() const override { return Kind == Immediate; }
128   bool isMem() const override { return false; }
129 
130   bool isConstantImm() const {
131     return isImm() && isa<MCConstantExpr>(getImm());
132   }
133 
134   int64_t getConstantImm() const {
135     const MCExpr *Val = getImm();
136     return static_cast<const MCConstantExpr *>(Val)->getValue();
137   }
138 
139   bool isSImm12() const {
140     return (isConstantImm() && isInt<12>(getConstantImm()));
141   }
142 
143   /// getStartLoc - Gets location of the first token of this operand
144   SMLoc getStartLoc() const override { return StartLoc; }
145   /// getEndLoc - Gets location of the last token of this operand
146   SMLoc getEndLoc() const override { return EndLoc; }
147 
148   unsigned getReg() const override {
149     assert(Kind == Register && "Invalid type access!");
150     return Reg.RegNum;
151   }
152 
153   const MCExpr *getImm() const {
154     assert(Kind == Immediate && "Invalid type access!");
155     return Imm.Val;
156   }
157 
158   StringRef getToken() const {
159     assert(Kind == Token && "Invalid type access!");
160     return Tok;
161   }
162 
163   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 
178   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
188   void addRegOperands(MCInst &Inst, unsigned N) const {
189     assert(N == 1 && "Invalid number of operands!");
190     Inst.addOperand(MCOperand::createReg(getReg()));
191   }
192 
193   void addImmOperands(MCInst &Inst, unsigned N) const {
194     assert(N == 1 && "Invalid number of operands!");
195     addExpr(Inst, getImm());
196   }
197 
198   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 
206   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 
215   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.
225   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.
238   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 
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 
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 
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 
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
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 
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 
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.
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 
504 bool BPFAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
505 
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