xref: /openbsd-src/gnu/llvm/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
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