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