xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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"
10*bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchMCExpr.h"
1181ad6265SDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h"
12*bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchMatInt.h"
1381ad6265SDimitry Andric #include "TargetInfo/LoongArchTargetInfo.h"
1481ad6265SDimitry Andric #include "llvm/MC/MCContext.h"
15*bdd1243dSDimitry Andric #include "llvm/MC/MCInstBuilder.h"
1681ad6265SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
1781ad6265SDimitry Andric #include "llvm/MC/MCParser/MCAsmLexer.h"
1881ad6265SDimitry Andric #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
1981ad6265SDimitry Andric #include "llvm/MC/MCParser/MCTargetAsmParser.h"
2081ad6265SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
2181ad6265SDimitry Andric #include "llvm/MC/MCStreamer.h"
2281ad6265SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
23*bdd1243dSDimitry Andric #include "llvm/MC/MCValue.h"
2481ad6265SDimitry Andric #include "llvm/MC/TargetRegistry.h"
2581ad6265SDimitry Andric #include "llvm/Support/Casting.h"
2681ad6265SDimitry Andric 
2781ad6265SDimitry Andric using namespace llvm;
2881ad6265SDimitry Andric 
2981ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-asm-parser"
3081ad6265SDimitry Andric 
3181ad6265SDimitry Andric namespace {
3281ad6265SDimitry Andric class LoongArchAsmParser : public MCTargetAsmParser {
3381ad6265SDimitry Andric   SMLoc getLoc() const { return getParser().getTok().getLoc(); }
34*bdd1243dSDimitry Andric   bool is64Bit() const { return getSTI().hasFeature(LoongArch::Feature64Bit); }
35*bdd1243dSDimitry Andric 
36*bdd1243dSDimitry Andric   struct Inst {
37*bdd1243dSDimitry Andric     unsigned Opc;
38*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK;
39*bdd1243dSDimitry Andric     Inst(unsigned Opc,
40*bdd1243dSDimitry Andric          LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None)
41*bdd1243dSDimitry Andric         : Opc(Opc), VK(VK) {}
42*bdd1243dSDimitry Andric   };
43*bdd1243dSDimitry Andric   using InstSeq = SmallVector<Inst>;
4481ad6265SDimitry Andric 
4581ad6265SDimitry Andric   /// Parse a register as used in CFI directives.
46*bdd1243dSDimitry Andric   bool parseRegister(MCRegister &RegNo, SMLoc &StartLoc,
47*bdd1243dSDimitry Andric                      SMLoc &EndLoc) override;
48*bdd1243dSDimitry Andric   OperandMatchResultTy tryParseRegister(MCRegister &RegNo, SMLoc &StartLoc,
4981ad6265SDimitry Andric                                         SMLoc &EndLoc) override;
5081ad6265SDimitry Andric 
5181ad6265SDimitry Andric   bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
5281ad6265SDimitry Andric                         SMLoc NameLoc, OperandVector &Operands) override;
5381ad6265SDimitry Andric 
5481ad6265SDimitry Andric   bool ParseDirective(AsmToken DirectiveID) override { return true; }
5581ad6265SDimitry Andric 
5681ad6265SDimitry Andric   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
5781ad6265SDimitry Andric                                OperandVector &Operands, MCStreamer &Out,
5881ad6265SDimitry Andric                                uint64_t &ErrorInfo,
5981ad6265SDimitry Andric                                bool MatchingInlineAsm) override;
6081ad6265SDimitry Andric 
6181ad6265SDimitry Andric   unsigned checkTargetMatchPredicate(MCInst &Inst) override;
6281ad6265SDimitry Andric 
6381ad6265SDimitry Andric   unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
6481ad6265SDimitry Andric                                       unsigned Kind) override;
6581ad6265SDimitry Andric 
6681ad6265SDimitry Andric   bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo,
6781ad6265SDimitry Andric                                   int64_t Lower, int64_t Upper, Twine Msg);
6881ad6265SDimitry Andric 
6981ad6265SDimitry Andric   /// Helper for processing MC instructions that have been successfully matched
7081ad6265SDimitry Andric   /// by MatchAndEmitInstruction.
7181ad6265SDimitry Andric   bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands,
7281ad6265SDimitry Andric                           MCStreamer &Out);
7381ad6265SDimitry Andric 
7481ad6265SDimitry Andric // Auto-generated instruction matching functions.
7581ad6265SDimitry Andric #define GET_ASSEMBLER_HEADER
7681ad6265SDimitry Andric #include "LoongArchGenAsmMatcher.inc"
7781ad6265SDimitry Andric 
7881ad6265SDimitry Andric   OperandMatchResultTy parseRegister(OperandVector &Operands);
7981ad6265SDimitry Andric   OperandMatchResultTy parseImmediate(OperandVector &Operands);
80*bdd1243dSDimitry Andric   OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands);
81*bdd1243dSDimitry Andric   OperandMatchResultTy parseSImm26Operand(OperandVector &Operands);
82*bdd1243dSDimitry Andric   OperandMatchResultTy parseAtomicMemOp(OperandVector &Operands);
8381ad6265SDimitry Andric 
8481ad6265SDimitry Andric   bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
8581ad6265SDimitry Andric 
86*bdd1243dSDimitry Andric   // Helper to emit the sequence of instructions generated by the
87*bdd1243dSDimitry Andric   // "emitLoadAddress*" functions.
88*bdd1243dSDimitry Andric   void emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg,
89*bdd1243dSDimitry Andric                      const MCExpr *Symbol, SmallVectorImpl<Inst> &Insts,
90*bdd1243dSDimitry Andric                      SMLoc IDLoc, MCStreamer &Out);
91*bdd1243dSDimitry Andric 
92*bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.abs $rd, sym".
93*bdd1243dSDimitry Andric   void emitLoadAddressAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
94*bdd1243dSDimitry Andric 
95*bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.pcrel $rd, sym".
96*bdd1243dSDimitry Andric   void emitLoadAddressPcrel(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
97*bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.pcrel $rd, $rj, sym".
98*bdd1243dSDimitry Andric   void emitLoadAddressPcrelLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
99*bdd1243dSDimitry Andric 
100*bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.got $rd, sym".
101*bdd1243dSDimitry Andric   void emitLoadAddressGot(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
102*bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.got $rd, $rj, sym".
103*bdd1243dSDimitry Andric   void emitLoadAddressGotLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
104*bdd1243dSDimitry Andric 
105*bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.le $rd, sym".
106*bdd1243dSDimitry Andric   void emitLoadAddressTLSLE(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
107*bdd1243dSDimitry Andric 
108*bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.ie $rd, sym".
109*bdd1243dSDimitry Andric   void emitLoadAddressTLSIE(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
110*bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.ie $rd, $rj, sym".
111*bdd1243dSDimitry Andric   void emitLoadAddressTLSIELarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
112*bdd1243dSDimitry Andric 
113*bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.ld $rd, sym".
114*bdd1243dSDimitry Andric   void emitLoadAddressTLSLD(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
115*bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.ld $rd, $rj, sym".
116*bdd1243dSDimitry Andric   void emitLoadAddressTLSLDLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
117*bdd1243dSDimitry Andric 
118*bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.gd $rd, sym".
119*bdd1243dSDimitry Andric   void emitLoadAddressTLSGD(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
120*bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.gd $rd, $rj, sym".
121*bdd1243dSDimitry Andric   void emitLoadAddressTLSGDLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
122*bdd1243dSDimitry Andric 
123*bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "li.w/d $rd, $imm".
124*bdd1243dSDimitry Andric   void emitLoadImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
125*bdd1243dSDimitry Andric 
12681ad6265SDimitry Andric public:
12781ad6265SDimitry Andric   enum LoongArchMatchResultTy {
12881ad6265SDimitry Andric     Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
12981ad6265SDimitry Andric     Match_RequiresMsbNotLessThanLsb,
13081ad6265SDimitry Andric     Match_RequiresOpnd2NotR0R1,
131*bdd1243dSDimitry Andric     Match_RequiresAMORdDifferRkRj,
132*bdd1243dSDimitry Andric     Match_RequiresLAORdDifferRj,
13381ad6265SDimitry Andric #define GET_OPERAND_DIAGNOSTIC_TYPES
13481ad6265SDimitry Andric #include "LoongArchGenAsmMatcher.inc"
13581ad6265SDimitry Andric #undef GET_OPERAND_DIAGNOSTIC_TYPES
13681ad6265SDimitry Andric   };
13781ad6265SDimitry Andric 
138*bdd1243dSDimitry Andric   static bool classifySymbolRef(const MCExpr *Expr,
139*bdd1243dSDimitry Andric                                 LoongArchMCExpr::VariantKind &Kind);
140*bdd1243dSDimitry Andric 
14181ad6265SDimitry Andric   LoongArchAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
14281ad6265SDimitry Andric                      const MCInstrInfo &MII, const MCTargetOptions &Options)
14381ad6265SDimitry Andric       : MCTargetAsmParser(Options, STI, MII) {
14481ad6265SDimitry Andric     Parser.addAliasForDirective(".half", ".2byte");
14581ad6265SDimitry Andric     Parser.addAliasForDirective(".hword", ".2byte");
14681ad6265SDimitry Andric     Parser.addAliasForDirective(".word", ".4byte");
14781ad6265SDimitry Andric     Parser.addAliasForDirective(".dword", ".8byte");
14881ad6265SDimitry Andric 
14981ad6265SDimitry Andric     // Initialize the set of available features.
15081ad6265SDimitry Andric     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
15181ad6265SDimitry Andric   }
15281ad6265SDimitry Andric };
15381ad6265SDimitry Andric 
15481ad6265SDimitry Andric // Instances of this class represent a parsed LoongArch machine instruction.
15581ad6265SDimitry Andric class LoongArchOperand : public MCParsedAsmOperand {
15681ad6265SDimitry Andric   enum class KindTy {
15781ad6265SDimitry Andric     Token,
15881ad6265SDimitry Andric     Register,
15981ad6265SDimitry Andric     Immediate,
16081ad6265SDimitry Andric   } Kind;
16181ad6265SDimitry Andric 
16281ad6265SDimitry Andric   struct RegOp {
16381ad6265SDimitry Andric     MCRegister RegNum;
16481ad6265SDimitry Andric   };
16581ad6265SDimitry Andric 
16681ad6265SDimitry Andric   struct ImmOp {
16781ad6265SDimitry Andric     const MCExpr *Val;
16881ad6265SDimitry Andric   };
16981ad6265SDimitry Andric 
17081ad6265SDimitry Andric   SMLoc StartLoc, EndLoc;
17181ad6265SDimitry Andric   union {
17281ad6265SDimitry Andric     StringRef Tok;
17381ad6265SDimitry Andric     struct RegOp Reg;
17481ad6265SDimitry Andric     struct ImmOp Imm;
17581ad6265SDimitry Andric   };
17681ad6265SDimitry Andric 
17781ad6265SDimitry Andric public:
17881ad6265SDimitry Andric   LoongArchOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
17981ad6265SDimitry Andric 
18081ad6265SDimitry Andric   bool isToken() const override { return Kind == KindTy::Token; }
18181ad6265SDimitry Andric   bool isReg() const override { return Kind == KindTy::Register; }
18281ad6265SDimitry Andric   bool isImm() const override { return Kind == KindTy::Immediate; }
18381ad6265SDimitry Andric   bool isMem() const override { return false; }
18481ad6265SDimitry Andric   void setReg(MCRegister PhysReg) { Reg.RegNum = PhysReg; }
185*bdd1243dSDimitry Andric   bool isGPR() const {
186*bdd1243dSDimitry Andric     return Kind == KindTy::Register &&
187*bdd1243dSDimitry Andric            LoongArchMCRegisterClasses[LoongArch::GPRRegClassID].contains(
188*bdd1243dSDimitry Andric                Reg.RegNum);
189*bdd1243dSDimitry Andric   }
19081ad6265SDimitry Andric 
191*bdd1243dSDimitry Andric   static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm,
192*bdd1243dSDimitry Andric                                   LoongArchMCExpr::VariantKind &VK) {
193*bdd1243dSDimitry Andric     if (auto *LE = dyn_cast<LoongArchMCExpr>(Expr)) {
194*bdd1243dSDimitry Andric       VK = LE->getKind();
195*bdd1243dSDimitry Andric       return false;
196*bdd1243dSDimitry Andric     }
197*bdd1243dSDimitry Andric 
19881ad6265SDimitry Andric     if (auto CE = dyn_cast<MCConstantExpr>(Expr)) {
19981ad6265SDimitry Andric       Imm = CE->getValue();
20081ad6265SDimitry Andric       return true;
20181ad6265SDimitry Andric     }
20281ad6265SDimitry Andric 
20381ad6265SDimitry Andric     return false;
20481ad6265SDimitry Andric   }
20581ad6265SDimitry Andric 
20681ad6265SDimitry Andric   template <unsigned N, int P = 0> bool isUImm() const {
20781ad6265SDimitry Andric     if (!isImm())
20881ad6265SDimitry Andric       return false;
20981ad6265SDimitry Andric 
21081ad6265SDimitry Andric     int64_t Imm;
211*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
212*bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
213*bdd1243dSDimitry Andric     return IsConstantImm && isUInt<N>(Imm - P) &&
214*bdd1243dSDimitry Andric            VK == LoongArchMCExpr::VK_LoongArch_None;
21581ad6265SDimitry Andric   }
21681ad6265SDimitry Andric 
21781ad6265SDimitry Andric   template <unsigned N, unsigned S = 0> bool isSImm() const {
21881ad6265SDimitry Andric     if (!isImm())
21981ad6265SDimitry Andric       return false;
22081ad6265SDimitry Andric 
22181ad6265SDimitry Andric     int64_t Imm;
222*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
223*bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
224*bdd1243dSDimitry Andric     return IsConstantImm && isShiftedInt<N, S>(Imm) &&
225*bdd1243dSDimitry Andric            VK == LoongArchMCExpr::VK_LoongArch_None;
226*bdd1243dSDimitry Andric   }
227*bdd1243dSDimitry Andric 
228*bdd1243dSDimitry Andric   bool isBareSymbol() const {
229*bdd1243dSDimitry Andric     int64_t Imm;
230*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
231*bdd1243dSDimitry Andric     // Must be of 'immediate' type but not a constant.
232*bdd1243dSDimitry Andric     if (!isImm() || evaluateConstantImm(getImm(), Imm, VK))
233*bdd1243dSDimitry Andric       return false;
234*bdd1243dSDimitry Andric     return LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
235*bdd1243dSDimitry Andric            VK == LoongArchMCExpr::VK_LoongArch_None;
23681ad6265SDimitry Andric   }
23781ad6265SDimitry Andric 
23881ad6265SDimitry Andric   bool isUImm2() const { return isUImm<2>(); }
23981ad6265SDimitry Andric   bool isUImm2plus1() const { return isUImm<2, 1>(); }
24081ad6265SDimitry Andric   bool isUImm3() const { return isUImm<3>(); }
24181ad6265SDimitry Andric   bool isUImm5() const { return isUImm<5>(); }
24281ad6265SDimitry Andric   bool isUImm6() const { return isUImm<6>(); }
24381ad6265SDimitry Andric   bool isUImm8() const { return isUImm<8>(); }
244*bdd1243dSDimitry Andric   bool isSImm12() const { return isSImm<12>(); }
245*bdd1243dSDimitry Andric 
246*bdd1243dSDimitry Andric   bool isSImm12addlike() const {
247*bdd1243dSDimitry Andric     if (!isImm())
248*bdd1243dSDimitry Andric       return false;
249*bdd1243dSDimitry Andric 
250*bdd1243dSDimitry Andric     int64_t Imm;
251*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
252*bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
253*bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
254*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12 ||
255*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12 ||
256*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12;
257*bdd1243dSDimitry Andric     return IsConstantImm
258*bdd1243dSDimitry Andric                ? isInt<12>(Imm) && IsValidKind
259*bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
260*bdd1243dSDimitry Andric                      IsValidKind;
261*bdd1243dSDimitry Andric   }
262*bdd1243dSDimitry Andric 
263*bdd1243dSDimitry Andric   bool isSImm12lu52id() const {
264*bdd1243dSDimitry Andric     if (!isImm())
265*bdd1243dSDimitry Andric       return false;
266*bdd1243dSDimitry Andric 
267*bdd1243dSDimitry Andric     int64_t Imm;
268*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
269*bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
270*bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
271*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_ABS64_HI12 ||
272*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_PCALA64_HI12 ||
273*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT64_HI12 ||
274*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12 ||
275*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_LE64_HI12 ||
276*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_HI12 ||
277*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_HI12;
278*bdd1243dSDimitry Andric     return IsConstantImm
279*bdd1243dSDimitry Andric                ? isInt<12>(Imm) && IsValidKind
280*bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
281*bdd1243dSDimitry Andric                      IsValidKind;
282*bdd1243dSDimitry Andric   }
283*bdd1243dSDimitry Andric 
28481ad6265SDimitry Andric   bool isUImm12() const { return isUImm<12>(); }
285*bdd1243dSDimitry Andric 
286*bdd1243dSDimitry Andric   bool isUImm12ori() const {
287*bdd1243dSDimitry Andric     if (!isImm())
288*bdd1243dSDimitry Andric       return false;
289*bdd1243dSDimitry Andric 
290*bdd1243dSDimitry Andric     int64_t Imm;
291*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
292*bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
293*bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
294*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_ABS_LO12 ||
295*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12 ||
296*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT_LO12 ||
297*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12 ||
298*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_LO12 ||
299*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_LO12 ||
300*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12;
301*bdd1243dSDimitry Andric     return IsConstantImm
302*bdd1243dSDimitry Andric                ? isUInt<12>(Imm) && IsValidKind
303*bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
304*bdd1243dSDimitry Andric                      IsValidKind;
305*bdd1243dSDimitry Andric   }
306*bdd1243dSDimitry Andric 
30781ad6265SDimitry Andric   bool isUImm14() const { return isUImm<14>(); }
30881ad6265SDimitry Andric   bool isUImm15() const { return isUImm<15>(); }
309*bdd1243dSDimitry Andric 
31081ad6265SDimitry Andric   bool isSImm14lsl2() const { return isSImm<14, 2>(); }
31181ad6265SDimitry Andric   bool isSImm16() const { return isSImm<16>(); }
312*bdd1243dSDimitry Andric 
313*bdd1243dSDimitry Andric   bool isSImm16lsl2() const {
314*bdd1243dSDimitry Andric     if (!isImm())
315*bdd1243dSDimitry Andric       return false;
316*bdd1243dSDimitry Andric 
317*bdd1243dSDimitry Andric     int64_t Imm;
318*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
319*bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
320*bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
321*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_B16 ||
322*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12;
323*bdd1243dSDimitry Andric     return IsConstantImm
324*bdd1243dSDimitry Andric                ? isShiftedInt<16, 2>(Imm) && IsValidKind
325*bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
326*bdd1243dSDimitry Andric                      IsValidKind;
327*bdd1243dSDimitry Andric   }
328*bdd1243dSDimitry Andric 
32981ad6265SDimitry Andric   bool isSImm20() const { return isSImm<20>(); }
330*bdd1243dSDimitry Andric 
331*bdd1243dSDimitry Andric   bool isSImm20pcalau12i() const {
332*bdd1243dSDimitry Andric     if (!isImm())
333*bdd1243dSDimitry Andric       return false;
334*bdd1243dSDimitry Andric 
335*bdd1243dSDimitry Andric     int64_t Imm;
336*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
337*bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
338*bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
339*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_PCALA_HI20 ||
340*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20 ||
341*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20 ||
342*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20 ||
343*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20;
344*bdd1243dSDimitry Andric     return IsConstantImm
345*bdd1243dSDimitry Andric                ? isInt<20>(Imm) && IsValidKind
346*bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
347*bdd1243dSDimitry Andric                      IsValidKind;
348*bdd1243dSDimitry Andric   }
349*bdd1243dSDimitry Andric 
350*bdd1243dSDimitry Andric   bool isSImm20lu12iw() const {
351*bdd1243dSDimitry Andric     if (!isImm())
352*bdd1243dSDimitry Andric       return false;
353*bdd1243dSDimitry Andric 
354*bdd1243dSDimitry Andric     int64_t Imm;
355*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
356*bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
357*bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
358*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_ABS_HI20 ||
359*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT_HI20 ||
360*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_GD_HI20 ||
361*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_LD_HI20 ||
362*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_HI20 ||
363*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_HI20;
364*bdd1243dSDimitry Andric     return IsConstantImm
365*bdd1243dSDimitry Andric                ? isInt<20>(Imm) && IsValidKind
366*bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
367*bdd1243dSDimitry Andric                      IsValidKind;
368*bdd1243dSDimitry Andric   }
369*bdd1243dSDimitry Andric 
370*bdd1243dSDimitry Andric   bool isSImm20lu32id() const {
371*bdd1243dSDimitry Andric     if (!isImm())
372*bdd1243dSDimitry Andric       return false;
373*bdd1243dSDimitry Andric 
374*bdd1243dSDimitry Andric     int64_t Imm;
375*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
376*bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
377*bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
378*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_ABS64_LO20 ||
379*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_PCALA64_LO20 ||
380*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT64_LO20 ||
381*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20 ||
382*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_LO20 ||
383*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_LO20 ||
384*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_LE64_LO20;
385*bdd1243dSDimitry Andric 
386*bdd1243dSDimitry Andric     return IsConstantImm
387*bdd1243dSDimitry Andric                ? isInt<20>(Imm) && IsValidKind
388*bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
389*bdd1243dSDimitry Andric                      IsValidKind;
390*bdd1243dSDimitry Andric   }
391*bdd1243dSDimitry Andric 
392*bdd1243dSDimitry Andric   bool isSImm21lsl2() const {
393*bdd1243dSDimitry Andric     if (!isImm())
394*bdd1243dSDimitry Andric       return false;
395*bdd1243dSDimitry Andric 
396*bdd1243dSDimitry Andric     int64_t Imm;
397*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
398*bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
399*bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
400*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_B21;
401*bdd1243dSDimitry Andric     return IsConstantImm
402*bdd1243dSDimitry Andric                ? isShiftedInt<21, 2>(Imm) && IsValidKind
403*bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
404*bdd1243dSDimitry Andric                      IsValidKind;
405*bdd1243dSDimitry Andric   }
406*bdd1243dSDimitry Andric 
407*bdd1243dSDimitry Andric   bool isSImm26Operand() const {
408*bdd1243dSDimitry Andric     if (!isImm())
409*bdd1243dSDimitry Andric       return false;
410*bdd1243dSDimitry Andric 
411*bdd1243dSDimitry Andric     int64_t Imm;
412*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
413*bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
414*bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
415*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_CALL ||
416*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_CALL_PLT ||
417*bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_B26;
418*bdd1243dSDimitry Andric     return IsConstantImm
419*bdd1243dSDimitry Andric                ? isShiftedInt<26, 2>(Imm) && IsValidKind
420*bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
421*bdd1243dSDimitry Andric                      IsValidKind;
422*bdd1243dSDimitry Andric   }
423*bdd1243dSDimitry Andric 
424*bdd1243dSDimitry Andric   bool isImm32() const { return isSImm<32>() || isUImm<32>(); }
42581ad6265SDimitry Andric 
42681ad6265SDimitry Andric   /// Gets location of the first token of this operand.
42781ad6265SDimitry Andric   SMLoc getStartLoc() const override { return StartLoc; }
42881ad6265SDimitry Andric   /// Gets location of the last token of this operand.
42981ad6265SDimitry Andric   SMLoc getEndLoc() const override { return EndLoc; }
43081ad6265SDimitry Andric 
43181ad6265SDimitry Andric   unsigned getReg() const override {
43281ad6265SDimitry Andric     assert(Kind == KindTy::Register && "Invalid type access!");
43381ad6265SDimitry Andric     return Reg.RegNum.id();
43481ad6265SDimitry Andric   }
43581ad6265SDimitry Andric 
43681ad6265SDimitry Andric   const MCExpr *getImm() const {
43781ad6265SDimitry Andric     assert(Kind == KindTy::Immediate && "Invalid type access!");
43881ad6265SDimitry Andric     return Imm.Val;
43981ad6265SDimitry Andric   }
44081ad6265SDimitry Andric 
44181ad6265SDimitry Andric   StringRef getToken() const {
44281ad6265SDimitry Andric     assert(Kind == KindTy::Token && "Invalid type access!");
44381ad6265SDimitry Andric     return Tok;
44481ad6265SDimitry Andric   }
44581ad6265SDimitry Andric 
44681ad6265SDimitry Andric   void print(raw_ostream &OS) const override {
447*bdd1243dSDimitry Andric     auto RegName = [](MCRegister Reg) {
44881ad6265SDimitry Andric       if (Reg)
44981ad6265SDimitry Andric         return LoongArchInstPrinter::getRegisterName(Reg);
45081ad6265SDimitry Andric       else
45181ad6265SDimitry Andric         return "noreg";
45281ad6265SDimitry Andric     };
45381ad6265SDimitry Andric 
45481ad6265SDimitry Andric     switch (Kind) {
45581ad6265SDimitry Andric     case KindTy::Immediate:
45681ad6265SDimitry Andric       OS << *getImm();
45781ad6265SDimitry Andric       break;
45881ad6265SDimitry Andric     case KindTy::Register:
45981ad6265SDimitry Andric       OS << "<register " << RegName(getReg()) << ">";
46081ad6265SDimitry Andric       break;
46181ad6265SDimitry Andric     case KindTy::Token:
46281ad6265SDimitry Andric       OS << "'" << getToken() << "'";
46381ad6265SDimitry Andric       break;
46481ad6265SDimitry Andric     }
46581ad6265SDimitry Andric   }
46681ad6265SDimitry Andric 
46781ad6265SDimitry Andric   static std::unique_ptr<LoongArchOperand> createToken(StringRef Str, SMLoc S) {
46881ad6265SDimitry Andric     auto Op = std::make_unique<LoongArchOperand>(KindTy::Token);
46981ad6265SDimitry Andric     Op->Tok = Str;
47081ad6265SDimitry Andric     Op->StartLoc = S;
47181ad6265SDimitry Andric     Op->EndLoc = S;
47281ad6265SDimitry Andric     return Op;
47381ad6265SDimitry Andric   }
47481ad6265SDimitry Andric 
47581ad6265SDimitry Andric   static std::unique_ptr<LoongArchOperand> createReg(unsigned RegNo, SMLoc S,
47681ad6265SDimitry Andric                                                      SMLoc E) {
47781ad6265SDimitry Andric     auto Op = std::make_unique<LoongArchOperand>(KindTy::Register);
47881ad6265SDimitry Andric     Op->Reg.RegNum = RegNo;
47981ad6265SDimitry Andric     Op->StartLoc = S;
48081ad6265SDimitry Andric     Op->EndLoc = E;
48181ad6265SDimitry Andric     return Op;
48281ad6265SDimitry Andric   }
48381ad6265SDimitry Andric 
48481ad6265SDimitry Andric   static std::unique_ptr<LoongArchOperand> createImm(const MCExpr *Val, SMLoc S,
48581ad6265SDimitry Andric                                                      SMLoc E) {
48681ad6265SDimitry Andric     auto Op = std::make_unique<LoongArchOperand>(KindTy::Immediate);
48781ad6265SDimitry Andric     Op->Imm.Val = Val;
48881ad6265SDimitry Andric     Op->StartLoc = S;
48981ad6265SDimitry Andric     Op->EndLoc = E;
49081ad6265SDimitry Andric     return Op;
49181ad6265SDimitry Andric   }
49281ad6265SDimitry Andric 
49381ad6265SDimitry Andric   void addExpr(MCInst &Inst, const MCExpr *Expr) const {
49481ad6265SDimitry Andric     if (auto CE = dyn_cast<MCConstantExpr>(Expr))
49581ad6265SDimitry Andric       Inst.addOperand(MCOperand::createImm(CE->getValue()));
49681ad6265SDimitry Andric     else
49781ad6265SDimitry Andric       Inst.addOperand(MCOperand::createExpr(Expr));
49881ad6265SDimitry Andric   }
49981ad6265SDimitry Andric 
50081ad6265SDimitry Andric   // Used by the TableGen Code.
50181ad6265SDimitry Andric   void addRegOperands(MCInst &Inst, unsigned N) const {
50281ad6265SDimitry Andric     assert(N == 1 && "Invalid number of operands!");
50381ad6265SDimitry Andric     Inst.addOperand(MCOperand::createReg(getReg()));
50481ad6265SDimitry Andric   }
50581ad6265SDimitry Andric   void addImmOperands(MCInst &Inst, unsigned N) const {
50681ad6265SDimitry Andric     assert(N == 1 && "Invalid number of operands!");
50781ad6265SDimitry Andric     addExpr(Inst, getImm());
50881ad6265SDimitry Andric   }
50981ad6265SDimitry Andric };
510972a253aSDimitry Andric } // end namespace
51181ad6265SDimitry Andric 
51281ad6265SDimitry Andric #define GET_REGISTER_MATCHER
51381ad6265SDimitry Andric #define GET_SUBTARGET_FEATURE_NAME
51481ad6265SDimitry Andric #define GET_MATCHER_IMPLEMENTATION
51581ad6265SDimitry Andric #define GET_MNEMONIC_SPELL_CHECKER
51681ad6265SDimitry Andric #include "LoongArchGenAsmMatcher.inc"
51781ad6265SDimitry Andric 
51881ad6265SDimitry Andric static MCRegister convertFPR32ToFPR64(MCRegister Reg) {
51981ad6265SDimitry Andric   assert(Reg >= LoongArch::F0 && Reg <= LoongArch::F31 && "Invalid register");
52081ad6265SDimitry Andric   return Reg - LoongArch::F0 + LoongArch::F0_64;
52181ad6265SDimitry Andric }
52281ad6265SDimitry Andric 
52381ad6265SDimitry Andric // Attempts to match Name as a register (either using the default name or
52481ad6265SDimitry Andric // alternative ABI names), setting RegNo to the matching register. Upon
52581ad6265SDimitry Andric // failure, returns true and sets RegNo to 0.
52681ad6265SDimitry Andric static bool matchRegisterNameHelper(MCRegister &RegNo, StringRef Name) {
52781ad6265SDimitry Andric   RegNo = MatchRegisterName(Name);
52881ad6265SDimitry Andric   // The 32-bit and 64-bit FPRs have the same asm name. Check that the initial
52981ad6265SDimitry Andric   // match always matches the 32-bit variant, and not the 64-bit one.
53081ad6265SDimitry Andric   assert(!(RegNo >= LoongArch::F0_64 && RegNo <= LoongArch::F31_64));
53181ad6265SDimitry Andric   // The default FPR register class is based on the tablegen enum ordering.
53281ad6265SDimitry Andric   static_assert(LoongArch::F0 < LoongArch::F0_64,
53381ad6265SDimitry Andric                 "FPR matching must be updated");
53481ad6265SDimitry Andric   if (RegNo == LoongArch::NoRegister)
53581ad6265SDimitry Andric     RegNo = MatchRegisterAltName(Name);
53681ad6265SDimitry Andric 
53781ad6265SDimitry Andric   return RegNo == LoongArch::NoRegister;
53881ad6265SDimitry Andric }
53981ad6265SDimitry Andric 
540*bdd1243dSDimitry Andric bool LoongArchAsmParser::parseRegister(MCRegister &RegNo, SMLoc &StartLoc,
54181ad6265SDimitry Andric                                        SMLoc &EndLoc) {
54281ad6265SDimitry Andric   return Error(getLoc(), "invalid register number");
54381ad6265SDimitry Andric }
54481ad6265SDimitry Andric 
545*bdd1243dSDimitry Andric OperandMatchResultTy LoongArchAsmParser::tryParseRegister(MCRegister &RegNo,
54681ad6265SDimitry Andric                                                           SMLoc &StartLoc,
54781ad6265SDimitry Andric                                                           SMLoc &EndLoc) {
54881ad6265SDimitry Andric   llvm_unreachable("Unimplemented function.");
54981ad6265SDimitry Andric }
55081ad6265SDimitry Andric 
551*bdd1243dSDimitry Andric bool LoongArchAsmParser::classifySymbolRef(const MCExpr *Expr,
552*bdd1243dSDimitry Andric                                            LoongArchMCExpr::VariantKind &Kind) {
553*bdd1243dSDimitry Andric   Kind = LoongArchMCExpr::VK_LoongArch_None;
554*bdd1243dSDimitry Andric 
555*bdd1243dSDimitry Andric   if (const LoongArchMCExpr *RE = dyn_cast<LoongArchMCExpr>(Expr)) {
556*bdd1243dSDimitry Andric     Kind = RE->getKind();
557*bdd1243dSDimitry Andric     Expr = RE->getSubExpr();
558*bdd1243dSDimitry Andric   }
559*bdd1243dSDimitry Andric 
560*bdd1243dSDimitry Andric   MCValue Res;
561*bdd1243dSDimitry Andric   if (Expr->evaluateAsRelocatable(Res, nullptr, nullptr))
562*bdd1243dSDimitry Andric     return Res.getRefKind() == LoongArchMCExpr::VK_LoongArch_None;
563*bdd1243dSDimitry Andric   return false;
564*bdd1243dSDimitry Andric }
565*bdd1243dSDimitry Andric 
56681ad6265SDimitry Andric OperandMatchResultTy
56781ad6265SDimitry Andric LoongArchAsmParser::parseRegister(OperandVector &Operands) {
56881ad6265SDimitry Andric   if (getLexer().getTok().isNot(AsmToken::Dollar))
56981ad6265SDimitry Andric     return MatchOperand_NoMatch;
57081ad6265SDimitry Andric 
57181ad6265SDimitry Andric   // Eat the $ prefix.
57281ad6265SDimitry Andric   getLexer().Lex();
57381ad6265SDimitry Andric   if (getLexer().getKind() != AsmToken::Identifier)
57481ad6265SDimitry Andric     return MatchOperand_NoMatch;
57581ad6265SDimitry Andric 
57681ad6265SDimitry Andric   StringRef Name = getLexer().getTok().getIdentifier();
57781ad6265SDimitry Andric   MCRegister RegNo;
57881ad6265SDimitry Andric   matchRegisterNameHelper(RegNo, Name);
57981ad6265SDimitry Andric   if (RegNo == LoongArch::NoRegister)
58081ad6265SDimitry Andric     return MatchOperand_NoMatch;
58181ad6265SDimitry Andric 
58281ad6265SDimitry Andric   SMLoc S = getLoc();
58381ad6265SDimitry Andric   SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size());
58481ad6265SDimitry Andric   getLexer().Lex();
58581ad6265SDimitry Andric   Operands.push_back(LoongArchOperand::createReg(RegNo, S, E));
58681ad6265SDimitry Andric 
58781ad6265SDimitry Andric   return MatchOperand_Success;
58881ad6265SDimitry Andric }
58981ad6265SDimitry Andric 
59081ad6265SDimitry Andric OperandMatchResultTy
59181ad6265SDimitry Andric LoongArchAsmParser::parseImmediate(OperandVector &Operands) {
59281ad6265SDimitry Andric   SMLoc S = getLoc();
59381ad6265SDimitry Andric   SMLoc E;
59481ad6265SDimitry Andric   const MCExpr *Res;
59581ad6265SDimitry Andric 
596*bdd1243dSDimitry Andric   switch (getLexer().getKind()) {
597*bdd1243dSDimitry Andric   default:
598*bdd1243dSDimitry Andric     return MatchOperand_NoMatch;
599*bdd1243dSDimitry Andric   case AsmToken::LParen:
600*bdd1243dSDimitry Andric   case AsmToken::Dot:
601*bdd1243dSDimitry Andric   case AsmToken::Minus:
602*bdd1243dSDimitry Andric   case AsmToken::Plus:
603*bdd1243dSDimitry Andric   case AsmToken::Exclaim:
604*bdd1243dSDimitry Andric   case AsmToken::Tilde:
605*bdd1243dSDimitry Andric   case AsmToken::Integer:
606*bdd1243dSDimitry Andric   case AsmToken::String:
607*bdd1243dSDimitry Andric   case AsmToken::Identifier:
60881ad6265SDimitry Andric     if (getParser().parseExpression(Res, E))
60981ad6265SDimitry Andric       return MatchOperand_ParseFail;
610*bdd1243dSDimitry Andric     break;
611*bdd1243dSDimitry Andric   case AsmToken::Percent:
612*bdd1243dSDimitry Andric     return parseOperandWithModifier(Operands);
613*bdd1243dSDimitry Andric   }
61481ad6265SDimitry Andric 
61581ad6265SDimitry Andric   Operands.push_back(LoongArchOperand::createImm(Res, S, E));
61681ad6265SDimitry Andric   return MatchOperand_Success;
61781ad6265SDimitry Andric }
61881ad6265SDimitry Andric 
619*bdd1243dSDimitry Andric OperandMatchResultTy
620*bdd1243dSDimitry Andric LoongArchAsmParser::parseOperandWithModifier(OperandVector &Operands) {
621*bdd1243dSDimitry Andric   SMLoc S = getLoc();
622*bdd1243dSDimitry Andric   SMLoc E;
623*bdd1243dSDimitry Andric 
624*bdd1243dSDimitry Andric   if (getLexer().getKind() != AsmToken::Percent) {
625*bdd1243dSDimitry Andric     Error(getLoc(), "expected '%' for operand modifier");
626*bdd1243dSDimitry Andric     return MatchOperand_ParseFail;
627*bdd1243dSDimitry Andric   }
628*bdd1243dSDimitry Andric 
629*bdd1243dSDimitry Andric   getParser().Lex(); // Eat '%'
630*bdd1243dSDimitry Andric 
631*bdd1243dSDimitry Andric   if (getLexer().getKind() != AsmToken::Identifier) {
632*bdd1243dSDimitry Andric     Error(getLoc(), "expected valid identifier for operand modifier");
633*bdd1243dSDimitry Andric     return MatchOperand_ParseFail;
634*bdd1243dSDimitry Andric   }
635*bdd1243dSDimitry Andric   StringRef Identifier = getParser().getTok().getIdentifier();
636*bdd1243dSDimitry Andric   LoongArchMCExpr::VariantKind VK =
637*bdd1243dSDimitry Andric       LoongArchMCExpr::getVariantKindForName(Identifier);
638*bdd1243dSDimitry Andric   if (VK == LoongArchMCExpr::VK_LoongArch_Invalid) {
639*bdd1243dSDimitry Andric     Error(getLoc(), "unrecognized operand modifier");
640*bdd1243dSDimitry Andric     return MatchOperand_ParseFail;
641*bdd1243dSDimitry Andric   }
642*bdd1243dSDimitry Andric 
643*bdd1243dSDimitry Andric   getParser().Lex(); // Eat the identifier
644*bdd1243dSDimitry Andric   if (getLexer().getKind() != AsmToken::LParen) {
645*bdd1243dSDimitry Andric     Error(getLoc(), "expected '('");
646*bdd1243dSDimitry Andric     return MatchOperand_ParseFail;
647*bdd1243dSDimitry Andric   }
648*bdd1243dSDimitry Andric   getParser().Lex(); // Eat '('
649*bdd1243dSDimitry Andric 
650*bdd1243dSDimitry Andric   const MCExpr *SubExpr;
651*bdd1243dSDimitry Andric   if (getParser().parseParenExpression(SubExpr, E)) {
652*bdd1243dSDimitry Andric     return MatchOperand_ParseFail;
653*bdd1243dSDimitry Andric   }
654*bdd1243dSDimitry Andric 
655*bdd1243dSDimitry Andric   const MCExpr *ModExpr = LoongArchMCExpr::create(SubExpr, VK, getContext());
656*bdd1243dSDimitry Andric   Operands.push_back(LoongArchOperand::createImm(ModExpr, S, E));
657*bdd1243dSDimitry Andric   return MatchOperand_Success;
658*bdd1243dSDimitry Andric }
659*bdd1243dSDimitry Andric 
660*bdd1243dSDimitry Andric OperandMatchResultTy
661*bdd1243dSDimitry Andric LoongArchAsmParser::parseSImm26Operand(OperandVector &Operands) {
662*bdd1243dSDimitry Andric   SMLoc S = getLoc();
663*bdd1243dSDimitry Andric   const MCExpr *Res;
664*bdd1243dSDimitry Andric 
665*bdd1243dSDimitry Andric   if (getLexer().getKind() == AsmToken::Percent)
666*bdd1243dSDimitry Andric     return parseOperandWithModifier(Operands);
667*bdd1243dSDimitry Andric 
668*bdd1243dSDimitry Andric   if (getLexer().getKind() != AsmToken::Identifier)
669*bdd1243dSDimitry Andric     return MatchOperand_NoMatch;
670*bdd1243dSDimitry Andric 
671*bdd1243dSDimitry Andric   StringRef Identifier;
672*bdd1243dSDimitry Andric   if (getParser().parseIdentifier(Identifier))
673*bdd1243dSDimitry Andric     return MatchOperand_ParseFail;
674*bdd1243dSDimitry Andric 
675*bdd1243dSDimitry Andric   SMLoc E = SMLoc::getFromPointer(S.getPointer() + Identifier.size());
676*bdd1243dSDimitry Andric 
677*bdd1243dSDimitry Andric   MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
678*bdd1243dSDimitry Andric   Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
679*bdd1243dSDimitry Andric   Res = LoongArchMCExpr::create(Res, LoongArchMCExpr::VK_LoongArch_CALL,
680*bdd1243dSDimitry Andric                                 getContext());
681*bdd1243dSDimitry Andric   Operands.push_back(LoongArchOperand::createImm(Res, S, E));
682*bdd1243dSDimitry Andric   return MatchOperand_Success;
683*bdd1243dSDimitry Andric }
684*bdd1243dSDimitry Andric 
685*bdd1243dSDimitry Andric OperandMatchResultTy
686*bdd1243dSDimitry Andric LoongArchAsmParser::parseAtomicMemOp(OperandVector &Operands) {
687*bdd1243dSDimitry Andric   // Parse "$r*".
688*bdd1243dSDimitry Andric   if (parseRegister(Operands) != MatchOperand_Success)
689*bdd1243dSDimitry Andric     return MatchOperand_NoMatch;
690*bdd1243dSDimitry Andric 
691*bdd1243dSDimitry Andric   // If there is a next operand and it is 0, ignore it. Otherwise print a
692*bdd1243dSDimitry Andric   // diagnostic message.
693*bdd1243dSDimitry Andric   if (getLexer().is(AsmToken::Comma)) {
694*bdd1243dSDimitry Andric     getLexer().Lex(); // Consume comma token.
695*bdd1243dSDimitry Andric     int64_t ImmVal;
696*bdd1243dSDimitry Andric     SMLoc ImmStart = getLoc();
697*bdd1243dSDimitry Andric     if (getParser().parseIntToken(ImmVal, "expected optional integer offset"))
698*bdd1243dSDimitry Andric       return MatchOperand_ParseFail;
699*bdd1243dSDimitry Andric     if (ImmVal) {
700*bdd1243dSDimitry Andric       Error(ImmStart, "optional integer offset must be 0");
701*bdd1243dSDimitry Andric       return MatchOperand_ParseFail;
702*bdd1243dSDimitry Andric     }
703*bdd1243dSDimitry Andric   }
704*bdd1243dSDimitry Andric 
705*bdd1243dSDimitry Andric   return MatchOperand_Success;
706*bdd1243dSDimitry Andric }
70781ad6265SDimitry Andric /// Looks at a token type and creates the relevant operand from this
70881ad6265SDimitry Andric /// information, adding to Operands. Return true upon an error.
70981ad6265SDimitry Andric bool LoongArchAsmParser::parseOperand(OperandVector &Operands,
71081ad6265SDimitry Andric                                       StringRef Mnemonic) {
711*bdd1243dSDimitry Andric   // Check if the current operand has a custom associated parser, if so, try to
712*bdd1243dSDimitry Andric   // custom parse the operand, or fallback to the general approach.
713*bdd1243dSDimitry Andric   OperandMatchResultTy Result =
714*bdd1243dSDimitry Andric       MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/true);
715*bdd1243dSDimitry Andric   if (Result == MatchOperand_Success)
716*bdd1243dSDimitry Andric     return false;
717*bdd1243dSDimitry Andric   if (Result == MatchOperand_ParseFail)
718*bdd1243dSDimitry Andric     return true;
719*bdd1243dSDimitry Andric 
72081ad6265SDimitry Andric   if (parseRegister(Operands) == MatchOperand_Success ||
72181ad6265SDimitry Andric       parseImmediate(Operands) == MatchOperand_Success)
72281ad6265SDimitry Andric     return false;
72381ad6265SDimitry Andric 
72481ad6265SDimitry Andric   // Finally we have exhausted all options and must declare defeat.
72581ad6265SDimitry Andric   Error(getLoc(), "unknown operand");
72681ad6265SDimitry Andric   return true;
72781ad6265SDimitry Andric }
72881ad6265SDimitry Andric 
72981ad6265SDimitry Andric bool LoongArchAsmParser::ParseInstruction(ParseInstructionInfo &Info,
73081ad6265SDimitry Andric                                           StringRef Name, SMLoc NameLoc,
73181ad6265SDimitry Andric                                           OperandVector &Operands) {
73281ad6265SDimitry Andric   // First operand in MCInst is instruction mnemonic.
73381ad6265SDimitry Andric   Operands.push_back(LoongArchOperand::createToken(Name, NameLoc));
73481ad6265SDimitry Andric 
73581ad6265SDimitry Andric   // If there are no more operands, then finish.
73681ad6265SDimitry Andric   if (parseOptionalToken(AsmToken::EndOfStatement))
73781ad6265SDimitry Andric     return false;
73881ad6265SDimitry Andric 
73981ad6265SDimitry Andric   // Parse first operand.
74081ad6265SDimitry Andric   if (parseOperand(Operands, Name))
74181ad6265SDimitry Andric     return true;
74281ad6265SDimitry Andric 
74381ad6265SDimitry Andric   // Parse until end of statement, consuming commas between operands.
74481ad6265SDimitry Andric   while (parseOptionalToken(AsmToken::Comma))
74581ad6265SDimitry Andric     if (parseOperand(Operands, Name))
74681ad6265SDimitry Andric       return true;
74781ad6265SDimitry Andric 
74881ad6265SDimitry Andric   // Parse end of statement and return successfully.
74981ad6265SDimitry Andric   if (parseOptionalToken(AsmToken::EndOfStatement))
75081ad6265SDimitry Andric     return false;
75181ad6265SDimitry Andric 
75281ad6265SDimitry Andric   SMLoc Loc = getLexer().getLoc();
75381ad6265SDimitry Andric   getParser().eatToEndOfStatement();
75481ad6265SDimitry Andric   return Error(Loc, "unexpected token");
75581ad6265SDimitry Andric }
75681ad6265SDimitry Andric 
757*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg,
758*bdd1243dSDimitry Andric                                        const MCExpr *Symbol,
759*bdd1243dSDimitry Andric                                        SmallVectorImpl<Inst> &Insts,
760*bdd1243dSDimitry Andric                                        SMLoc IDLoc, MCStreamer &Out) {
761*bdd1243dSDimitry Andric   MCContext &Ctx = getContext();
762*bdd1243dSDimitry Andric   for (LoongArchAsmParser::Inst &Inst : Insts) {
763*bdd1243dSDimitry Andric     unsigned Opc = Inst.Opc;
764*bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = Inst.VK;
765*bdd1243dSDimitry Andric     const LoongArchMCExpr *LE = LoongArchMCExpr::create(Symbol, VK, Ctx);
766*bdd1243dSDimitry Andric     switch (Opc) {
767*bdd1243dSDimitry Andric     default:
768*bdd1243dSDimitry Andric       llvm_unreachable("unexpected opcode");
769*bdd1243dSDimitry Andric     case LoongArch::PCALAU12I:
770*bdd1243dSDimitry Andric     case LoongArch::LU12I_W:
771*bdd1243dSDimitry Andric       Out.emitInstruction(MCInstBuilder(Opc).addReg(DestReg).addExpr(LE),
772*bdd1243dSDimitry Andric                           getSTI());
773*bdd1243dSDimitry Andric       break;
774*bdd1243dSDimitry Andric     case LoongArch::ORI:
775*bdd1243dSDimitry Andric     case LoongArch::ADDI_W:
776*bdd1243dSDimitry Andric     case LoongArch::LD_W:
777*bdd1243dSDimitry Andric     case LoongArch::LD_D: {
778*bdd1243dSDimitry Andric       if (VK == LoongArchMCExpr::VK_LoongArch_None) {
779*bdd1243dSDimitry Andric         Out.emitInstruction(
780*bdd1243dSDimitry Andric             MCInstBuilder(Opc).addReg(DestReg).addReg(DestReg).addImm(0),
781*bdd1243dSDimitry Andric             getSTI());
782*bdd1243dSDimitry Andric         continue;
783*bdd1243dSDimitry Andric       }
784*bdd1243dSDimitry Andric       Out.emitInstruction(
785*bdd1243dSDimitry Andric           MCInstBuilder(Opc).addReg(DestReg).addReg(DestReg).addExpr(LE),
786*bdd1243dSDimitry Andric           getSTI());
787*bdd1243dSDimitry Andric       break;
788*bdd1243dSDimitry Andric     }
789*bdd1243dSDimitry Andric     case LoongArch::LU32I_D:
790*bdd1243dSDimitry Andric       Out.emitInstruction(MCInstBuilder(Opc)
791*bdd1243dSDimitry Andric                               .addReg(DestReg == TmpReg ? DestReg : TmpReg)
792*bdd1243dSDimitry Andric                               .addReg(DestReg == TmpReg ? DestReg : TmpReg)
793*bdd1243dSDimitry Andric                               .addExpr(LE),
794*bdd1243dSDimitry Andric                           getSTI());
795*bdd1243dSDimitry Andric       break;
796*bdd1243dSDimitry Andric     case LoongArch::LU52I_D:
797*bdd1243dSDimitry Andric       Out.emitInstruction(
798*bdd1243dSDimitry Andric           MCInstBuilder(Opc).addReg(TmpReg).addReg(TmpReg).addExpr(LE),
799*bdd1243dSDimitry Andric           getSTI());
800*bdd1243dSDimitry Andric       break;
801*bdd1243dSDimitry Andric     case LoongArch::ADDI_D:
802*bdd1243dSDimitry Andric       Out.emitInstruction(
803*bdd1243dSDimitry Andric           MCInstBuilder(Opc)
804*bdd1243dSDimitry Andric               .addReg(TmpReg)
805*bdd1243dSDimitry Andric               .addReg(DestReg == TmpReg ? TmpReg : LoongArch::R0)
806*bdd1243dSDimitry Andric               .addExpr(LE),
807*bdd1243dSDimitry Andric           getSTI());
808*bdd1243dSDimitry Andric       break;
809*bdd1243dSDimitry Andric     case LoongArch::ADD_D:
810*bdd1243dSDimitry Andric     case LoongArch::LDX_D:
811*bdd1243dSDimitry Andric       Out.emitInstruction(
812*bdd1243dSDimitry Andric           MCInstBuilder(Opc).addReg(DestReg).addReg(DestReg).addReg(TmpReg),
813*bdd1243dSDimitry Andric           getSTI());
814*bdd1243dSDimitry Andric       break;
815*bdd1243dSDimitry Andric     }
816*bdd1243dSDimitry Andric   }
817*bdd1243dSDimitry Andric }
818*bdd1243dSDimitry Andric 
819*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressAbs(MCInst &Inst, SMLoc IDLoc,
820*bdd1243dSDimitry Andric                                             MCStreamer &Out) {
821*bdd1243dSDimitry Andric   // la.abs $rd, sym
822*bdd1243dSDimitry Andric   // expands to:
823*bdd1243dSDimitry Andric   //   lu12i.w $rd, %abs_hi20(sym)
824*bdd1243dSDimitry Andric   //   ori     $rd, $rd, %abs_lo12(sym)
825*bdd1243dSDimitry Andric   //
826*bdd1243dSDimitry Andric   // for 64bit appends:
827*bdd1243dSDimitry Andric   //   lu32i.d $rd, %abs64_lo20(sym)
828*bdd1243dSDimitry Andric   //   lu52i.d $rd, $rd, %abs64_hi12(sym)
829*bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
830*bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOpcode() == LoongArch::PseudoLA_ABS
831*bdd1243dSDimitry Andric                              ? Inst.getOperand(1).getExpr()
832*bdd1243dSDimitry Andric                              : Inst.getOperand(2).getExpr();
833*bdd1243dSDimitry Andric   InstSeq Insts;
834*bdd1243dSDimitry Andric 
835*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
836*bdd1243dSDimitry Andric       LoongArch::LU12I_W, LoongArchMCExpr::VK_LoongArch_ABS_HI20));
837*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
838*bdd1243dSDimitry Andric       LoongArch::ORI, LoongArchMCExpr::VK_LoongArch_ABS_LO12));
839*bdd1243dSDimitry Andric 
840*bdd1243dSDimitry Andric   if (is64Bit()) {
841*bdd1243dSDimitry Andric     Insts.push_back(LoongArchAsmParser::Inst(
842*bdd1243dSDimitry Andric         LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_ABS64_LO20));
843*bdd1243dSDimitry Andric     Insts.push_back(LoongArchAsmParser::Inst(
844*bdd1243dSDimitry Andric         LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_ABS64_HI12));
845*bdd1243dSDimitry Andric   }
846*bdd1243dSDimitry Andric 
847*bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
848*bdd1243dSDimitry Andric }
849*bdd1243dSDimitry Andric 
850*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressPcrel(MCInst &Inst, SMLoc IDLoc,
851*bdd1243dSDimitry Andric                                               MCStreamer &Out) {
852*bdd1243dSDimitry Andric   // la.pcrel $rd, sym
853*bdd1243dSDimitry Andric   // expands to:
854*bdd1243dSDimitry Andric   //   pcalau12i $rd, %pc_hi20(sym)
855*bdd1243dSDimitry Andric   //   addi.w/d  $rd, rd, %pc_lo12(sym)
856*bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
857*bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(1).getExpr();
858*bdd1243dSDimitry Andric   InstSeq Insts;
859*bdd1243dSDimitry Andric   unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
860*bdd1243dSDimitry Andric 
861*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
862*bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_PCALA_HI20));
863*bdd1243dSDimitry Andric   Insts.push_back(
864*bdd1243dSDimitry Andric       LoongArchAsmParser::Inst(ADDI, LoongArchMCExpr::VK_LoongArch_PCALA_LO12));
865*bdd1243dSDimitry Andric 
866*bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
867*bdd1243dSDimitry Andric }
868*bdd1243dSDimitry Andric 
869*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressPcrelLarge(MCInst &Inst, SMLoc IDLoc,
870*bdd1243dSDimitry Andric                                                    MCStreamer &Out) {
871*bdd1243dSDimitry Andric   // la.pcrel $rd, $rj, sym
872*bdd1243dSDimitry Andric   // expands to:
873*bdd1243dSDimitry Andric   //   pcalau12i $rd, %pc_hi20(sym)
874*bdd1243dSDimitry Andric   //   addi.d    $rj, $r0, %pc_lo12(sym)
875*bdd1243dSDimitry Andric   //   lu32i.d   $rj, %pc64_lo20(sym)
876*bdd1243dSDimitry Andric   //   lu52i.d   $rj, $rj, %pc64_hi12(sym)
877*bdd1243dSDimitry Andric   //   add.d     $rd, $rd, $rj
878*bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
879*bdd1243dSDimitry Andric   MCRegister TmpReg = Inst.getOperand(1).getReg();
880*bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(2).getExpr();
881*bdd1243dSDimitry Andric   InstSeq Insts;
882*bdd1243dSDimitry Andric 
883*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
884*bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_PCALA_HI20));
885*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
886*bdd1243dSDimitry Andric       LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_PCALA_LO12));
887*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
888*bdd1243dSDimitry Andric       LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_PCALA64_LO20));
889*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
890*bdd1243dSDimitry Andric       LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_PCALA64_HI12));
891*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(LoongArch::ADD_D));
892*bdd1243dSDimitry Andric 
893*bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
894*bdd1243dSDimitry Andric }
895*bdd1243dSDimitry Andric 
896*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressGot(MCInst &Inst, SMLoc IDLoc,
897*bdd1243dSDimitry Andric                                             MCStreamer &Out) {
898*bdd1243dSDimitry Andric   // la.got $rd, sym
899*bdd1243dSDimitry Andric   // expands to:
900*bdd1243dSDimitry Andric   //   pcalau12i $rd, %got_pc_hi20(sym)
901*bdd1243dSDimitry Andric   //   ld.w/d    $rd, $rd, %got_pc_lo12(sym)
902*bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
903*bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(1).getExpr();
904*bdd1243dSDimitry Andric   InstSeq Insts;
905*bdd1243dSDimitry Andric   unsigned LD = is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
906*bdd1243dSDimitry Andric 
907*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
908*bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20));
909*bdd1243dSDimitry Andric   Insts.push_back(
910*bdd1243dSDimitry Andric       LoongArchAsmParser::Inst(LD, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
911*bdd1243dSDimitry Andric 
912*bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
913*bdd1243dSDimitry Andric }
914*bdd1243dSDimitry Andric 
915*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressGotLarge(MCInst &Inst, SMLoc IDLoc,
916*bdd1243dSDimitry Andric                                                  MCStreamer &Out) {
917*bdd1243dSDimitry Andric   // la.got $rd, $rj, sym
918*bdd1243dSDimitry Andric   // expands to:
919*bdd1243dSDimitry Andric   //   pcalau12i $rd, %got_pc_hi20(sym)
920*bdd1243dSDimitry Andric   //   addi.d    $rj, $r0, %got_pc_lo12(sym)
921*bdd1243dSDimitry Andric   //   lu32i.d   $rj, %got64_pc_lo20(sym)
922*bdd1243dSDimitry Andric   //   lu52i.d   $rj, $rj, %got64_pc_hi12(sym)
923*bdd1243dSDimitry Andric   //   ldx.d     $rd, $rd, $rj
924*bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
925*bdd1243dSDimitry Andric   MCRegister TmpReg = Inst.getOperand(1).getReg();
926*bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(2).getExpr();
927*bdd1243dSDimitry Andric   InstSeq Insts;
928*bdd1243dSDimitry Andric 
929*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
930*bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20));
931*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
932*bdd1243dSDimitry Andric       LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
933*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
934*bdd1243dSDimitry Andric       LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20));
935*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
936*bdd1243dSDimitry Andric       LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12));
937*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(LoongArch::LDX_D));
938*bdd1243dSDimitry Andric 
939*bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
940*bdd1243dSDimitry Andric }
941*bdd1243dSDimitry Andric 
942*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSLE(MCInst &Inst, SMLoc IDLoc,
943*bdd1243dSDimitry Andric                                               MCStreamer &Out) {
944*bdd1243dSDimitry Andric   // la.tls.le $rd, sym
945*bdd1243dSDimitry Andric   // expands to:
946*bdd1243dSDimitry Andric   //   lu12i.w $rd, %le_hi20(sym)
947*bdd1243dSDimitry Andric   //   ori     $rd, $rd, %le_lo12(sym)
948*bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
949*bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(1).getExpr();
950*bdd1243dSDimitry Andric   InstSeq Insts;
951*bdd1243dSDimitry Andric 
952*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
953*bdd1243dSDimitry Andric       LoongArch::LU12I_W, LoongArchMCExpr::VK_LoongArch_TLS_LE_HI20));
954*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
955*bdd1243dSDimitry Andric       LoongArch::ORI, LoongArchMCExpr::VK_LoongArch_TLS_LE_LO12));
956*bdd1243dSDimitry Andric 
957*bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
958*bdd1243dSDimitry Andric }
959*bdd1243dSDimitry Andric 
960*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSIE(MCInst &Inst, SMLoc IDLoc,
961*bdd1243dSDimitry Andric                                               MCStreamer &Out) {
962*bdd1243dSDimitry Andric   // la.tls.ie $rd, sym
963*bdd1243dSDimitry Andric   // expands to:
964*bdd1243dSDimitry Andric   //   pcalau12i $rd, %ie_pc_hi20(sym)
965*bdd1243dSDimitry Andric   //   ld.w/d    $rd, $rd, %ie_pc_lo12(sym)
966*bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
967*bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(1).getExpr();
968*bdd1243dSDimitry Andric   InstSeq Insts;
969*bdd1243dSDimitry Andric   unsigned LD = is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
970*bdd1243dSDimitry Andric 
971*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
972*bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20));
973*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
974*bdd1243dSDimitry Andric       LD, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12));
975*bdd1243dSDimitry Andric 
976*bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
977*bdd1243dSDimitry Andric }
978*bdd1243dSDimitry Andric 
979*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSIELarge(MCInst &Inst, SMLoc IDLoc,
980*bdd1243dSDimitry Andric                                                    MCStreamer &Out) {
981*bdd1243dSDimitry Andric   // la.tls.ie $rd, $rj, sym
982*bdd1243dSDimitry Andric   // expands to:
983*bdd1243dSDimitry Andric   //   pcalau12i $rd, %ie_pc_hi20(sym)
984*bdd1243dSDimitry Andric   //   addi.d    $rj, $r0, %ie_pc_lo12(sym)
985*bdd1243dSDimitry Andric   //   lu32i.d   $rj, %ie64_pc_lo20(sym)
986*bdd1243dSDimitry Andric   //   lu52i.d   $rj, $rj, %ie64_pc_hi12(sym)
987*bdd1243dSDimitry Andric   //   ldx.d     $rd, $rd, $rj
988*bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
989*bdd1243dSDimitry Andric   MCRegister TmpReg = Inst.getOperand(1).getReg();
990*bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(2).getExpr();
991*bdd1243dSDimitry Andric   InstSeq Insts;
992*bdd1243dSDimitry Andric 
993*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
994*bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20));
995*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
996*bdd1243dSDimitry Andric       LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12));
997*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
998*bdd1243dSDimitry Andric       LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_LO20));
999*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1000*bdd1243dSDimitry Andric       LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_HI12));
1001*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(LoongArch::LDX_D));
1002*bdd1243dSDimitry Andric 
1003*bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
1004*bdd1243dSDimitry Andric }
1005*bdd1243dSDimitry Andric 
1006*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSLD(MCInst &Inst, SMLoc IDLoc,
1007*bdd1243dSDimitry Andric                                               MCStreamer &Out) {
1008*bdd1243dSDimitry Andric   // la.tls.ld $rd, sym
1009*bdd1243dSDimitry Andric   // expands to:
1010*bdd1243dSDimitry Andric   //   pcalau12i $rd, %ld_pc_hi20(sym)
1011*bdd1243dSDimitry Andric   //   addi.w/d  $rd, $rd, %got_pc_lo12(sym)
1012*bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
1013*bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(1).getExpr();
1014*bdd1243dSDimitry Andric   InstSeq Insts;
1015*bdd1243dSDimitry Andric   unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
1016*bdd1243dSDimitry Andric 
1017*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1018*bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20));
1019*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1020*bdd1243dSDimitry Andric       ADDI, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
1021*bdd1243dSDimitry Andric 
1022*bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
1023*bdd1243dSDimitry Andric }
1024*bdd1243dSDimitry Andric 
1025*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSLDLarge(MCInst &Inst, SMLoc IDLoc,
1026*bdd1243dSDimitry Andric                                                    MCStreamer &Out) {
1027*bdd1243dSDimitry Andric   // la.tls.ld $rd, $rj, sym
1028*bdd1243dSDimitry Andric   // expands to:
1029*bdd1243dSDimitry Andric   //   pcalau12i $rd, %ld_pc_hi20(sym)
1030*bdd1243dSDimitry Andric   //   addi.d    $rj, $r0, %got_pc_lo12(sym)
1031*bdd1243dSDimitry Andric   //   lu32i.d   $rj, %got64_pc_lo20(sym)
1032*bdd1243dSDimitry Andric   //   lu52i.d   $rj, $rj, %got64_pc_hi12(sym)
1033*bdd1243dSDimitry Andric   //   add.d     $rd, $rd, $rj
1034*bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
1035*bdd1243dSDimitry Andric   MCRegister TmpReg = Inst.getOperand(1).getReg();
1036*bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(2).getExpr();
1037*bdd1243dSDimitry Andric   InstSeq Insts;
1038*bdd1243dSDimitry Andric 
1039*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1040*bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20));
1041*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1042*bdd1243dSDimitry Andric       LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
1043*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1044*bdd1243dSDimitry Andric       LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20));
1045*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1046*bdd1243dSDimitry Andric       LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12));
1047*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(LoongArch::ADD_D));
1048*bdd1243dSDimitry Andric 
1049*bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
1050*bdd1243dSDimitry Andric }
1051*bdd1243dSDimitry Andric 
1052*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSGD(MCInst &Inst, SMLoc IDLoc,
1053*bdd1243dSDimitry Andric                                               MCStreamer &Out) {
1054*bdd1243dSDimitry Andric   // la.tls.gd $rd, sym
1055*bdd1243dSDimitry Andric   // expands to:
1056*bdd1243dSDimitry Andric   //   pcalau12i $rd, %gd_pc_hi20(sym)
1057*bdd1243dSDimitry Andric   //   addi.w/d  $rd, $rd, %got_pc_lo12(sym)
1058*bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
1059*bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(1).getExpr();
1060*bdd1243dSDimitry Andric   InstSeq Insts;
1061*bdd1243dSDimitry Andric   unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
1062*bdd1243dSDimitry Andric 
1063*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1064*bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20));
1065*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1066*bdd1243dSDimitry Andric       ADDI, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
1067*bdd1243dSDimitry Andric 
1068*bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
1069*bdd1243dSDimitry Andric }
1070*bdd1243dSDimitry Andric 
1071*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSGDLarge(MCInst &Inst, SMLoc IDLoc,
1072*bdd1243dSDimitry Andric                                                    MCStreamer &Out) {
1073*bdd1243dSDimitry Andric   // la.tls.gd $rd, $rj, sym
1074*bdd1243dSDimitry Andric   // expands to:
1075*bdd1243dSDimitry Andric   //   pcalau12i $rd, %gd_pc_hi20(sym)
1076*bdd1243dSDimitry Andric   //   addi.d    $rj, $r0, %got_pc_lo12(sym)
1077*bdd1243dSDimitry Andric   //   lu32i.d   $rj, %got64_pc_lo20(sym)
1078*bdd1243dSDimitry Andric   //   lu52i.d   $rj, $rj, %got64_pc_hi12(sym)
1079*bdd1243dSDimitry Andric   //   add.d     $rd, $rd, $rj
1080*bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
1081*bdd1243dSDimitry Andric   MCRegister TmpReg = Inst.getOperand(1).getReg();
1082*bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(2).getExpr();
1083*bdd1243dSDimitry Andric   InstSeq Insts;
1084*bdd1243dSDimitry Andric 
1085*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1086*bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20));
1087*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1088*bdd1243dSDimitry Andric       LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
1089*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1090*bdd1243dSDimitry Andric       LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20));
1091*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1092*bdd1243dSDimitry Andric       LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12));
1093*bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(LoongArch::ADD_D));
1094*bdd1243dSDimitry Andric 
1095*bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
1096*bdd1243dSDimitry Andric }
1097*bdd1243dSDimitry Andric 
1098*bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadImm(MCInst &Inst, SMLoc IDLoc,
1099*bdd1243dSDimitry Andric                                      MCStreamer &Out) {
1100*bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
1101*bdd1243dSDimitry Andric   int64_t Imm = Inst.getOperand(1).getImm();
1102*bdd1243dSDimitry Andric   MCRegister SrcReg = LoongArch::R0;
1103*bdd1243dSDimitry Andric 
1104*bdd1243dSDimitry Andric   if (Inst.getOpcode() == LoongArch::PseudoLI_W)
1105*bdd1243dSDimitry Andric     Imm = SignExtend64<32>(Imm);
1106*bdd1243dSDimitry Andric 
1107*bdd1243dSDimitry Andric   for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Imm)) {
1108*bdd1243dSDimitry Andric     unsigned Opc = Inst.Opc;
1109*bdd1243dSDimitry Andric     if (Opc == LoongArch::LU12I_W)
1110*bdd1243dSDimitry Andric       Out.emitInstruction(MCInstBuilder(Opc).addReg(DestReg).addImm(Inst.Imm),
1111*bdd1243dSDimitry Andric                           getSTI());
1112*bdd1243dSDimitry Andric     else
1113*bdd1243dSDimitry Andric       Out.emitInstruction(
1114*bdd1243dSDimitry Andric           MCInstBuilder(Opc).addReg(DestReg).addReg(SrcReg).addImm(Inst.Imm),
1115*bdd1243dSDimitry Andric           getSTI());
1116*bdd1243dSDimitry Andric     SrcReg = DestReg;
1117*bdd1243dSDimitry Andric   }
1118*bdd1243dSDimitry Andric }
1119*bdd1243dSDimitry Andric 
112081ad6265SDimitry Andric bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
112181ad6265SDimitry Andric                                             OperandVector &Operands,
112281ad6265SDimitry Andric                                             MCStreamer &Out) {
112381ad6265SDimitry Andric   Inst.setLoc(IDLoc);
1124*bdd1243dSDimitry Andric   switch (Inst.getOpcode()) {
1125*bdd1243dSDimitry Andric   default:
1126*bdd1243dSDimitry Andric     break;
1127*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_ABS:
1128*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_ABS_LARGE:
1129*bdd1243dSDimitry Andric     emitLoadAddressAbs(Inst, IDLoc, Out);
1130*bdd1243dSDimitry Andric     return false;
1131*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_PCREL:
1132*bdd1243dSDimitry Andric     emitLoadAddressPcrel(Inst, IDLoc, Out);
1133*bdd1243dSDimitry Andric     return false;
1134*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_PCREL_LARGE:
1135*bdd1243dSDimitry Andric     emitLoadAddressPcrelLarge(Inst, IDLoc, Out);
1136*bdd1243dSDimitry Andric     return false;
1137*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_GOT:
1138*bdd1243dSDimitry Andric     emitLoadAddressGot(Inst, IDLoc, Out);
1139*bdd1243dSDimitry Andric     return false;
1140*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_GOT_LARGE:
1141*bdd1243dSDimitry Andric     emitLoadAddressGotLarge(Inst, IDLoc, Out);
1142*bdd1243dSDimitry Andric     return false;
1143*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_LE:
1144*bdd1243dSDimitry Andric     emitLoadAddressTLSLE(Inst, IDLoc, Out);
1145*bdd1243dSDimitry Andric     return false;
1146*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_IE:
1147*bdd1243dSDimitry Andric     emitLoadAddressTLSIE(Inst, IDLoc, Out);
1148*bdd1243dSDimitry Andric     return false;
1149*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_IE_LARGE:
1150*bdd1243dSDimitry Andric     emitLoadAddressTLSIELarge(Inst, IDLoc, Out);
1151*bdd1243dSDimitry Andric     return false;
1152*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_LD:
1153*bdd1243dSDimitry Andric     emitLoadAddressTLSLD(Inst, IDLoc, Out);
1154*bdd1243dSDimitry Andric     return false;
1155*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_LD_LARGE:
1156*bdd1243dSDimitry Andric     emitLoadAddressTLSLDLarge(Inst, IDLoc, Out);
1157*bdd1243dSDimitry Andric     return false;
1158*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_GD:
1159*bdd1243dSDimitry Andric     emitLoadAddressTLSGD(Inst, IDLoc, Out);
1160*bdd1243dSDimitry Andric     return false;
1161*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_GD_LARGE:
1162*bdd1243dSDimitry Andric     emitLoadAddressTLSGDLarge(Inst, IDLoc, Out);
1163*bdd1243dSDimitry Andric     return false;
1164*bdd1243dSDimitry Andric   case LoongArch::PseudoLI_W:
1165*bdd1243dSDimitry Andric   case LoongArch::PseudoLI_D:
1166*bdd1243dSDimitry Andric     emitLoadImm(Inst, IDLoc, Out);
1167*bdd1243dSDimitry Andric     return false;
1168*bdd1243dSDimitry Andric   }
116981ad6265SDimitry Andric   Out.emitInstruction(Inst, getSTI());
117081ad6265SDimitry Andric   return false;
117181ad6265SDimitry Andric }
117281ad6265SDimitry Andric 
117381ad6265SDimitry Andric unsigned LoongArchAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
1174*bdd1243dSDimitry Andric   unsigned Opc = Inst.getOpcode();
1175*bdd1243dSDimitry Andric   switch (Opc) {
117681ad6265SDimitry Andric   default:
1177*bdd1243dSDimitry Andric     if (Opc >= LoongArch::AMADD_D && Opc <= LoongArch::AMXOR_W) {
1178*bdd1243dSDimitry Andric       unsigned Rd = Inst.getOperand(0).getReg();
1179*bdd1243dSDimitry Andric       unsigned Rk = Inst.getOperand(1).getReg();
1180*bdd1243dSDimitry Andric       unsigned Rj = Inst.getOperand(2).getReg();
1181*bdd1243dSDimitry Andric       if ((Rd == Rk || Rd == Rj) && Rd != LoongArch::R0)
1182*bdd1243dSDimitry Andric         return Match_RequiresAMORdDifferRkRj;
1183*bdd1243dSDimitry Andric     }
118481ad6265SDimitry Andric     break;
1185*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_PCREL_LARGE:
1186*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_GOT_LARGE:
1187*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_IE_LARGE:
1188*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_LD_LARGE:
1189*bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_GD_LARGE: {
1190*bdd1243dSDimitry Andric     unsigned Rd = Inst.getOperand(0).getReg();
1191*bdd1243dSDimitry Andric     unsigned Rj = Inst.getOperand(1).getReg();
1192*bdd1243dSDimitry Andric     if (Rd == Rj)
1193*bdd1243dSDimitry Andric       return Match_RequiresLAORdDifferRj;
1194*bdd1243dSDimitry Andric     break;
1195*bdd1243dSDimitry Andric   }
119681ad6265SDimitry Andric   case LoongArch::CSRXCHG: {
119781ad6265SDimitry Andric     unsigned Rj = Inst.getOperand(2).getReg();
119881ad6265SDimitry Andric     if (Rj == LoongArch::R0 || Rj == LoongArch::R1)
119981ad6265SDimitry Andric       return Match_RequiresOpnd2NotR0R1;
120081ad6265SDimitry Andric     return Match_Success;
120181ad6265SDimitry Andric   }
120281ad6265SDimitry Andric   case LoongArch::BSTRINS_W:
120381ad6265SDimitry Andric   case LoongArch::BSTRINS_D:
120481ad6265SDimitry Andric   case LoongArch::BSTRPICK_W:
120581ad6265SDimitry Andric   case LoongArch::BSTRPICK_D: {
120681ad6265SDimitry Andric     unsigned Opc = Inst.getOpcode();
120781ad6265SDimitry Andric     const signed Msb =
120881ad6265SDimitry Andric         (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D)
120981ad6265SDimitry Andric             ? Inst.getOperand(3).getImm()
121081ad6265SDimitry Andric             : Inst.getOperand(2).getImm();
121181ad6265SDimitry Andric     const signed Lsb =
121281ad6265SDimitry Andric         (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D)
121381ad6265SDimitry Andric             ? Inst.getOperand(4).getImm()
121481ad6265SDimitry Andric             : Inst.getOperand(3).getImm();
121581ad6265SDimitry Andric     if (Msb < Lsb)
121681ad6265SDimitry Andric       return Match_RequiresMsbNotLessThanLsb;
121781ad6265SDimitry Andric     return Match_Success;
121881ad6265SDimitry Andric   }
121981ad6265SDimitry Andric   }
122081ad6265SDimitry Andric 
122181ad6265SDimitry Andric   return Match_Success;
122281ad6265SDimitry Andric }
122381ad6265SDimitry Andric 
122481ad6265SDimitry Andric unsigned
122581ad6265SDimitry Andric LoongArchAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
122681ad6265SDimitry Andric                                                unsigned Kind) {
122781ad6265SDimitry Andric   LoongArchOperand &Op = static_cast<LoongArchOperand &>(AsmOp);
122881ad6265SDimitry Andric   if (!Op.isReg())
122981ad6265SDimitry Andric     return Match_InvalidOperand;
123081ad6265SDimitry Andric 
123181ad6265SDimitry Andric   MCRegister Reg = Op.getReg();
123281ad6265SDimitry Andric   // As the parser couldn't differentiate an FPR32 from an FPR64, coerce the
123381ad6265SDimitry Andric   // register from FPR32 to FPR64 if necessary.
123481ad6265SDimitry Andric   if (LoongArchMCRegisterClasses[LoongArch::FPR32RegClassID].contains(Reg) &&
123581ad6265SDimitry Andric       Kind == MCK_FPR64) {
123681ad6265SDimitry Andric     Op.setReg(convertFPR32ToFPR64(Reg));
123781ad6265SDimitry Andric     return Match_Success;
123881ad6265SDimitry Andric   }
123981ad6265SDimitry Andric 
124081ad6265SDimitry Andric   return Match_InvalidOperand;
124181ad6265SDimitry Andric }
124281ad6265SDimitry Andric 
124381ad6265SDimitry Andric bool LoongArchAsmParser::generateImmOutOfRangeError(
124481ad6265SDimitry Andric     OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper,
124581ad6265SDimitry Andric     Twine Msg = "immediate must be an integer in the range") {
124681ad6265SDimitry Andric   SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
124781ad6265SDimitry Andric   return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]");
124881ad6265SDimitry Andric }
124981ad6265SDimitry Andric 
125081ad6265SDimitry Andric bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
125181ad6265SDimitry Andric                                                  OperandVector &Operands,
125281ad6265SDimitry Andric                                                  MCStreamer &Out,
125381ad6265SDimitry Andric                                                  uint64_t &ErrorInfo,
125481ad6265SDimitry Andric                                                  bool MatchingInlineAsm) {
125581ad6265SDimitry Andric   MCInst Inst;
125681ad6265SDimitry Andric   FeatureBitset MissingFeatures;
125781ad6265SDimitry Andric 
125881ad6265SDimitry Andric   auto Result = MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
125981ad6265SDimitry Andric                                      MatchingInlineAsm);
126081ad6265SDimitry Andric   switch (Result) {
126181ad6265SDimitry Andric   default:
126281ad6265SDimitry Andric     break;
126381ad6265SDimitry Andric   case Match_Success:
126481ad6265SDimitry Andric     return processInstruction(Inst, IDLoc, Operands, Out);
126581ad6265SDimitry Andric   case Match_MissingFeature: {
126681ad6265SDimitry Andric     assert(MissingFeatures.any() && "Unknown missing features!");
126781ad6265SDimitry Andric     bool FirstFeature = true;
126881ad6265SDimitry Andric     std::string Msg = "instruction requires the following:";
126981ad6265SDimitry Andric     for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
127081ad6265SDimitry Andric       if (MissingFeatures[i]) {
127181ad6265SDimitry Andric         Msg += FirstFeature ? " " : ", ";
127281ad6265SDimitry Andric         Msg += getSubtargetFeatureName(i);
127381ad6265SDimitry Andric         FirstFeature = false;
127481ad6265SDimitry Andric       }
127581ad6265SDimitry Andric     }
127681ad6265SDimitry Andric     return Error(IDLoc, Msg);
127781ad6265SDimitry Andric   }
127881ad6265SDimitry Andric   case Match_MnemonicFail: {
127981ad6265SDimitry Andric     FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
128081ad6265SDimitry Andric     std::string Suggestion = LoongArchMnemonicSpellCheck(
128181ad6265SDimitry Andric         ((LoongArchOperand &)*Operands[0]).getToken(), FBS, 0);
128281ad6265SDimitry Andric     return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion);
128381ad6265SDimitry Andric   }
128481ad6265SDimitry Andric   case Match_InvalidOperand: {
128581ad6265SDimitry Andric     SMLoc ErrorLoc = IDLoc;
128681ad6265SDimitry Andric     if (ErrorInfo != ~0ULL) {
128781ad6265SDimitry Andric       if (ErrorInfo >= Operands.size())
128881ad6265SDimitry Andric         return Error(ErrorLoc, "too few operands for instruction");
128981ad6265SDimitry Andric 
129081ad6265SDimitry Andric       ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
129181ad6265SDimitry Andric       if (ErrorLoc == SMLoc())
129281ad6265SDimitry Andric         ErrorLoc = IDLoc;
129381ad6265SDimitry Andric     }
129481ad6265SDimitry Andric     return Error(ErrorLoc, "invalid operand for instruction");
129581ad6265SDimitry Andric   }
129681ad6265SDimitry Andric   }
129781ad6265SDimitry Andric 
129881ad6265SDimitry Andric   // Handle the case when the error message is of specific type
129981ad6265SDimitry Andric   // other than the generic Match_InvalidOperand, and the
130081ad6265SDimitry Andric   // corresponding operand is missing.
130181ad6265SDimitry Andric   if (Result > FIRST_TARGET_MATCH_RESULT_TY) {
130281ad6265SDimitry Andric     SMLoc ErrorLoc = IDLoc;
130381ad6265SDimitry Andric     if (ErrorInfo != ~0ULL && ErrorInfo >= Operands.size())
130481ad6265SDimitry Andric       return Error(ErrorLoc, "too few operands for instruction");
130581ad6265SDimitry Andric   }
130681ad6265SDimitry Andric 
130781ad6265SDimitry Andric   switch (Result) {
130881ad6265SDimitry Andric   default:
130981ad6265SDimitry Andric     break;
131081ad6265SDimitry Andric   case Match_RequiresMsbNotLessThanLsb: {
131181ad6265SDimitry Andric     SMLoc ErrorStart = Operands[3]->getStartLoc();
131281ad6265SDimitry Andric     return Error(ErrorStart, "msb is less than lsb",
131381ad6265SDimitry Andric                  SMRange(ErrorStart, Operands[4]->getEndLoc()));
131481ad6265SDimitry Andric   }
131581ad6265SDimitry Andric   case Match_RequiresOpnd2NotR0R1:
131681ad6265SDimitry Andric     return Error(Operands[2]->getStartLoc(), "must not be $r0 or $r1");
1317*bdd1243dSDimitry Andric   case Match_RequiresAMORdDifferRkRj:
1318*bdd1243dSDimitry Andric     return Error(Operands[1]->getStartLoc(),
1319*bdd1243dSDimitry Andric                  "$rd must be different from both $rk and $rj");
1320*bdd1243dSDimitry Andric   case Match_RequiresLAORdDifferRj:
1321*bdd1243dSDimitry Andric     return Error(Operands[1]->getStartLoc(), "$rd must be different from $rj");
132281ad6265SDimitry Andric   case Match_InvalidUImm2:
132381ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
132481ad6265SDimitry Andric                                       /*Upper=*/(1 << 2) - 1);
132581ad6265SDimitry Andric   case Match_InvalidUImm2plus1:
132681ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/1,
132781ad6265SDimitry Andric                                       /*Upper=*/(1 << 2));
132881ad6265SDimitry Andric   case Match_InvalidUImm3:
132981ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
133081ad6265SDimitry Andric                                       /*Upper=*/(1 << 3) - 1);
133181ad6265SDimitry Andric   case Match_InvalidUImm5:
133281ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
133381ad6265SDimitry Andric                                       /*Upper=*/(1 << 5) - 1);
133481ad6265SDimitry Andric   case Match_InvalidUImm6:
133581ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
133681ad6265SDimitry Andric                                       /*Upper=*/(1 << 6) - 1);
133781ad6265SDimitry Andric   case Match_InvalidUImm12:
133881ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
133981ad6265SDimitry Andric                                       /*Upper=*/(1 << 12) - 1);
1340*bdd1243dSDimitry Andric   case Match_InvalidUImm12ori:
1341*bdd1243dSDimitry Andric     return generateImmOutOfRangeError(
1342*bdd1243dSDimitry Andric         Operands, ErrorInfo, /*Lower=*/0,
1343*bdd1243dSDimitry Andric         /*Upper=*/(1 << 12) - 1,
1344*bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %abs_lo12) or an "
1345*bdd1243dSDimitry Andric         "integer in the range");
134681ad6265SDimitry Andric   case Match_InvalidUImm15:
134781ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
134881ad6265SDimitry Andric                                       /*Upper=*/(1 << 15) - 1);
134981ad6265SDimitry Andric   case Match_InvalidSImm12:
135081ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 11),
135181ad6265SDimitry Andric                                       /*Upper=*/(1 << 11) - 1);
1352*bdd1243dSDimitry Andric   case Match_InvalidSImm12addlike:
1353*bdd1243dSDimitry Andric     return generateImmOutOfRangeError(
1354*bdd1243dSDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 11),
1355*bdd1243dSDimitry Andric         /*Upper=*/(1 << 11) - 1,
1356*bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %pc_lo12) or an integer "
1357*bdd1243dSDimitry Andric         "in the range");
1358*bdd1243dSDimitry Andric   case Match_InvalidSImm12lu52id:
1359*bdd1243dSDimitry Andric     return generateImmOutOfRangeError(
1360*bdd1243dSDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 11),
1361*bdd1243dSDimitry Andric         /*Upper=*/(1 << 11) - 1,
1362*bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %pc64_hi12) or an "
1363*bdd1243dSDimitry Andric         "integer in the range");
136481ad6265SDimitry Andric   case Match_InvalidSImm14lsl2:
136581ad6265SDimitry Andric     return generateImmOutOfRangeError(
136681ad6265SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 15), /*Upper=*/(1 << 15) - 4,
136781ad6265SDimitry Andric         "immediate must be a multiple of 4 in the range");
136881ad6265SDimitry Andric   case Match_InvalidSImm16:
136981ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 15),
137081ad6265SDimitry Andric                                       /*Upper=*/(1 << 15) - 1);
137181ad6265SDimitry Andric   case Match_InvalidSImm16lsl2:
137281ad6265SDimitry Andric     return generateImmOutOfRangeError(
137381ad6265SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 17), /*Upper=*/(1 << 17) - 4,
1374*bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %b16) or an integer "
1375*bdd1243dSDimitry Andric         "in the range");
137681ad6265SDimitry Andric   case Match_InvalidSImm20:
137781ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 19),
137881ad6265SDimitry Andric                                       /*Upper=*/(1 << 19) - 1);
1379*bdd1243dSDimitry Andric   case Match_InvalidSImm20lu12iw:
1380*bdd1243dSDimitry Andric     return generateImmOutOfRangeError(
1381*bdd1243dSDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 19),
1382*bdd1243dSDimitry Andric         /*Upper=*/(1 << 19) - 1,
1383*bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %abs_hi20) or an integer "
1384*bdd1243dSDimitry Andric         "in the range");
1385*bdd1243dSDimitry Andric   case Match_InvalidSImm20lu32id:
1386*bdd1243dSDimitry Andric     return generateImmOutOfRangeError(
1387*bdd1243dSDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 19),
1388*bdd1243dSDimitry Andric         /*Upper=*/(1 << 19) - 1,
1389*bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %abs64_lo20) or an "
1390*bdd1243dSDimitry Andric         "integer in the range");
1391*bdd1243dSDimitry Andric   case Match_InvalidSImm20pcalau12i:
1392*bdd1243dSDimitry Andric     return generateImmOutOfRangeError(
1393*bdd1243dSDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 19),
1394*bdd1243dSDimitry Andric         /*Upper=*/(1 << 19) - 1,
1395*bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %pc_hi20) or an integer "
1396*bdd1243dSDimitry Andric         "in the range");
139781ad6265SDimitry Andric   case Match_InvalidSImm21lsl2:
139881ad6265SDimitry Andric     return generateImmOutOfRangeError(
139981ad6265SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4,
1400*bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %b21) or an integer "
1401*bdd1243dSDimitry Andric         "in the range");
1402*bdd1243dSDimitry Andric   case Match_InvalidSImm26Operand:
140381ad6265SDimitry Andric     return generateImmOutOfRangeError(
140481ad6265SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4,
1405*bdd1243dSDimitry Andric         "operand must be a bare symbol name or an immediate must be a multiple "
1406*bdd1243dSDimitry Andric         "of 4 in the range");
1407*bdd1243dSDimitry Andric   case Match_InvalidImm32: {
1408*bdd1243dSDimitry Andric     SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
1409*bdd1243dSDimitry Andric     return Error(ErrorLoc, "operand must be a 32 bit immediate");
1410*bdd1243dSDimitry Andric   }
1411*bdd1243dSDimitry Andric   case Match_InvalidBareSymbol: {
1412*bdd1243dSDimitry Andric     SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
1413*bdd1243dSDimitry Andric     return Error(ErrorLoc, "operand must be a bare symbol name");
1414*bdd1243dSDimitry Andric   }
141581ad6265SDimitry Andric   }
141681ad6265SDimitry Andric   llvm_unreachable("Unknown match type detected!");
141781ad6265SDimitry Andric }
141881ad6265SDimitry Andric 
141981ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() {
142081ad6265SDimitry Andric   RegisterMCAsmParser<LoongArchAsmParser> X(getTheLoongArch32Target());
142181ad6265SDimitry Andric   RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target());
142281ad6265SDimitry Andric }
1423