xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp (revision 972a253a57b6f144b0e4a3e2080a2a0076ec55a0)
181ad6265SDimitry Andric // LoongArchAsmParser.cpp - Parse LoongArch assembly to MCInst instructions -=//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric 
981ad6265SDimitry Andric #include "MCTargetDesc/LoongArchInstPrinter.h"
1081ad6265SDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h"
1181ad6265SDimitry Andric #include "TargetInfo/LoongArchTargetInfo.h"
1281ad6265SDimitry Andric #include "llvm/MC/MCContext.h"
1381ad6265SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
1481ad6265SDimitry Andric #include "llvm/MC/MCParser/MCAsmLexer.h"
1581ad6265SDimitry Andric #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
1681ad6265SDimitry Andric #include "llvm/MC/MCParser/MCTargetAsmParser.h"
1781ad6265SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
1881ad6265SDimitry Andric #include "llvm/MC/MCStreamer.h"
1981ad6265SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
2081ad6265SDimitry Andric #include "llvm/MC/TargetRegistry.h"
2181ad6265SDimitry Andric #include "llvm/Support/Casting.h"
2281ad6265SDimitry Andric 
2381ad6265SDimitry Andric using namespace llvm;
2481ad6265SDimitry Andric 
2581ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-asm-parser"
2681ad6265SDimitry Andric 
2781ad6265SDimitry Andric namespace {
2881ad6265SDimitry Andric class LoongArchAsmParser : public MCTargetAsmParser {
2981ad6265SDimitry Andric   SMLoc getLoc() const { return getParser().getTok().getLoc(); }
3081ad6265SDimitry Andric 
3181ad6265SDimitry Andric   /// Parse a register as used in CFI directives.
3281ad6265SDimitry Andric   bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
3381ad6265SDimitry Andric   OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc,
3481ad6265SDimitry Andric                                         SMLoc &EndLoc) override;
3581ad6265SDimitry Andric 
3681ad6265SDimitry Andric   bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
3781ad6265SDimitry Andric                         SMLoc NameLoc, OperandVector &Operands) override;
3881ad6265SDimitry Andric 
3981ad6265SDimitry Andric   bool ParseDirective(AsmToken DirectiveID) override { return true; }
4081ad6265SDimitry Andric 
4181ad6265SDimitry Andric   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
4281ad6265SDimitry Andric                                OperandVector &Operands, MCStreamer &Out,
4381ad6265SDimitry Andric                                uint64_t &ErrorInfo,
4481ad6265SDimitry Andric                                bool MatchingInlineAsm) override;
4581ad6265SDimitry Andric 
4681ad6265SDimitry Andric   unsigned checkTargetMatchPredicate(MCInst &Inst) override;
4781ad6265SDimitry Andric 
4881ad6265SDimitry Andric   unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
4981ad6265SDimitry Andric                                       unsigned Kind) override;
5081ad6265SDimitry Andric 
5181ad6265SDimitry Andric   bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo,
5281ad6265SDimitry Andric                                   int64_t Lower, int64_t Upper, Twine Msg);
5381ad6265SDimitry Andric 
5481ad6265SDimitry Andric   /// Helper for processing MC instructions that have been successfully matched
5581ad6265SDimitry Andric   /// by MatchAndEmitInstruction.
5681ad6265SDimitry Andric   bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands,
5781ad6265SDimitry Andric                           MCStreamer &Out);
5881ad6265SDimitry Andric 
5981ad6265SDimitry Andric // Auto-generated instruction matching functions.
6081ad6265SDimitry Andric #define GET_ASSEMBLER_HEADER
6181ad6265SDimitry Andric #include "LoongArchGenAsmMatcher.inc"
6281ad6265SDimitry Andric 
6381ad6265SDimitry Andric   OperandMatchResultTy parseRegister(OperandVector &Operands);
6481ad6265SDimitry Andric   OperandMatchResultTy parseImmediate(OperandVector &Operands);
6581ad6265SDimitry Andric 
6681ad6265SDimitry Andric   bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
6781ad6265SDimitry Andric 
6881ad6265SDimitry Andric public:
6981ad6265SDimitry Andric   enum LoongArchMatchResultTy {
7081ad6265SDimitry Andric     Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
7181ad6265SDimitry Andric     Match_RequiresMsbNotLessThanLsb,
7281ad6265SDimitry Andric     Match_RequiresOpnd2NotR0R1,
7381ad6265SDimitry Andric #define GET_OPERAND_DIAGNOSTIC_TYPES
7481ad6265SDimitry Andric #include "LoongArchGenAsmMatcher.inc"
7581ad6265SDimitry Andric #undef GET_OPERAND_DIAGNOSTIC_TYPES
7681ad6265SDimitry Andric   };
7781ad6265SDimitry Andric 
7881ad6265SDimitry Andric   LoongArchAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
7981ad6265SDimitry Andric                      const MCInstrInfo &MII, const MCTargetOptions &Options)
8081ad6265SDimitry Andric       : MCTargetAsmParser(Options, STI, MII) {
8181ad6265SDimitry Andric     Parser.addAliasForDirective(".half", ".2byte");
8281ad6265SDimitry Andric     Parser.addAliasForDirective(".hword", ".2byte");
8381ad6265SDimitry Andric     Parser.addAliasForDirective(".word", ".4byte");
8481ad6265SDimitry Andric     Parser.addAliasForDirective(".dword", ".8byte");
8581ad6265SDimitry Andric 
8681ad6265SDimitry Andric     // Initialize the set of available features.
8781ad6265SDimitry Andric     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
8881ad6265SDimitry Andric   }
8981ad6265SDimitry Andric };
9081ad6265SDimitry Andric 
9181ad6265SDimitry Andric // Instances of this class represent a parsed LoongArch machine instruction.
9281ad6265SDimitry Andric class LoongArchOperand : public MCParsedAsmOperand {
9381ad6265SDimitry Andric   enum class KindTy {
9481ad6265SDimitry Andric     Token,
9581ad6265SDimitry Andric     Register,
9681ad6265SDimitry Andric     Immediate,
9781ad6265SDimitry Andric   } Kind;
9881ad6265SDimitry Andric 
9981ad6265SDimitry Andric   struct RegOp {
10081ad6265SDimitry Andric     MCRegister RegNum;
10181ad6265SDimitry Andric   };
10281ad6265SDimitry Andric 
10381ad6265SDimitry Andric   struct ImmOp {
10481ad6265SDimitry Andric     const MCExpr *Val;
10581ad6265SDimitry Andric   };
10681ad6265SDimitry Andric 
10781ad6265SDimitry Andric   SMLoc StartLoc, EndLoc;
10881ad6265SDimitry Andric   union {
10981ad6265SDimitry Andric     StringRef Tok;
11081ad6265SDimitry Andric     struct RegOp Reg;
11181ad6265SDimitry Andric     struct ImmOp Imm;
11281ad6265SDimitry Andric   };
11381ad6265SDimitry Andric 
11481ad6265SDimitry Andric public:
11581ad6265SDimitry Andric   LoongArchOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
11681ad6265SDimitry Andric 
11781ad6265SDimitry Andric   bool isToken() const override { return Kind == KindTy::Token; }
11881ad6265SDimitry Andric   bool isReg() const override { return Kind == KindTy::Register; }
11981ad6265SDimitry Andric   bool isImm() const override { return Kind == KindTy::Immediate; }
12081ad6265SDimitry Andric   bool isMem() const override { return false; }
12181ad6265SDimitry Andric   void setReg(MCRegister PhysReg) { Reg.RegNum = PhysReg; }
12281ad6265SDimitry Andric 
12381ad6265SDimitry Andric   static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm) {
12481ad6265SDimitry Andric     if (auto CE = dyn_cast<MCConstantExpr>(Expr)) {
12581ad6265SDimitry Andric       Imm = CE->getValue();
12681ad6265SDimitry Andric       return true;
12781ad6265SDimitry Andric     }
12881ad6265SDimitry Andric 
12981ad6265SDimitry Andric     return false;
13081ad6265SDimitry Andric   }
13181ad6265SDimitry Andric 
13281ad6265SDimitry Andric   template <unsigned N, int P = 0> bool isUImm() const {
13381ad6265SDimitry Andric     if (!isImm())
13481ad6265SDimitry Andric       return false;
13581ad6265SDimitry Andric 
13681ad6265SDimitry Andric     int64_t Imm;
13781ad6265SDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
13881ad6265SDimitry Andric     return IsConstantImm && isUInt<N>(Imm - P);
13981ad6265SDimitry Andric   }
14081ad6265SDimitry Andric 
14181ad6265SDimitry Andric   template <unsigned N, unsigned S = 0> bool isSImm() const {
14281ad6265SDimitry Andric     if (!isImm())
14381ad6265SDimitry Andric       return false;
14481ad6265SDimitry Andric 
14581ad6265SDimitry Andric     int64_t Imm;
14681ad6265SDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
14781ad6265SDimitry Andric     return IsConstantImm && isShiftedInt<N, S>(Imm);
14881ad6265SDimitry Andric   }
14981ad6265SDimitry Andric 
15081ad6265SDimitry Andric   bool isUImm2() const { return isUImm<2>(); }
15181ad6265SDimitry Andric   bool isUImm2plus1() const { return isUImm<2, 1>(); }
15281ad6265SDimitry Andric   bool isUImm3() const { return isUImm<3>(); }
15381ad6265SDimitry Andric   bool isUImm5() const { return isUImm<5>(); }
15481ad6265SDimitry Andric   bool isUImm6() const { return isUImm<6>(); }
15581ad6265SDimitry Andric   bool isUImm8() const { return isUImm<8>(); }
15681ad6265SDimitry Andric   bool isUImm12() const { return isUImm<12>(); }
15781ad6265SDimitry Andric   bool isUImm14() const { return isUImm<14>(); }
15881ad6265SDimitry Andric   bool isUImm15() const { return isUImm<15>(); }
15981ad6265SDimitry Andric   bool isSImm12() const { return isSImm<12>(); }
16081ad6265SDimitry Andric   bool isSImm14lsl2() const { return isSImm<14, 2>(); }
16181ad6265SDimitry Andric   bool isSImm16() const { return isSImm<16>(); }
16281ad6265SDimitry Andric   bool isSImm16lsl2() const { return isSImm<16, 2>(); }
16381ad6265SDimitry Andric   bool isSImm20() const { return isSImm<20>(); }
16481ad6265SDimitry Andric   bool isSImm21lsl2() const { return isSImm<21, 2>(); }
16581ad6265SDimitry Andric   bool isSImm26lsl2() const { return isSImm<26, 2>(); }
16681ad6265SDimitry Andric 
16781ad6265SDimitry Andric   /// Gets location of the first token of this operand.
16881ad6265SDimitry Andric   SMLoc getStartLoc() const override { return StartLoc; }
16981ad6265SDimitry Andric   /// Gets location of the last token of this operand.
17081ad6265SDimitry Andric   SMLoc getEndLoc() const override { return EndLoc; }
17181ad6265SDimitry Andric 
17281ad6265SDimitry Andric   unsigned getReg() const override {
17381ad6265SDimitry Andric     assert(Kind == KindTy::Register && "Invalid type access!");
17481ad6265SDimitry Andric     return Reg.RegNum.id();
17581ad6265SDimitry Andric   }
17681ad6265SDimitry Andric 
17781ad6265SDimitry Andric   const MCExpr *getImm() const {
17881ad6265SDimitry Andric     assert(Kind == KindTy::Immediate && "Invalid type access!");
17981ad6265SDimitry Andric     return Imm.Val;
18081ad6265SDimitry Andric   }
18181ad6265SDimitry Andric 
18281ad6265SDimitry Andric   StringRef getToken() const {
18381ad6265SDimitry Andric     assert(Kind == KindTy::Token && "Invalid type access!");
18481ad6265SDimitry Andric     return Tok;
18581ad6265SDimitry Andric   }
18681ad6265SDimitry Andric 
18781ad6265SDimitry Andric   void print(raw_ostream &OS) const override {
18881ad6265SDimitry Andric     auto RegName = [](unsigned Reg) {
18981ad6265SDimitry Andric       if (Reg)
19081ad6265SDimitry Andric         return LoongArchInstPrinter::getRegisterName(Reg);
19181ad6265SDimitry Andric       else
19281ad6265SDimitry Andric         return "noreg";
19381ad6265SDimitry Andric     };
19481ad6265SDimitry Andric 
19581ad6265SDimitry Andric     switch (Kind) {
19681ad6265SDimitry Andric     case KindTy::Immediate:
19781ad6265SDimitry Andric       OS << *getImm();
19881ad6265SDimitry Andric       break;
19981ad6265SDimitry Andric     case KindTy::Register:
20081ad6265SDimitry Andric       OS << "<register " << RegName(getReg()) << ">";
20181ad6265SDimitry Andric       break;
20281ad6265SDimitry Andric     case KindTy::Token:
20381ad6265SDimitry Andric       OS << "'" << getToken() << "'";
20481ad6265SDimitry Andric       break;
20581ad6265SDimitry Andric     }
20681ad6265SDimitry Andric   }
20781ad6265SDimitry Andric 
20881ad6265SDimitry Andric   static std::unique_ptr<LoongArchOperand> createToken(StringRef Str, SMLoc S) {
20981ad6265SDimitry Andric     auto Op = std::make_unique<LoongArchOperand>(KindTy::Token);
21081ad6265SDimitry Andric     Op->Tok = Str;
21181ad6265SDimitry Andric     Op->StartLoc = S;
21281ad6265SDimitry Andric     Op->EndLoc = S;
21381ad6265SDimitry Andric     return Op;
21481ad6265SDimitry Andric   }
21581ad6265SDimitry Andric 
21681ad6265SDimitry Andric   static std::unique_ptr<LoongArchOperand> createReg(unsigned RegNo, SMLoc S,
21781ad6265SDimitry Andric                                                      SMLoc E) {
21881ad6265SDimitry Andric     auto Op = std::make_unique<LoongArchOperand>(KindTy::Register);
21981ad6265SDimitry Andric     Op->Reg.RegNum = RegNo;
22081ad6265SDimitry Andric     Op->StartLoc = S;
22181ad6265SDimitry Andric     Op->EndLoc = E;
22281ad6265SDimitry Andric     return Op;
22381ad6265SDimitry Andric   }
22481ad6265SDimitry Andric 
22581ad6265SDimitry Andric   static std::unique_ptr<LoongArchOperand> createImm(const MCExpr *Val, SMLoc S,
22681ad6265SDimitry Andric                                                      SMLoc E) {
22781ad6265SDimitry Andric     auto Op = std::make_unique<LoongArchOperand>(KindTy::Immediate);
22881ad6265SDimitry Andric     Op->Imm.Val = Val;
22981ad6265SDimitry Andric     Op->StartLoc = S;
23081ad6265SDimitry Andric     Op->EndLoc = E;
23181ad6265SDimitry Andric     return Op;
23281ad6265SDimitry Andric   }
23381ad6265SDimitry Andric 
23481ad6265SDimitry Andric   void addExpr(MCInst &Inst, const MCExpr *Expr) const {
23581ad6265SDimitry Andric     if (auto CE = dyn_cast<MCConstantExpr>(Expr))
23681ad6265SDimitry Andric       Inst.addOperand(MCOperand::createImm(CE->getValue()));
23781ad6265SDimitry Andric     else
23881ad6265SDimitry Andric       Inst.addOperand(MCOperand::createExpr(Expr));
23981ad6265SDimitry Andric   }
24081ad6265SDimitry Andric 
24181ad6265SDimitry Andric   // Used by the TableGen Code.
24281ad6265SDimitry Andric   void addRegOperands(MCInst &Inst, unsigned N) const {
24381ad6265SDimitry Andric     assert(N == 1 && "Invalid number of operands!");
24481ad6265SDimitry Andric     Inst.addOperand(MCOperand::createReg(getReg()));
24581ad6265SDimitry Andric   }
24681ad6265SDimitry Andric   void addImmOperands(MCInst &Inst, unsigned N) const {
24781ad6265SDimitry Andric     assert(N == 1 && "Invalid number of operands!");
24881ad6265SDimitry Andric     addExpr(Inst, getImm());
24981ad6265SDimitry Andric   }
25081ad6265SDimitry Andric };
251*972a253aSDimitry Andric } // end namespace
25281ad6265SDimitry Andric 
25381ad6265SDimitry Andric #define GET_REGISTER_MATCHER
25481ad6265SDimitry Andric #define GET_SUBTARGET_FEATURE_NAME
25581ad6265SDimitry Andric #define GET_MATCHER_IMPLEMENTATION
25681ad6265SDimitry Andric #define GET_MNEMONIC_SPELL_CHECKER
25781ad6265SDimitry Andric #include "LoongArchGenAsmMatcher.inc"
25881ad6265SDimitry Andric 
25981ad6265SDimitry Andric static MCRegister convertFPR32ToFPR64(MCRegister Reg) {
26081ad6265SDimitry Andric   assert(Reg >= LoongArch::F0 && Reg <= LoongArch::F31 && "Invalid register");
26181ad6265SDimitry Andric   return Reg - LoongArch::F0 + LoongArch::F0_64;
26281ad6265SDimitry Andric }
26381ad6265SDimitry Andric 
26481ad6265SDimitry Andric // Attempts to match Name as a register (either using the default name or
26581ad6265SDimitry Andric // alternative ABI names), setting RegNo to the matching register. Upon
26681ad6265SDimitry Andric // failure, returns true and sets RegNo to 0.
26781ad6265SDimitry Andric static bool matchRegisterNameHelper(MCRegister &RegNo, StringRef Name) {
26881ad6265SDimitry Andric   RegNo = MatchRegisterName(Name);
26981ad6265SDimitry Andric   // The 32-bit and 64-bit FPRs have the same asm name. Check that the initial
27081ad6265SDimitry Andric   // match always matches the 32-bit variant, and not the 64-bit one.
27181ad6265SDimitry Andric   assert(!(RegNo >= LoongArch::F0_64 && RegNo <= LoongArch::F31_64));
27281ad6265SDimitry Andric   // The default FPR register class is based on the tablegen enum ordering.
27381ad6265SDimitry Andric   static_assert(LoongArch::F0 < LoongArch::F0_64,
27481ad6265SDimitry Andric                 "FPR matching must be updated");
27581ad6265SDimitry Andric   if (RegNo == LoongArch::NoRegister)
27681ad6265SDimitry Andric     RegNo = MatchRegisterAltName(Name);
27781ad6265SDimitry Andric 
27881ad6265SDimitry Andric   return RegNo == LoongArch::NoRegister;
27981ad6265SDimitry Andric }
28081ad6265SDimitry Andric 
28181ad6265SDimitry Andric bool LoongArchAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
28281ad6265SDimitry Andric                                        SMLoc &EndLoc) {
28381ad6265SDimitry Andric   return Error(getLoc(), "invalid register number");
28481ad6265SDimitry Andric }
28581ad6265SDimitry Andric 
28681ad6265SDimitry Andric OperandMatchResultTy LoongArchAsmParser::tryParseRegister(unsigned &RegNo,
28781ad6265SDimitry Andric                                                           SMLoc &StartLoc,
28881ad6265SDimitry Andric                                                           SMLoc &EndLoc) {
28981ad6265SDimitry Andric   llvm_unreachable("Unimplemented function.");
29081ad6265SDimitry Andric }
29181ad6265SDimitry Andric 
29281ad6265SDimitry Andric OperandMatchResultTy
29381ad6265SDimitry Andric LoongArchAsmParser::parseRegister(OperandVector &Operands) {
29481ad6265SDimitry Andric   if (getLexer().getTok().isNot(AsmToken::Dollar))
29581ad6265SDimitry Andric     return MatchOperand_NoMatch;
29681ad6265SDimitry Andric 
29781ad6265SDimitry Andric   // Eat the $ prefix.
29881ad6265SDimitry Andric   getLexer().Lex();
29981ad6265SDimitry Andric   if (getLexer().getKind() != AsmToken::Identifier)
30081ad6265SDimitry Andric     return MatchOperand_NoMatch;
30181ad6265SDimitry Andric 
30281ad6265SDimitry Andric   StringRef Name = getLexer().getTok().getIdentifier();
30381ad6265SDimitry Andric   MCRegister RegNo;
30481ad6265SDimitry Andric   matchRegisterNameHelper(RegNo, Name);
30581ad6265SDimitry Andric   if (RegNo == LoongArch::NoRegister)
30681ad6265SDimitry Andric     return MatchOperand_NoMatch;
30781ad6265SDimitry Andric 
30881ad6265SDimitry Andric   SMLoc S = getLoc();
30981ad6265SDimitry Andric   SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size());
31081ad6265SDimitry Andric   getLexer().Lex();
31181ad6265SDimitry Andric   Operands.push_back(LoongArchOperand::createReg(RegNo, S, E));
31281ad6265SDimitry Andric 
31381ad6265SDimitry Andric   return MatchOperand_Success;
31481ad6265SDimitry Andric }
31581ad6265SDimitry Andric 
31681ad6265SDimitry Andric OperandMatchResultTy
31781ad6265SDimitry Andric LoongArchAsmParser::parseImmediate(OperandVector &Operands) {
31881ad6265SDimitry Andric   SMLoc S = getLoc();
31981ad6265SDimitry Andric   SMLoc E;
32081ad6265SDimitry Andric   const MCExpr *Res;
32181ad6265SDimitry Andric 
32281ad6265SDimitry Andric   if (getParser().parseExpression(Res, E))
32381ad6265SDimitry Andric     return MatchOperand_ParseFail;
32481ad6265SDimitry Andric 
32581ad6265SDimitry Andric   Operands.push_back(LoongArchOperand::createImm(Res, S, E));
32681ad6265SDimitry Andric   return MatchOperand_Success;
32781ad6265SDimitry Andric }
32881ad6265SDimitry Andric 
32981ad6265SDimitry Andric /// Looks at a token type and creates the relevant operand from this
33081ad6265SDimitry Andric /// information, adding to Operands. Return true upon an error.
33181ad6265SDimitry Andric bool LoongArchAsmParser::parseOperand(OperandVector &Operands,
33281ad6265SDimitry Andric                                       StringRef Mnemonic) {
33381ad6265SDimitry Andric   if (parseRegister(Operands) == MatchOperand_Success ||
33481ad6265SDimitry Andric       parseImmediate(Operands) == MatchOperand_Success)
33581ad6265SDimitry Andric     return false;
33681ad6265SDimitry Andric 
33781ad6265SDimitry Andric   // Finally we have exhausted all options and must declare defeat.
33881ad6265SDimitry Andric   Error(getLoc(), "unknown operand");
33981ad6265SDimitry Andric   return true;
34081ad6265SDimitry Andric }
34181ad6265SDimitry Andric 
34281ad6265SDimitry Andric bool LoongArchAsmParser::ParseInstruction(ParseInstructionInfo &Info,
34381ad6265SDimitry Andric                                           StringRef Name, SMLoc NameLoc,
34481ad6265SDimitry Andric                                           OperandVector &Operands) {
34581ad6265SDimitry Andric   // First operand in MCInst is instruction mnemonic.
34681ad6265SDimitry Andric   Operands.push_back(LoongArchOperand::createToken(Name, NameLoc));
34781ad6265SDimitry Andric 
34881ad6265SDimitry Andric   // If there are no more operands, then finish.
34981ad6265SDimitry Andric   if (parseOptionalToken(AsmToken::EndOfStatement))
35081ad6265SDimitry Andric     return false;
35181ad6265SDimitry Andric 
35281ad6265SDimitry Andric   // Parse first operand.
35381ad6265SDimitry Andric   if (parseOperand(Operands, Name))
35481ad6265SDimitry Andric     return true;
35581ad6265SDimitry Andric 
35681ad6265SDimitry Andric   // Parse until end of statement, consuming commas between operands.
35781ad6265SDimitry Andric   while (parseOptionalToken(AsmToken::Comma))
35881ad6265SDimitry Andric     if (parseOperand(Operands, Name))
35981ad6265SDimitry Andric       return true;
36081ad6265SDimitry Andric 
36181ad6265SDimitry Andric   // Parse end of statement and return successfully.
36281ad6265SDimitry Andric   if (parseOptionalToken(AsmToken::EndOfStatement))
36381ad6265SDimitry Andric     return false;
36481ad6265SDimitry Andric 
36581ad6265SDimitry Andric   SMLoc Loc = getLexer().getLoc();
36681ad6265SDimitry Andric   getParser().eatToEndOfStatement();
36781ad6265SDimitry Andric   return Error(Loc, "unexpected token");
36881ad6265SDimitry Andric }
36981ad6265SDimitry Andric 
37081ad6265SDimitry Andric bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
37181ad6265SDimitry Andric                                             OperandVector &Operands,
37281ad6265SDimitry Andric                                             MCStreamer &Out) {
37381ad6265SDimitry Andric   Inst.setLoc(IDLoc);
37481ad6265SDimitry Andric   Out.emitInstruction(Inst, getSTI());
37581ad6265SDimitry Andric   return false;
37681ad6265SDimitry Andric }
37781ad6265SDimitry Andric 
37881ad6265SDimitry Andric unsigned LoongArchAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
37981ad6265SDimitry Andric   switch (Inst.getOpcode()) {
38081ad6265SDimitry Andric   default:
38181ad6265SDimitry Andric     break;
38281ad6265SDimitry Andric   case LoongArch::CSRXCHG: {
38381ad6265SDimitry Andric     unsigned Rj = Inst.getOperand(2).getReg();
38481ad6265SDimitry Andric     if (Rj == LoongArch::R0 || Rj == LoongArch::R1)
38581ad6265SDimitry Andric       return Match_RequiresOpnd2NotR0R1;
38681ad6265SDimitry Andric     return Match_Success;
38781ad6265SDimitry Andric   }
38881ad6265SDimitry Andric   case LoongArch::BSTRINS_W:
38981ad6265SDimitry Andric   case LoongArch::BSTRINS_D:
39081ad6265SDimitry Andric   case LoongArch::BSTRPICK_W:
39181ad6265SDimitry Andric   case LoongArch::BSTRPICK_D: {
39281ad6265SDimitry Andric     unsigned Opc = Inst.getOpcode();
39381ad6265SDimitry Andric     const signed Msb =
39481ad6265SDimitry Andric         (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D)
39581ad6265SDimitry Andric             ? Inst.getOperand(3).getImm()
39681ad6265SDimitry Andric             : Inst.getOperand(2).getImm();
39781ad6265SDimitry Andric     const signed Lsb =
39881ad6265SDimitry Andric         (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D)
39981ad6265SDimitry Andric             ? Inst.getOperand(4).getImm()
40081ad6265SDimitry Andric             : Inst.getOperand(3).getImm();
40181ad6265SDimitry Andric     if (Msb < Lsb)
40281ad6265SDimitry Andric       return Match_RequiresMsbNotLessThanLsb;
40381ad6265SDimitry Andric     return Match_Success;
40481ad6265SDimitry Andric   }
40581ad6265SDimitry Andric   }
40681ad6265SDimitry Andric 
40781ad6265SDimitry Andric   return Match_Success;
40881ad6265SDimitry Andric }
40981ad6265SDimitry Andric 
41081ad6265SDimitry Andric unsigned
41181ad6265SDimitry Andric LoongArchAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
41281ad6265SDimitry Andric                                                unsigned Kind) {
41381ad6265SDimitry Andric   LoongArchOperand &Op = static_cast<LoongArchOperand &>(AsmOp);
41481ad6265SDimitry Andric   if (!Op.isReg())
41581ad6265SDimitry Andric     return Match_InvalidOperand;
41681ad6265SDimitry Andric 
41781ad6265SDimitry Andric   MCRegister Reg = Op.getReg();
41881ad6265SDimitry Andric   // As the parser couldn't differentiate an FPR32 from an FPR64, coerce the
41981ad6265SDimitry Andric   // register from FPR32 to FPR64 if necessary.
42081ad6265SDimitry Andric   if (LoongArchMCRegisterClasses[LoongArch::FPR32RegClassID].contains(Reg) &&
42181ad6265SDimitry Andric       Kind == MCK_FPR64) {
42281ad6265SDimitry Andric     Op.setReg(convertFPR32ToFPR64(Reg));
42381ad6265SDimitry Andric     return Match_Success;
42481ad6265SDimitry Andric   }
42581ad6265SDimitry Andric 
42681ad6265SDimitry Andric   return Match_InvalidOperand;
42781ad6265SDimitry Andric }
42881ad6265SDimitry Andric 
42981ad6265SDimitry Andric bool LoongArchAsmParser::generateImmOutOfRangeError(
43081ad6265SDimitry Andric     OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper,
43181ad6265SDimitry Andric     Twine Msg = "immediate must be an integer in the range") {
43281ad6265SDimitry Andric   SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
43381ad6265SDimitry Andric   return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]");
43481ad6265SDimitry Andric }
43581ad6265SDimitry Andric 
43681ad6265SDimitry Andric bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
43781ad6265SDimitry Andric                                                  OperandVector &Operands,
43881ad6265SDimitry Andric                                                  MCStreamer &Out,
43981ad6265SDimitry Andric                                                  uint64_t &ErrorInfo,
44081ad6265SDimitry Andric                                                  bool MatchingInlineAsm) {
44181ad6265SDimitry Andric   MCInst Inst;
44281ad6265SDimitry Andric   FeatureBitset MissingFeatures;
44381ad6265SDimitry Andric 
44481ad6265SDimitry Andric   auto Result = MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
44581ad6265SDimitry Andric                                      MatchingInlineAsm);
44681ad6265SDimitry Andric   switch (Result) {
44781ad6265SDimitry Andric   default:
44881ad6265SDimitry Andric     break;
44981ad6265SDimitry Andric   case Match_Success:
45081ad6265SDimitry Andric     return processInstruction(Inst, IDLoc, Operands, Out);
45181ad6265SDimitry Andric   case Match_MissingFeature: {
45281ad6265SDimitry Andric     assert(MissingFeatures.any() && "Unknown missing features!");
45381ad6265SDimitry Andric     bool FirstFeature = true;
45481ad6265SDimitry Andric     std::string Msg = "instruction requires the following:";
45581ad6265SDimitry Andric     for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
45681ad6265SDimitry Andric       if (MissingFeatures[i]) {
45781ad6265SDimitry Andric         Msg += FirstFeature ? " " : ", ";
45881ad6265SDimitry Andric         Msg += getSubtargetFeatureName(i);
45981ad6265SDimitry Andric         FirstFeature = false;
46081ad6265SDimitry Andric       }
46181ad6265SDimitry Andric     }
46281ad6265SDimitry Andric     return Error(IDLoc, Msg);
46381ad6265SDimitry Andric   }
46481ad6265SDimitry Andric   case Match_MnemonicFail: {
46581ad6265SDimitry Andric     FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
46681ad6265SDimitry Andric     std::string Suggestion = LoongArchMnemonicSpellCheck(
46781ad6265SDimitry Andric         ((LoongArchOperand &)*Operands[0]).getToken(), FBS, 0);
46881ad6265SDimitry Andric     return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion);
46981ad6265SDimitry Andric   }
47081ad6265SDimitry Andric   case Match_InvalidOperand: {
47181ad6265SDimitry Andric     SMLoc ErrorLoc = IDLoc;
47281ad6265SDimitry Andric     if (ErrorInfo != ~0ULL) {
47381ad6265SDimitry Andric       if (ErrorInfo >= Operands.size())
47481ad6265SDimitry Andric         return Error(ErrorLoc, "too few operands for instruction");
47581ad6265SDimitry Andric 
47681ad6265SDimitry Andric       ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
47781ad6265SDimitry Andric       if (ErrorLoc == SMLoc())
47881ad6265SDimitry Andric         ErrorLoc = IDLoc;
47981ad6265SDimitry Andric     }
48081ad6265SDimitry Andric     return Error(ErrorLoc, "invalid operand for instruction");
48181ad6265SDimitry Andric   }
48281ad6265SDimitry Andric   }
48381ad6265SDimitry Andric 
48481ad6265SDimitry Andric   // Handle the case when the error message is of specific type
48581ad6265SDimitry Andric   // other than the generic Match_InvalidOperand, and the
48681ad6265SDimitry Andric   // corresponding operand is missing.
48781ad6265SDimitry Andric   if (Result > FIRST_TARGET_MATCH_RESULT_TY) {
48881ad6265SDimitry Andric     SMLoc ErrorLoc = IDLoc;
48981ad6265SDimitry Andric     if (ErrorInfo != ~0ULL && ErrorInfo >= Operands.size())
49081ad6265SDimitry Andric       return Error(ErrorLoc, "too few operands for instruction");
49181ad6265SDimitry Andric   }
49281ad6265SDimitry Andric 
49381ad6265SDimitry Andric   switch (Result) {
49481ad6265SDimitry Andric   default:
49581ad6265SDimitry Andric     break;
49681ad6265SDimitry Andric   case Match_RequiresMsbNotLessThanLsb: {
49781ad6265SDimitry Andric     SMLoc ErrorStart = Operands[3]->getStartLoc();
49881ad6265SDimitry Andric     return Error(ErrorStart, "msb is less than lsb",
49981ad6265SDimitry Andric                  SMRange(ErrorStart, Operands[4]->getEndLoc()));
50081ad6265SDimitry Andric   }
50181ad6265SDimitry Andric   case Match_RequiresOpnd2NotR0R1:
50281ad6265SDimitry Andric     return Error(Operands[2]->getStartLoc(), "must not be $r0 or $r1");
50381ad6265SDimitry Andric   case Match_InvalidUImm2:
50481ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
50581ad6265SDimitry Andric                                       /*Upper=*/(1 << 2) - 1);
50681ad6265SDimitry Andric   case Match_InvalidUImm2plus1:
50781ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/1,
50881ad6265SDimitry Andric                                       /*Upper=*/(1 << 2));
50981ad6265SDimitry Andric   case Match_InvalidUImm3:
51081ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
51181ad6265SDimitry Andric                                       /*Upper=*/(1 << 3) - 1);
51281ad6265SDimitry Andric   case Match_InvalidUImm5:
51381ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
51481ad6265SDimitry Andric                                       /*Upper=*/(1 << 5) - 1);
51581ad6265SDimitry Andric   case Match_InvalidUImm6:
51681ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
51781ad6265SDimitry Andric                                       /*Upper=*/(1 << 6) - 1);
51881ad6265SDimitry Andric   case Match_InvalidUImm12:
51981ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
52081ad6265SDimitry Andric                                       /*Upper=*/(1 << 12) - 1);
52181ad6265SDimitry Andric   case Match_InvalidUImm15:
52281ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
52381ad6265SDimitry Andric                                       /*Upper=*/(1 << 15) - 1);
52481ad6265SDimitry Andric   case Match_InvalidSImm12:
52581ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 11),
52681ad6265SDimitry Andric                                       /*Upper=*/(1 << 11) - 1);
52781ad6265SDimitry Andric   case Match_InvalidSImm14lsl2:
52881ad6265SDimitry Andric     return generateImmOutOfRangeError(
52981ad6265SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 15), /*Upper=*/(1 << 15) - 4,
53081ad6265SDimitry Andric         "immediate must be a multiple of 4 in the range");
53181ad6265SDimitry Andric   case Match_InvalidSImm16:
53281ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 15),
53381ad6265SDimitry Andric                                       /*Upper=*/(1 << 15) - 1);
53481ad6265SDimitry Andric   case Match_InvalidSImm16lsl2:
53581ad6265SDimitry Andric     return generateImmOutOfRangeError(
53681ad6265SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 17), /*Upper=*/(1 << 17) - 4,
53781ad6265SDimitry Andric         "immediate must be a multiple of 4 in the range");
53881ad6265SDimitry Andric   case Match_InvalidSImm20:
53981ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 19),
54081ad6265SDimitry Andric                                       /*Upper=*/(1 << 19) - 1);
54181ad6265SDimitry Andric   case Match_InvalidSImm21lsl2:
54281ad6265SDimitry Andric     return generateImmOutOfRangeError(
54381ad6265SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4,
54481ad6265SDimitry Andric         "immediate must be a multiple of 4 in the range");
54581ad6265SDimitry Andric   case Match_InvalidSImm26lsl2:
54681ad6265SDimitry Andric     return generateImmOutOfRangeError(
54781ad6265SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4,
54881ad6265SDimitry Andric         "immediate must be a multiple of 4 in the range");
54981ad6265SDimitry Andric   }
55081ad6265SDimitry Andric   llvm_unreachable("Unknown match type detected!");
55181ad6265SDimitry Andric }
55281ad6265SDimitry Andric 
55381ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() {
55481ad6265SDimitry Andric   RegisterMCAsmParser<LoongArchAsmParser> X(getTheLoongArch32Target());
55581ad6265SDimitry Andric   RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target());
55681ad6265SDimitry Andric }
557