xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp (revision 7ef62cebc2f965b0f640263e179276928885e33d)
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 
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 &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.
54   bool equalIsAsmAssignment() override { return false; }
55   // "*" is used for dereferencing memory that it will be the start of
56   // statement.
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 
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 
106   BPFOperand(KindTy K) : Kind(K) {}
107 
108 public:
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>(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 isSImm12() const {
142     return (isConstantImm() && isInt<12>(getConstantImm()));
143   }
144 
145   /// getStartLoc - Gets location of the first token of this operand
146   SMLoc getStartLoc() const override { return StartLoc; }
147   /// getEndLoc - Gets location of the last token of this operand
148   SMLoc getEndLoc() const override { return EndLoc; }
149 
150   unsigned getReg() const override {
151     assert(Kind == Register && "Invalid type access!");
152     return Reg.RegNum;
153   }
154 
155   const MCExpr *getImm() const {
156     assert(Kind == Immediate && "Invalid type access!");
157     return Imm.Val;
158   }
159 
160   StringRef getToken() const {
161     assert(Kind == Token && "Invalid type access!");
162     return Tok;
163   }
164 
165   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 
180   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
190   void addRegOperands(MCInst &Inst, unsigned N) const {
191     assert(N == 1 && "Invalid number of operands!");
192     Inst.addOperand(MCOperand::createReg(getReg()));
193   }
194 
195   void addImmOperands(MCInst &Inst, unsigned N) const {
196     assert(N == 1 && "Invalid number of operands!");
197     addExpr(Inst, getImm());
198   }
199 
200   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 
208   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 
217   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.
227   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.
240   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 
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 
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 
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 
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
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 
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 
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.
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 
506 bool BPFAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
507 
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