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