1 // LoongArchAsmParser.cpp - Parse LoongArch 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/LoongArchInstPrinter.h"
10 #include "MCTargetDesc/LoongArchMCTargetDesc.h"
11 #include "TargetInfo/LoongArchTargetInfo.h"
12 #include "llvm/MC/MCContext.h"
13 #include "llvm/MC/MCInstrInfo.h"
14 #include "llvm/MC/MCParser/MCAsmLexer.h"
15 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
16 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
17 #include "llvm/MC/MCStreamer.h"
18 #include "llvm/MC/MCSubtargetInfo.h"
19 #include "llvm/MC/TargetRegistry.h"
20 #include "llvm/Support/Casting.h"
21 
22 using namespace llvm;
23 
24 #define DEBUG_TYPE "loongarch-asm-parser"
25 
26 namespace {
27 class LoongArchAsmParser : public MCTargetAsmParser {
28   SMLoc getLoc() const { return getParser().getTok().getLoc(); }
29 
30   /// Parse a register as used in CFI directives.
31   bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
32   OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc,
33                                         SMLoc &EndLoc) override;
34 
35   bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
36                         SMLoc NameLoc, OperandVector &Operands) override;
37 
38   bool ParseDirective(AsmToken DirectiveID) override { return true; }
39 
40   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
41                                OperandVector &Operands, MCStreamer &Out,
42                                uint64_t &ErrorInfo,
43                                bool MatchingInlineAsm) override;
44 
45   bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo,
46                                   int64_t Lower, int64_t Upper, Twine Msg);
47 
48   /// Helper for processing MC instructions that have been successfully matched
49   /// by MatchAndEmitInstruction.
50   bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands,
51                           MCStreamer &Out);
52 
53 // Auto-generated instruction matching functions.
54 #define GET_ASSEMBLER_HEADER
55 #include "LoongArchGenAsmMatcher.inc"
56 
57   OperandMatchResultTy parseRegister(OperandVector &Operands);
58   OperandMatchResultTy parseImmediate(OperandVector &Operands);
59 
60   bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
61 
62 public:
63   enum LoongArchMatchResultTy {
64     Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
65 #define GET_OPERAND_DIAGNOSTIC_TYPES
66 #include "LoongArchGenAsmMatcher.inc"
67 #undef GET_OPERAND_DIAGNOSTIC_TYPES
68   };
69 
70   LoongArchAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
71                      const MCInstrInfo &MII, const MCTargetOptions &Options)
72       : MCTargetAsmParser(Options, STI, MII) {
73     Parser.addAliasForDirective(".half", ".2byte");
74     Parser.addAliasForDirective(".hword", ".2byte");
75     Parser.addAliasForDirective(".word", ".4byte");
76     Parser.addAliasForDirective(".dword", ".8byte");
77 
78     // Initialize the set of available features.
79     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
80   }
81 };
82 
83 // Instances of this class represent a parsed LoongArch machine instruction.
84 class LoongArchOperand : public MCParsedAsmOperand {
85   enum class KindTy {
86     Token,
87     Register,
88     Immediate,
89   } Kind;
90 
91   struct RegOp {
92     MCRegister RegNum;
93   };
94 
95   struct ImmOp {
96     const MCExpr *Val;
97   };
98 
99   SMLoc StartLoc, EndLoc;
100   union {
101     StringRef Tok;
102     struct RegOp Reg;
103     struct ImmOp Imm;
104   };
105 
106 public:
107   LoongArchOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
108 
109   bool isToken() const override { return Kind == KindTy::Token; }
110   bool isReg() const override { return Kind == KindTy::Register; }
111   bool isImm() const override { return Kind == KindTy::Immediate; }
112   bool isMem() const override { return false; }
113 
114   static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm) {
115     if (auto CE = dyn_cast<MCConstantExpr>(Expr)) {
116       Imm = CE->getValue();
117       return true;
118     }
119 
120     return false;
121   }
122 
123   template <unsigned N, int P = 0> bool isUImm() const {
124     if (!isImm())
125       return false;
126 
127     int64_t Imm;
128     bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
129     return IsConstantImm && isUInt<N>(Imm - P);
130   }
131 
132   template <unsigned N, unsigned S = 0> bool isSImm() const {
133     if (!isImm())
134       return false;
135 
136     int64_t Imm;
137     bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
138     return IsConstantImm && isShiftedInt<N, S>(Imm);
139   }
140 
141   bool isUImm2() const { return isUImm<2>(); }
142   bool isUImm2plus1() const { return isUImm<2, 1>(); }
143   bool isUImm3() const { return isUImm<3>(); }
144   bool isUImm5() const { return isUImm<5>(); }
145   bool isUImm6() const { return isUImm<6>(); }
146   bool isUImm12() const { return isUImm<12>(); }
147   bool isUImm15() const { return isUImm<15>(); }
148   bool isSImm12() const { return isSImm<12>(); }
149   bool isSImm14lsl2() const { return isSImm<14, 2>(); }
150   bool isSImm16() const { return isSImm<16>(); }
151   bool isSImm16lsl2() const { return isSImm<16, 2>(); }
152   bool isSImm20() const { return isSImm<20>(); }
153   bool isSImm21lsl2() const { return isSImm<21, 2>(); }
154   bool isSImm26lsl2() const { return isSImm<26, 2>(); }
155 
156   /// Gets location of the first token of this operand.
157   SMLoc getStartLoc() const override { return StartLoc; }
158   /// Gets location of the last token of this operand.
159   SMLoc getEndLoc() const override { return EndLoc; }
160 
161   unsigned getReg() const override {
162     assert(Kind == KindTy::Register && "Invalid type access!");
163     return Reg.RegNum.id();
164   }
165 
166   const MCExpr *getImm() const {
167     assert(Kind == KindTy::Immediate && "Invalid type access!");
168     return Imm.Val;
169   }
170 
171   StringRef getToken() const {
172     assert(Kind == KindTy::Token && "Invalid type access!");
173     return Tok;
174   }
175 
176   void print(raw_ostream &OS) const override {
177     auto RegName = [](unsigned Reg) {
178       if (Reg)
179         return LoongArchInstPrinter::getRegisterName(Reg);
180       else
181         return "noreg";
182     };
183 
184     switch (Kind) {
185     case KindTy::Immediate:
186       OS << *getImm();
187       break;
188     case KindTy::Register:
189       OS << "<register " << RegName(getReg()) << ">";
190       break;
191     case KindTy::Token:
192       OS << "'" << getToken() << "'";
193       break;
194     }
195   }
196 
197   static std::unique_ptr<LoongArchOperand> createToken(StringRef Str, SMLoc S) {
198     auto Op = std::make_unique<LoongArchOperand>(KindTy::Token);
199     Op->Tok = Str;
200     Op->StartLoc = S;
201     Op->EndLoc = S;
202     return Op;
203   }
204 
205   static std::unique_ptr<LoongArchOperand> createReg(unsigned RegNo, SMLoc S,
206                                                      SMLoc E) {
207     auto Op = std::make_unique<LoongArchOperand>(KindTy::Register);
208     Op->Reg.RegNum = RegNo;
209     Op->StartLoc = S;
210     Op->EndLoc = E;
211     return Op;
212   }
213 
214   static std::unique_ptr<LoongArchOperand> createImm(const MCExpr *Val, SMLoc S,
215                                                      SMLoc E) {
216     auto Op = std::make_unique<LoongArchOperand>(KindTy::Immediate);
217     Op->Imm.Val = Val;
218     Op->StartLoc = S;
219     Op->EndLoc = E;
220     return Op;
221   }
222 
223   void addExpr(MCInst &Inst, const MCExpr *Expr) const {
224     if (auto CE = dyn_cast<MCConstantExpr>(Expr))
225       Inst.addOperand(MCOperand::createImm(CE->getValue()));
226     else
227       Inst.addOperand(MCOperand::createExpr(Expr));
228   }
229 
230   // Used by the TableGen Code.
231   void addRegOperands(MCInst &Inst, unsigned N) const {
232     assert(N == 1 && "Invalid number of operands!");
233     Inst.addOperand(MCOperand::createReg(getReg()));
234   }
235   void addImmOperands(MCInst &Inst, unsigned N) const {
236     assert(N == 1 && "Invalid number of operands!");
237     addExpr(Inst, getImm());
238   }
239 };
240 } // end anonymous namespace
241 
242 #define GET_REGISTER_MATCHER
243 #define GET_SUBTARGET_FEATURE_NAME
244 #define GET_MATCHER_IMPLEMENTATION
245 #define GET_MNEMONIC_SPELL_CHECKER
246 #include "LoongArchGenAsmMatcher.inc"
247 
248 static bool matchRegisterNameHelper(MCRegister &RegNo, StringRef Name) {
249   RegNo = MatchRegisterName(Name);
250 
251   if (RegNo == LoongArch::NoRegister)
252     RegNo = MatchRegisterAltName(Name);
253 
254   return RegNo == LoongArch::NoRegister;
255 }
256 
257 bool LoongArchAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
258                                        SMLoc &EndLoc) {
259   return Error(getLoc(), "invalid register number");
260 }
261 
262 OperandMatchResultTy LoongArchAsmParser::tryParseRegister(unsigned &RegNo,
263                                                           SMLoc &StartLoc,
264                                                           SMLoc &EndLoc) {
265   llvm_unreachable("Unimplemented function.");
266 }
267 
268 OperandMatchResultTy
269 LoongArchAsmParser::parseRegister(OperandVector &Operands) {
270   if (getLexer().getTok().isNot(AsmToken::Dollar))
271     return MatchOperand_NoMatch;
272 
273   // Eat the $ prefix.
274   getLexer().Lex();
275   if (getLexer().getKind() != AsmToken::Identifier)
276     return MatchOperand_NoMatch;
277 
278   StringRef Name = getLexer().getTok().getIdentifier();
279   MCRegister RegNo;
280   matchRegisterNameHelper(RegNo, Name);
281   if (RegNo == LoongArch::NoRegister)
282     return MatchOperand_NoMatch;
283 
284   SMLoc S = getLoc();
285   SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size());
286   getLexer().Lex();
287   Operands.push_back(LoongArchOperand::createReg(RegNo, S, E));
288 
289   return MatchOperand_Success;
290 }
291 
292 OperandMatchResultTy
293 LoongArchAsmParser::parseImmediate(OperandVector &Operands) {
294   SMLoc S = getLoc();
295   SMLoc E;
296   const MCExpr *Res;
297 
298   if (getParser().parseExpression(Res, E))
299     return MatchOperand_ParseFail;
300 
301   Operands.push_back(LoongArchOperand::createImm(Res, S, E));
302   return MatchOperand_Success;
303 }
304 
305 /// Looks at a token type and creates the relevant operand from this
306 /// information, adding to Operands. Return true upon an error.
307 bool LoongArchAsmParser::parseOperand(OperandVector &Operands,
308                                       StringRef Mnemonic) {
309   if (parseRegister(Operands) == MatchOperand_Success ||
310       parseImmediate(Operands) == MatchOperand_Success)
311     return false;
312 
313   // Finally we have exhausted all options and must declare defeat.
314   Error(getLoc(), "unknown operand");
315   return true;
316 }
317 
318 bool LoongArchAsmParser::ParseInstruction(ParseInstructionInfo &Info,
319                                           StringRef Name, SMLoc NameLoc,
320                                           OperandVector &Operands) {
321   // First operand in MCInst is instruction mnemonic.
322   Operands.push_back(LoongArchOperand::createToken(Name, NameLoc));
323 
324   // If there are no more operands, then finish.
325   if (parseOptionalToken(AsmToken::EndOfStatement))
326     return false;
327 
328   // Parse first operand.
329   if (parseOperand(Operands, Name))
330     return true;
331 
332   // Parse until end of statement, consuming commas between operands.
333   while (parseOptionalToken(AsmToken::Comma))
334     if (parseOperand(Operands, Name))
335       return true;
336 
337   // Parse end of statement and return successfully.
338   if (parseOptionalToken(AsmToken::EndOfStatement))
339     return false;
340 
341   SMLoc Loc = getLexer().getLoc();
342   getParser().eatToEndOfStatement();
343   return Error(Loc, "unexpected token");
344 }
345 
346 bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
347                                             OperandVector &Operands,
348                                             MCStreamer &Out) {
349   Inst.setLoc(IDLoc);
350   Out.emitInstruction(Inst, getSTI());
351   return false;
352 }
353 
354 bool LoongArchAsmParser::generateImmOutOfRangeError(
355     OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper,
356     Twine Msg = "immediate must be an integer in the range") {
357   SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
358   return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]");
359 }
360 
361 bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
362                                                  OperandVector &Operands,
363                                                  MCStreamer &Out,
364                                                  uint64_t &ErrorInfo,
365                                                  bool MatchingInlineAsm) {
366   MCInst Inst;
367   FeatureBitset MissingFeatures;
368 
369   auto Result = MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
370                                      MatchingInlineAsm);
371   switch (Result) {
372   default:
373     break;
374   case Match_Success:
375     return processInstruction(Inst, IDLoc, Operands, Out);
376   case Match_MissingFeature: {
377     assert(MissingFeatures.any() && "Unknown missing features!");
378     bool FirstFeature = true;
379     std::string Msg = "instruction requires the following:";
380     for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
381       if (MissingFeatures[i]) {
382         Msg += FirstFeature ? " " : ", ";
383         Msg += getSubtargetFeatureName(i);
384         FirstFeature = false;
385       }
386     }
387     return Error(IDLoc, Msg);
388   }
389   case Match_MnemonicFail: {
390     FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
391     std::string Suggestion = LoongArchMnemonicSpellCheck(
392         ((LoongArchOperand &)*Operands[0]).getToken(), FBS, 0);
393     return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion);
394   }
395   case Match_InvalidOperand: {
396     SMLoc ErrorLoc = IDLoc;
397     if (ErrorInfo != ~0ULL) {
398       if (ErrorInfo >= Operands.size())
399         return Error(ErrorLoc, "too few operands for instruction");
400 
401       ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
402       if (ErrorLoc == SMLoc())
403         ErrorLoc = IDLoc;
404     }
405     return Error(ErrorLoc, "invalid operand for instruction");
406   }
407   }
408 
409   // Handle the case when the error message is of specific type
410   // other than the generic Match_InvalidOperand, and the
411   // corresponding operand is missing.
412   if (Result > FIRST_TARGET_MATCH_RESULT_TY) {
413     SMLoc ErrorLoc = IDLoc;
414     if (ErrorInfo != ~0ULL && ErrorInfo >= Operands.size())
415       return Error(ErrorLoc, "too few operands for instruction");
416   }
417 
418   switch (Result) {
419   default:
420     break;
421   case Match_InvalidUImm2:
422     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
423                                       /*Upper=*/(1 << 2) - 1);
424   case Match_InvalidUImm2plus1:
425     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/1,
426                                       /*Upper=*/(1 << 2));
427   case Match_InvalidUImm3:
428     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
429                                       /*Upper=*/(1 << 3) - 1);
430   case Match_InvalidUImm5:
431     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
432                                       /*Upper=*/(1 << 5) - 1);
433   case Match_InvalidUImm6:
434     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
435                                       /*Upper=*/(1 << 6) - 1);
436   case Match_InvalidUImm12:
437     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
438                                       /*Upper=*/(1 << 12) - 1);
439   case Match_InvalidUImm15:
440     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
441                                       /*Upper=*/(1 << 15) - 1);
442   case Match_InvalidSImm12:
443     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 11),
444                                       /*Upper=*/(1 << 11) - 1);
445   case Match_InvalidSImm14lsl2:
446     return generateImmOutOfRangeError(
447         Operands, ErrorInfo, /*Lower=*/-(1 << 15), /*Upper=*/(1 << 15) - 4,
448         "immediate must be a multiple of 4 in the range");
449   case Match_InvalidSImm16:
450     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 15),
451                                       /*Upper=*/(1 << 15) - 1);
452   case Match_InvalidSImm16lsl2:
453     return generateImmOutOfRangeError(
454         Operands, ErrorInfo, /*Lower=*/-(1 << 17), /*Upper=*/(1 << 17) - 4,
455         "immediate must be a multiple of 4 in the range");
456   case Match_InvalidSImm20:
457     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 19),
458                                       /*Upper=*/(1 << 19) - 1);
459   case Match_InvalidSImm21lsl2:
460     return generateImmOutOfRangeError(
461         Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4,
462         "immediate must be a multiple of 4 in the range");
463   case Match_InvalidSImm26lsl2:
464     return generateImmOutOfRangeError(
465         Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4,
466         "immediate must be a multiple of 4 in the range");
467   }
468   llvm_unreachable("Unknown match type detected!");
469 }
470 
471 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() {
472   RegisterMCAsmParser<LoongArchAsmParser> X(getTheLoongArch32Target());
473   RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target());
474 }
475