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