xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp (revision 647cbc5de815c5651677bf8582797f716ec7b48d)
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"
10bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchMCExpr.h"
1181ad6265SDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h"
12bdd1243dSDimitry Andric #include "MCTargetDesc/LoongArchMatInt.h"
1381ad6265SDimitry Andric #include "TargetInfo/LoongArchTargetInfo.h"
1481ad6265SDimitry Andric #include "llvm/MC/MCContext.h"
15bdd1243dSDimitry 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"
23bdd1243dSDimitry 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(); }
34bdd1243dSDimitry Andric   bool is64Bit() const { return getSTI().hasFeature(LoongArch::Feature64Bit); }
35bdd1243dSDimitry Andric 
36bdd1243dSDimitry Andric   struct Inst {
37bdd1243dSDimitry Andric     unsigned Opc;
38bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK;
39bdd1243dSDimitry Andric     Inst(unsigned Opc,
40bdd1243dSDimitry Andric          LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None)
41bdd1243dSDimitry Andric         : Opc(Opc), VK(VK) {}
42bdd1243dSDimitry Andric   };
43bdd1243dSDimitry Andric   using InstSeq = SmallVector<Inst>;
4481ad6265SDimitry Andric 
4581ad6265SDimitry Andric   /// Parse a register as used in CFI directives.
465f757f3fSDimitry Andric   bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override;
475f757f3fSDimitry Andric   ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
4881ad6265SDimitry Andric                                SMLoc &EndLoc) override;
4981ad6265SDimitry Andric 
5081ad6265SDimitry Andric   bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
5181ad6265SDimitry Andric                         SMLoc NameLoc, OperandVector &Operands) override;
5281ad6265SDimitry Andric 
5381ad6265SDimitry Andric   bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
5481ad6265SDimitry Andric                                OperandVector &Operands, MCStreamer &Out,
5581ad6265SDimitry Andric                                uint64_t &ErrorInfo,
5681ad6265SDimitry Andric                                bool MatchingInlineAsm) override;
5781ad6265SDimitry Andric 
5881ad6265SDimitry Andric   unsigned checkTargetMatchPredicate(MCInst &Inst) override;
5981ad6265SDimitry Andric 
6081ad6265SDimitry Andric   unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
6181ad6265SDimitry Andric                                       unsigned Kind) override;
6281ad6265SDimitry Andric 
6381ad6265SDimitry Andric   bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo,
6406c3fb27SDimitry Andric                                   int64_t Lower, int64_t Upper,
6506c3fb27SDimitry Andric                                   const Twine &Msg);
6681ad6265SDimitry Andric 
6781ad6265SDimitry Andric   /// Helper for processing MC instructions that have been successfully matched
6881ad6265SDimitry Andric   /// by MatchAndEmitInstruction.
6981ad6265SDimitry Andric   bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands,
7081ad6265SDimitry Andric                           MCStreamer &Out);
7181ad6265SDimitry Andric 
7281ad6265SDimitry Andric // Auto-generated instruction matching functions.
7381ad6265SDimitry Andric #define GET_ASSEMBLER_HEADER
7481ad6265SDimitry Andric #include "LoongArchGenAsmMatcher.inc"
7581ad6265SDimitry Andric 
7606c3fb27SDimitry Andric   ParseStatus parseRegister(OperandVector &Operands);
7706c3fb27SDimitry Andric   ParseStatus parseImmediate(OperandVector &Operands);
7806c3fb27SDimitry Andric   ParseStatus parseOperandWithModifier(OperandVector &Operands);
7906c3fb27SDimitry Andric   ParseStatus parseSImm26Operand(OperandVector &Operands);
8006c3fb27SDimitry Andric   ParseStatus parseAtomicMemOp(OperandVector &Operands);
8181ad6265SDimitry Andric 
8281ad6265SDimitry Andric   bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
8381ad6265SDimitry Andric 
84bdd1243dSDimitry Andric   // Helper to emit the sequence of instructions generated by the
85bdd1243dSDimitry Andric   // "emitLoadAddress*" functions.
86bdd1243dSDimitry Andric   void emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg,
87bdd1243dSDimitry Andric                      const MCExpr *Symbol, SmallVectorImpl<Inst> &Insts,
88*647cbc5dSDimitry Andric                      SMLoc IDLoc, MCStreamer &Out, bool RelaxHint = false);
89bdd1243dSDimitry Andric 
90bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.abs $rd, sym".
91bdd1243dSDimitry Andric   void emitLoadAddressAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
92bdd1243dSDimitry Andric 
93bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.pcrel $rd, sym".
94bdd1243dSDimitry Andric   void emitLoadAddressPcrel(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
95bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.pcrel $rd, $rj, sym".
96bdd1243dSDimitry Andric   void emitLoadAddressPcrelLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
97bdd1243dSDimitry Andric 
98bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.got $rd, sym".
99bdd1243dSDimitry Andric   void emitLoadAddressGot(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
100bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.got $rd, $rj, sym".
101bdd1243dSDimitry Andric   void emitLoadAddressGotLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
102bdd1243dSDimitry Andric 
103bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.le $rd, sym".
104bdd1243dSDimitry Andric   void emitLoadAddressTLSLE(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
105bdd1243dSDimitry Andric 
106bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.ie $rd, sym".
107bdd1243dSDimitry Andric   void emitLoadAddressTLSIE(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
108bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.ie $rd, $rj, sym".
109bdd1243dSDimitry Andric   void emitLoadAddressTLSIELarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
110bdd1243dSDimitry Andric 
111bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.ld $rd, sym".
112bdd1243dSDimitry Andric   void emitLoadAddressTLSLD(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
113bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.ld $rd, $rj, sym".
114bdd1243dSDimitry Andric   void emitLoadAddressTLSLDLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
115bdd1243dSDimitry Andric 
116bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.gd $rd, sym".
117bdd1243dSDimitry Andric   void emitLoadAddressTLSGD(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
118bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "la.tls.gd $rd, $rj, sym".
119bdd1243dSDimitry Andric   void emitLoadAddressTLSGDLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
120bdd1243dSDimitry Andric 
121bdd1243dSDimitry Andric   // Helper to emit pseudo instruction "li.w/d $rd, $imm".
122bdd1243dSDimitry Andric   void emitLoadImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
123bdd1243dSDimitry Andric 
12481ad6265SDimitry Andric public:
12581ad6265SDimitry Andric   enum LoongArchMatchResultTy {
12681ad6265SDimitry Andric     Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
12781ad6265SDimitry Andric     Match_RequiresMsbNotLessThanLsb,
12881ad6265SDimitry Andric     Match_RequiresOpnd2NotR0R1,
129bdd1243dSDimitry Andric     Match_RequiresAMORdDifferRkRj,
130bdd1243dSDimitry Andric     Match_RequiresLAORdDifferRj,
13181ad6265SDimitry Andric #define GET_OPERAND_DIAGNOSTIC_TYPES
13281ad6265SDimitry Andric #include "LoongArchGenAsmMatcher.inc"
13381ad6265SDimitry Andric #undef GET_OPERAND_DIAGNOSTIC_TYPES
13481ad6265SDimitry Andric   };
13581ad6265SDimitry Andric 
136bdd1243dSDimitry Andric   static bool classifySymbolRef(const MCExpr *Expr,
137bdd1243dSDimitry Andric                                 LoongArchMCExpr::VariantKind &Kind);
138bdd1243dSDimitry Andric 
13981ad6265SDimitry Andric   LoongArchAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
14081ad6265SDimitry Andric                      const MCInstrInfo &MII, const MCTargetOptions &Options)
14181ad6265SDimitry Andric       : MCTargetAsmParser(Options, STI, MII) {
14281ad6265SDimitry Andric     Parser.addAliasForDirective(".half", ".2byte");
14381ad6265SDimitry Andric     Parser.addAliasForDirective(".hword", ".2byte");
14481ad6265SDimitry Andric     Parser.addAliasForDirective(".word", ".4byte");
14581ad6265SDimitry Andric     Parser.addAliasForDirective(".dword", ".8byte");
14681ad6265SDimitry Andric 
14781ad6265SDimitry Andric     // Initialize the set of available features.
14881ad6265SDimitry Andric     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
14981ad6265SDimitry Andric   }
15081ad6265SDimitry Andric };
15181ad6265SDimitry Andric 
15281ad6265SDimitry Andric // Instances of this class represent a parsed LoongArch machine instruction.
15381ad6265SDimitry Andric class LoongArchOperand : public MCParsedAsmOperand {
15481ad6265SDimitry Andric   enum class KindTy {
15581ad6265SDimitry Andric     Token,
15681ad6265SDimitry Andric     Register,
15781ad6265SDimitry Andric     Immediate,
15881ad6265SDimitry Andric   } Kind;
15981ad6265SDimitry Andric 
16081ad6265SDimitry Andric   struct RegOp {
16181ad6265SDimitry Andric     MCRegister RegNum;
16281ad6265SDimitry Andric   };
16381ad6265SDimitry Andric 
16481ad6265SDimitry Andric   struct ImmOp {
16581ad6265SDimitry Andric     const MCExpr *Val;
16681ad6265SDimitry Andric   };
16781ad6265SDimitry Andric 
16881ad6265SDimitry Andric   SMLoc StartLoc, EndLoc;
16981ad6265SDimitry Andric   union {
17081ad6265SDimitry Andric     StringRef Tok;
17181ad6265SDimitry Andric     struct RegOp Reg;
17281ad6265SDimitry Andric     struct ImmOp Imm;
17381ad6265SDimitry Andric   };
17481ad6265SDimitry Andric 
17581ad6265SDimitry Andric public:
17681ad6265SDimitry Andric   LoongArchOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
17781ad6265SDimitry Andric 
17881ad6265SDimitry Andric   bool isToken() const override { return Kind == KindTy::Token; }
17981ad6265SDimitry Andric   bool isReg() const override { return Kind == KindTy::Register; }
18081ad6265SDimitry Andric   bool isImm() const override { return Kind == KindTy::Immediate; }
18181ad6265SDimitry Andric   bool isMem() const override { return false; }
18281ad6265SDimitry Andric   void setReg(MCRegister PhysReg) { Reg.RegNum = PhysReg; }
183bdd1243dSDimitry Andric   bool isGPR() const {
184bdd1243dSDimitry Andric     return Kind == KindTy::Register &&
185bdd1243dSDimitry Andric            LoongArchMCRegisterClasses[LoongArch::GPRRegClassID].contains(
186bdd1243dSDimitry Andric                Reg.RegNum);
187bdd1243dSDimitry Andric   }
18881ad6265SDimitry Andric 
189bdd1243dSDimitry Andric   static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm,
190bdd1243dSDimitry Andric                                   LoongArchMCExpr::VariantKind &VK) {
191bdd1243dSDimitry Andric     if (auto *LE = dyn_cast<LoongArchMCExpr>(Expr)) {
192bdd1243dSDimitry Andric       VK = LE->getKind();
193bdd1243dSDimitry Andric       return false;
194bdd1243dSDimitry Andric     }
195bdd1243dSDimitry Andric 
19681ad6265SDimitry Andric     if (auto CE = dyn_cast<MCConstantExpr>(Expr)) {
19781ad6265SDimitry Andric       Imm = CE->getValue();
19881ad6265SDimitry Andric       return true;
19981ad6265SDimitry Andric     }
20081ad6265SDimitry Andric 
20181ad6265SDimitry Andric     return false;
20281ad6265SDimitry Andric   }
20381ad6265SDimitry Andric 
20481ad6265SDimitry Andric   template <unsigned N, int P = 0> bool isUImm() const {
20581ad6265SDimitry Andric     if (!isImm())
20681ad6265SDimitry Andric       return false;
20781ad6265SDimitry Andric 
20881ad6265SDimitry Andric     int64_t Imm;
209bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
210bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
211bdd1243dSDimitry Andric     return IsConstantImm && isUInt<N>(Imm - P) &&
212bdd1243dSDimitry Andric            VK == LoongArchMCExpr::VK_LoongArch_None;
21381ad6265SDimitry Andric   }
21481ad6265SDimitry Andric 
21581ad6265SDimitry Andric   template <unsigned N, unsigned S = 0> bool isSImm() const {
21681ad6265SDimitry Andric     if (!isImm())
21781ad6265SDimitry Andric       return false;
21881ad6265SDimitry Andric 
21981ad6265SDimitry Andric     int64_t Imm;
220bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
221bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
222bdd1243dSDimitry Andric     return IsConstantImm && isShiftedInt<N, S>(Imm) &&
223bdd1243dSDimitry Andric            VK == LoongArchMCExpr::VK_LoongArch_None;
224bdd1243dSDimitry Andric   }
225bdd1243dSDimitry Andric 
226bdd1243dSDimitry Andric   bool isBareSymbol() const {
227bdd1243dSDimitry Andric     int64_t Imm;
228bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
229bdd1243dSDimitry Andric     // Must be of 'immediate' type but not a constant.
230bdd1243dSDimitry Andric     if (!isImm() || evaluateConstantImm(getImm(), Imm, VK))
231bdd1243dSDimitry Andric       return false;
232bdd1243dSDimitry Andric     return LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
233bdd1243dSDimitry Andric            VK == LoongArchMCExpr::VK_LoongArch_None;
23481ad6265SDimitry Andric   }
23581ad6265SDimitry Andric 
23606c3fb27SDimitry Andric   bool isUImm1() const { return isUImm<1>(); }
23781ad6265SDimitry Andric   bool isUImm2() const { return isUImm<2>(); }
23881ad6265SDimitry Andric   bool isUImm2plus1() const { return isUImm<2, 1>(); }
23981ad6265SDimitry Andric   bool isUImm3() const { return isUImm<3>(); }
24006c3fb27SDimitry Andric   bool isUImm4() const { return isUImm<4>(); }
24106c3fb27SDimitry Andric   bool isSImm5() const { return isSImm<5>(); }
24281ad6265SDimitry Andric   bool isUImm5() const { return isUImm<5>(); }
24381ad6265SDimitry Andric   bool isUImm6() const { return isUImm<6>(); }
24406c3fb27SDimitry Andric   bool isUImm7() const { return isUImm<7>(); }
24506c3fb27SDimitry Andric   bool isSImm8() const { return isSImm<8>(); }
24606c3fb27SDimitry Andric   bool isSImm8lsl1() const { return isSImm<8, 1>(); }
24706c3fb27SDimitry Andric   bool isSImm8lsl2() const { return isSImm<8, 2>(); }
24806c3fb27SDimitry Andric   bool isSImm8lsl3() const { return isSImm<8, 3>(); }
24981ad6265SDimitry Andric   bool isUImm8() const { return isUImm<8>(); }
25006c3fb27SDimitry Andric   bool isSImm9lsl3() const { return isSImm<9, 3>(); }
25106c3fb27SDimitry Andric   bool isSImm10() const { return isSImm<10>(); }
25206c3fb27SDimitry Andric   bool isSImm10lsl2() const { return isSImm<10, 2>(); }
25306c3fb27SDimitry Andric   bool isSImm11lsl1() const { return isSImm<11, 1>(); }
254bdd1243dSDimitry Andric   bool isSImm12() const { return isSImm<12>(); }
255bdd1243dSDimitry Andric 
256bdd1243dSDimitry Andric   bool isSImm12addlike() const {
257bdd1243dSDimitry Andric     if (!isImm())
258bdd1243dSDimitry Andric       return false;
259bdd1243dSDimitry Andric 
260bdd1243dSDimitry Andric     int64_t Imm;
261bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
262bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
263bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
264bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12 ||
265bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12 ||
266bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12;
267bdd1243dSDimitry Andric     return IsConstantImm
268bdd1243dSDimitry Andric                ? isInt<12>(Imm) && IsValidKind
269bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
270bdd1243dSDimitry Andric                      IsValidKind;
271bdd1243dSDimitry Andric   }
272bdd1243dSDimitry Andric 
273bdd1243dSDimitry Andric   bool isSImm12lu52id() const {
274bdd1243dSDimitry Andric     if (!isImm())
275bdd1243dSDimitry Andric       return false;
276bdd1243dSDimitry Andric 
277bdd1243dSDimitry Andric     int64_t Imm;
278bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
279bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
280bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
281bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_ABS64_HI12 ||
282bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_PCALA64_HI12 ||
283bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT64_HI12 ||
284bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12 ||
285bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_LE64_HI12 ||
286bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_HI12 ||
287bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_HI12;
288bdd1243dSDimitry Andric     return IsConstantImm
289bdd1243dSDimitry Andric                ? isInt<12>(Imm) && IsValidKind
290bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
291bdd1243dSDimitry Andric                      IsValidKind;
292bdd1243dSDimitry Andric   }
293bdd1243dSDimitry Andric 
29481ad6265SDimitry Andric   bool isUImm12() const { return isUImm<12>(); }
295bdd1243dSDimitry Andric 
296bdd1243dSDimitry Andric   bool isUImm12ori() const {
297bdd1243dSDimitry Andric     if (!isImm())
298bdd1243dSDimitry Andric       return false;
299bdd1243dSDimitry Andric 
300bdd1243dSDimitry Andric     int64_t Imm;
301bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
302bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
303bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
304bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_ABS_LO12 ||
305bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12 ||
306bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT_LO12 ||
307bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12 ||
308bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_LO12 ||
309bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_LO12 ||
310bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12;
311bdd1243dSDimitry Andric     return IsConstantImm
312bdd1243dSDimitry Andric                ? isUInt<12>(Imm) && IsValidKind
313bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
314bdd1243dSDimitry Andric                      IsValidKind;
315bdd1243dSDimitry Andric   }
316bdd1243dSDimitry Andric 
31706c3fb27SDimitry Andric   bool isSImm13() const { return isSImm<13>(); }
31881ad6265SDimitry Andric   bool isUImm14() const { return isUImm<14>(); }
31981ad6265SDimitry Andric   bool isUImm15() const { return isUImm<15>(); }
320bdd1243dSDimitry Andric 
32181ad6265SDimitry Andric   bool isSImm14lsl2() const { return isSImm<14, 2>(); }
32281ad6265SDimitry Andric   bool isSImm16() const { return isSImm<16>(); }
323bdd1243dSDimitry Andric 
324bdd1243dSDimitry Andric   bool isSImm16lsl2() const {
325bdd1243dSDimitry Andric     if (!isImm())
326bdd1243dSDimitry Andric       return false;
327bdd1243dSDimitry Andric 
328bdd1243dSDimitry Andric     int64_t Imm;
329bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
330bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
331bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
332bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_B16 ||
333bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12;
334bdd1243dSDimitry Andric     return IsConstantImm
335bdd1243dSDimitry Andric                ? isShiftedInt<16, 2>(Imm) && IsValidKind
336bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
337bdd1243dSDimitry Andric                      IsValidKind;
338bdd1243dSDimitry Andric   }
339bdd1243dSDimitry Andric 
34081ad6265SDimitry Andric   bool isSImm20() const { return isSImm<20>(); }
341bdd1243dSDimitry Andric 
342bdd1243dSDimitry Andric   bool isSImm20pcalau12i() const {
343bdd1243dSDimitry Andric     if (!isImm())
344bdd1243dSDimitry Andric       return false;
345bdd1243dSDimitry Andric 
346bdd1243dSDimitry Andric     int64_t Imm;
347bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
348bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
349bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
350bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_PCALA_HI20 ||
351bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20 ||
352bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20 ||
353bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20 ||
354bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20;
355bdd1243dSDimitry Andric     return IsConstantImm
356bdd1243dSDimitry Andric                ? isInt<20>(Imm) && IsValidKind
357bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
358bdd1243dSDimitry Andric                      IsValidKind;
359bdd1243dSDimitry Andric   }
360bdd1243dSDimitry Andric 
361bdd1243dSDimitry Andric   bool isSImm20lu12iw() const {
362bdd1243dSDimitry Andric     if (!isImm())
363bdd1243dSDimitry Andric       return false;
364bdd1243dSDimitry Andric 
365bdd1243dSDimitry Andric     int64_t Imm;
366bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
367bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
368bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
369bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_ABS_HI20 ||
370bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT_HI20 ||
371bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_GD_HI20 ||
372bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_LD_HI20 ||
373bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_HI20 ||
374bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_HI20;
375bdd1243dSDimitry Andric     return IsConstantImm
376bdd1243dSDimitry Andric                ? isInt<20>(Imm) && IsValidKind
377bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
378bdd1243dSDimitry Andric                      IsValidKind;
379bdd1243dSDimitry Andric   }
380bdd1243dSDimitry Andric 
381bdd1243dSDimitry Andric   bool isSImm20lu32id() const {
382bdd1243dSDimitry Andric     if (!isImm())
383bdd1243dSDimitry Andric       return false;
384bdd1243dSDimitry Andric 
385bdd1243dSDimitry Andric     int64_t Imm;
386bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
387bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
388bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
389bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_ABS64_LO20 ||
390bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_PCALA64_LO20 ||
391bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT64_LO20 ||
392bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20 ||
393bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_LO20 ||
394bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_LO20 ||
395bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_TLS_LE64_LO20;
396bdd1243dSDimitry Andric 
397bdd1243dSDimitry Andric     return IsConstantImm
398bdd1243dSDimitry Andric                ? isInt<20>(Imm) && IsValidKind
399bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
400bdd1243dSDimitry Andric                      IsValidKind;
401bdd1243dSDimitry Andric   }
402bdd1243dSDimitry Andric 
403bdd1243dSDimitry Andric   bool isSImm21lsl2() const {
404bdd1243dSDimitry Andric     if (!isImm())
405bdd1243dSDimitry Andric       return false;
406bdd1243dSDimitry Andric 
407bdd1243dSDimitry Andric     int64_t Imm;
408bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
409bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
410bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
411bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_B21;
412bdd1243dSDimitry Andric     return IsConstantImm
413bdd1243dSDimitry Andric                ? isShiftedInt<21, 2>(Imm) && IsValidKind
414bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
415bdd1243dSDimitry Andric                      IsValidKind;
416bdd1243dSDimitry Andric   }
417bdd1243dSDimitry Andric 
418bdd1243dSDimitry Andric   bool isSImm26Operand() const {
419bdd1243dSDimitry Andric     if (!isImm())
420bdd1243dSDimitry Andric       return false;
421bdd1243dSDimitry Andric 
422bdd1243dSDimitry Andric     int64_t Imm;
423bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
424bdd1243dSDimitry Andric     bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
425bdd1243dSDimitry Andric     bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
426bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_CALL ||
427bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_CALL_PLT ||
428bdd1243dSDimitry Andric                        VK == LoongArchMCExpr::VK_LoongArch_B26;
429bdd1243dSDimitry Andric     return IsConstantImm
430bdd1243dSDimitry Andric                ? isShiftedInt<26, 2>(Imm) && IsValidKind
431bdd1243dSDimitry Andric                : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
432bdd1243dSDimitry Andric                      IsValidKind;
433bdd1243dSDimitry Andric   }
434bdd1243dSDimitry Andric 
435bdd1243dSDimitry Andric   bool isImm32() const { return isSImm<32>() || isUImm<32>(); }
43681ad6265SDimitry Andric 
43781ad6265SDimitry Andric   /// Gets location of the first token of this operand.
43881ad6265SDimitry Andric   SMLoc getStartLoc() const override { return StartLoc; }
43981ad6265SDimitry Andric   /// Gets location of the last token of this operand.
44081ad6265SDimitry Andric   SMLoc getEndLoc() const override { return EndLoc; }
44181ad6265SDimitry Andric 
44281ad6265SDimitry Andric   unsigned getReg() const override {
44381ad6265SDimitry Andric     assert(Kind == KindTy::Register && "Invalid type access!");
44481ad6265SDimitry Andric     return Reg.RegNum.id();
44581ad6265SDimitry Andric   }
44681ad6265SDimitry Andric 
44781ad6265SDimitry Andric   const MCExpr *getImm() const {
44881ad6265SDimitry Andric     assert(Kind == KindTy::Immediate && "Invalid type access!");
44981ad6265SDimitry Andric     return Imm.Val;
45081ad6265SDimitry Andric   }
45181ad6265SDimitry Andric 
45281ad6265SDimitry Andric   StringRef getToken() const {
45381ad6265SDimitry Andric     assert(Kind == KindTy::Token && "Invalid type access!");
45481ad6265SDimitry Andric     return Tok;
45581ad6265SDimitry Andric   }
45681ad6265SDimitry Andric 
45781ad6265SDimitry Andric   void print(raw_ostream &OS) const override {
458bdd1243dSDimitry Andric     auto RegName = [](MCRegister Reg) {
45981ad6265SDimitry Andric       if (Reg)
46081ad6265SDimitry Andric         return LoongArchInstPrinter::getRegisterName(Reg);
46181ad6265SDimitry Andric       else
46281ad6265SDimitry Andric         return "noreg";
46381ad6265SDimitry Andric     };
46481ad6265SDimitry Andric 
46581ad6265SDimitry Andric     switch (Kind) {
46681ad6265SDimitry Andric     case KindTy::Immediate:
46781ad6265SDimitry Andric       OS << *getImm();
46881ad6265SDimitry Andric       break;
46981ad6265SDimitry Andric     case KindTy::Register:
47081ad6265SDimitry Andric       OS << "<register " << RegName(getReg()) << ">";
47181ad6265SDimitry Andric       break;
47281ad6265SDimitry Andric     case KindTy::Token:
47381ad6265SDimitry Andric       OS << "'" << getToken() << "'";
47481ad6265SDimitry Andric       break;
47581ad6265SDimitry Andric     }
47681ad6265SDimitry Andric   }
47781ad6265SDimitry Andric 
47881ad6265SDimitry Andric   static std::unique_ptr<LoongArchOperand> createToken(StringRef Str, SMLoc S) {
47981ad6265SDimitry Andric     auto Op = std::make_unique<LoongArchOperand>(KindTy::Token);
48081ad6265SDimitry Andric     Op->Tok = Str;
48181ad6265SDimitry Andric     Op->StartLoc = S;
48281ad6265SDimitry Andric     Op->EndLoc = S;
48381ad6265SDimitry Andric     return Op;
48481ad6265SDimitry Andric   }
48581ad6265SDimitry Andric 
48681ad6265SDimitry Andric   static std::unique_ptr<LoongArchOperand> createReg(unsigned RegNo, SMLoc S,
48781ad6265SDimitry Andric                                                      SMLoc E) {
48881ad6265SDimitry Andric     auto Op = std::make_unique<LoongArchOperand>(KindTy::Register);
48981ad6265SDimitry Andric     Op->Reg.RegNum = RegNo;
49081ad6265SDimitry Andric     Op->StartLoc = S;
49181ad6265SDimitry Andric     Op->EndLoc = E;
49281ad6265SDimitry Andric     return Op;
49381ad6265SDimitry Andric   }
49481ad6265SDimitry Andric 
49581ad6265SDimitry Andric   static std::unique_ptr<LoongArchOperand> createImm(const MCExpr *Val, SMLoc S,
49681ad6265SDimitry Andric                                                      SMLoc E) {
49781ad6265SDimitry Andric     auto Op = std::make_unique<LoongArchOperand>(KindTy::Immediate);
49881ad6265SDimitry Andric     Op->Imm.Val = Val;
49981ad6265SDimitry Andric     Op->StartLoc = S;
50081ad6265SDimitry Andric     Op->EndLoc = E;
50181ad6265SDimitry Andric     return Op;
50281ad6265SDimitry Andric   }
50381ad6265SDimitry Andric 
50481ad6265SDimitry Andric   void addExpr(MCInst &Inst, const MCExpr *Expr) const {
50581ad6265SDimitry Andric     if (auto CE = dyn_cast<MCConstantExpr>(Expr))
50681ad6265SDimitry Andric       Inst.addOperand(MCOperand::createImm(CE->getValue()));
50781ad6265SDimitry Andric     else
50881ad6265SDimitry Andric       Inst.addOperand(MCOperand::createExpr(Expr));
50981ad6265SDimitry Andric   }
51081ad6265SDimitry Andric 
51181ad6265SDimitry Andric   // Used by the TableGen Code.
51281ad6265SDimitry Andric   void addRegOperands(MCInst &Inst, unsigned N) const {
51381ad6265SDimitry Andric     assert(N == 1 && "Invalid number of operands!");
51481ad6265SDimitry Andric     Inst.addOperand(MCOperand::createReg(getReg()));
51581ad6265SDimitry Andric   }
51681ad6265SDimitry Andric   void addImmOperands(MCInst &Inst, unsigned N) const {
51781ad6265SDimitry Andric     assert(N == 1 && "Invalid number of operands!");
51881ad6265SDimitry Andric     addExpr(Inst, getImm());
51981ad6265SDimitry Andric   }
52081ad6265SDimitry Andric };
521972a253aSDimitry Andric } // end namespace
52281ad6265SDimitry Andric 
52381ad6265SDimitry Andric #define GET_REGISTER_MATCHER
52481ad6265SDimitry Andric #define GET_SUBTARGET_FEATURE_NAME
52581ad6265SDimitry Andric #define GET_MATCHER_IMPLEMENTATION
52681ad6265SDimitry Andric #define GET_MNEMONIC_SPELL_CHECKER
52781ad6265SDimitry Andric #include "LoongArchGenAsmMatcher.inc"
52881ad6265SDimitry Andric 
52981ad6265SDimitry Andric static MCRegister convertFPR32ToFPR64(MCRegister Reg) {
53081ad6265SDimitry Andric   assert(Reg >= LoongArch::F0 && Reg <= LoongArch::F31 && "Invalid register");
53181ad6265SDimitry Andric   return Reg - LoongArch::F0 + LoongArch::F0_64;
53281ad6265SDimitry Andric }
53381ad6265SDimitry Andric 
53481ad6265SDimitry Andric // Attempts to match Name as a register (either using the default name or
53581ad6265SDimitry Andric // alternative ABI names), setting RegNo to the matching register. Upon
53681ad6265SDimitry Andric // failure, returns true and sets RegNo to 0.
53781ad6265SDimitry Andric static bool matchRegisterNameHelper(MCRegister &RegNo, StringRef Name) {
53881ad6265SDimitry Andric   RegNo = MatchRegisterName(Name);
53981ad6265SDimitry Andric   // The 32-bit and 64-bit FPRs have the same asm name. Check that the initial
54081ad6265SDimitry Andric   // match always matches the 32-bit variant, and not the 64-bit one.
54181ad6265SDimitry Andric   assert(!(RegNo >= LoongArch::F0_64 && RegNo <= LoongArch::F31_64));
54281ad6265SDimitry Andric   // The default FPR register class is based on the tablegen enum ordering.
54381ad6265SDimitry Andric   static_assert(LoongArch::F0 < LoongArch::F0_64,
54481ad6265SDimitry Andric                 "FPR matching must be updated");
54581ad6265SDimitry Andric   if (RegNo == LoongArch::NoRegister)
54681ad6265SDimitry Andric     RegNo = MatchRegisterAltName(Name);
54781ad6265SDimitry Andric 
54881ad6265SDimitry Andric   return RegNo == LoongArch::NoRegister;
54981ad6265SDimitry Andric }
55081ad6265SDimitry Andric 
5515f757f3fSDimitry Andric bool LoongArchAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,
55281ad6265SDimitry Andric                                        SMLoc &EndLoc) {
55381ad6265SDimitry Andric   return Error(getLoc(), "invalid register number");
55481ad6265SDimitry Andric }
55581ad6265SDimitry Andric 
5565f757f3fSDimitry Andric ParseStatus LoongArchAsmParser::tryParseRegister(MCRegister &Reg,
55781ad6265SDimitry Andric                                                  SMLoc &StartLoc,
55881ad6265SDimitry Andric                                                  SMLoc &EndLoc) {
55981ad6265SDimitry Andric   llvm_unreachable("Unimplemented function.");
56081ad6265SDimitry Andric }
56181ad6265SDimitry Andric 
562bdd1243dSDimitry Andric bool LoongArchAsmParser::classifySymbolRef(const MCExpr *Expr,
563bdd1243dSDimitry Andric                                            LoongArchMCExpr::VariantKind &Kind) {
564bdd1243dSDimitry Andric   Kind = LoongArchMCExpr::VK_LoongArch_None;
565bdd1243dSDimitry Andric 
566bdd1243dSDimitry Andric   if (const LoongArchMCExpr *RE = dyn_cast<LoongArchMCExpr>(Expr)) {
567bdd1243dSDimitry Andric     Kind = RE->getKind();
568bdd1243dSDimitry Andric     Expr = RE->getSubExpr();
569bdd1243dSDimitry Andric   }
570bdd1243dSDimitry Andric 
571bdd1243dSDimitry Andric   MCValue Res;
572bdd1243dSDimitry Andric   if (Expr->evaluateAsRelocatable(Res, nullptr, nullptr))
573bdd1243dSDimitry Andric     return Res.getRefKind() == LoongArchMCExpr::VK_LoongArch_None;
574bdd1243dSDimitry Andric   return false;
575bdd1243dSDimitry Andric }
576bdd1243dSDimitry Andric 
57706c3fb27SDimitry Andric ParseStatus LoongArchAsmParser::parseRegister(OperandVector &Operands) {
57806c3fb27SDimitry Andric   if (!parseOptionalToken(AsmToken::Dollar))
57906c3fb27SDimitry Andric     return ParseStatus::NoMatch;
58081ad6265SDimitry Andric   if (getLexer().getKind() != AsmToken::Identifier)
58106c3fb27SDimitry Andric     return ParseStatus::NoMatch;
58281ad6265SDimitry Andric 
58381ad6265SDimitry Andric   StringRef Name = getLexer().getTok().getIdentifier();
58481ad6265SDimitry Andric   MCRegister RegNo;
58581ad6265SDimitry Andric   matchRegisterNameHelper(RegNo, Name);
58681ad6265SDimitry Andric   if (RegNo == LoongArch::NoRegister)
58706c3fb27SDimitry Andric     return ParseStatus::NoMatch;
58881ad6265SDimitry Andric 
58981ad6265SDimitry Andric   SMLoc S = getLoc();
59081ad6265SDimitry Andric   SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size());
59181ad6265SDimitry Andric   getLexer().Lex();
59281ad6265SDimitry Andric   Operands.push_back(LoongArchOperand::createReg(RegNo, S, E));
59381ad6265SDimitry Andric 
59406c3fb27SDimitry Andric   return ParseStatus::Success;
59581ad6265SDimitry Andric }
59681ad6265SDimitry Andric 
59706c3fb27SDimitry Andric ParseStatus LoongArchAsmParser::parseImmediate(OperandVector &Operands) {
59881ad6265SDimitry Andric   SMLoc S = getLoc();
59981ad6265SDimitry Andric   SMLoc E;
60081ad6265SDimitry Andric   const MCExpr *Res;
60181ad6265SDimitry Andric 
602bdd1243dSDimitry Andric   switch (getLexer().getKind()) {
603bdd1243dSDimitry Andric   default:
60406c3fb27SDimitry Andric     return ParseStatus::NoMatch;
605bdd1243dSDimitry Andric   case AsmToken::LParen:
606bdd1243dSDimitry Andric   case AsmToken::Dot:
607bdd1243dSDimitry Andric   case AsmToken::Minus:
608bdd1243dSDimitry Andric   case AsmToken::Plus:
609bdd1243dSDimitry Andric   case AsmToken::Exclaim:
610bdd1243dSDimitry Andric   case AsmToken::Tilde:
611bdd1243dSDimitry Andric   case AsmToken::Integer:
612bdd1243dSDimitry Andric   case AsmToken::String:
613bdd1243dSDimitry Andric   case AsmToken::Identifier:
61481ad6265SDimitry Andric     if (getParser().parseExpression(Res, E))
61506c3fb27SDimitry Andric       return ParseStatus::Failure;
616bdd1243dSDimitry Andric     break;
617bdd1243dSDimitry Andric   case AsmToken::Percent:
618bdd1243dSDimitry Andric     return parseOperandWithModifier(Operands);
619bdd1243dSDimitry Andric   }
62081ad6265SDimitry Andric 
62181ad6265SDimitry Andric   Operands.push_back(LoongArchOperand::createImm(Res, S, E));
62206c3fb27SDimitry Andric   return ParseStatus::Success;
62381ad6265SDimitry Andric }
62481ad6265SDimitry Andric 
62506c3fb27SDimitry Andric ParseStatus
626bdd1243dSDimitry Andric LoongArchAsmParser::parseOperandWithModifier(OperandVector &Operands) {
627bdd1243dSDimitry Andric   SMLoc S = getLoc();
628bdd1243dSDimitry Andric   SMLoc E;
629bdd1243dSDimitry Andric 
63006c3fb27SDimitry Andric   if (getLexer().getKind() != AsmToken::Percent)
63106c3fb27SDimitry Andric     return Error(getLoc(), "expected '%' for operand modifier");
632bdd1243dSDimitry Andric 
633bdd1243dSDimitry Andric   getParser().Lex(); // Eat '%'
634bdd1243dSDimitry Andric 
63506c3fb27SDimitry Andric   if (getLexer().getKind() != AsmToken::Identifier)
63606c3fb27SDimitry Andric     return Error(getLoc(), "expected valid identifier for operand modifier");
637bdd1243dSDimitry Andric   StringRef Identifier = getParser().getTok().getIdentifier();
638bdd1243dSDimitry Andric   LoongArchMCExpr::VariantKind VK =
639bdd1243dSDimitry Andric       LoongArchMCExpr::getVariantKindForName(Identifier);
64006c3fb27SDimitry Andric   if (VK == LoongArchMCExpr::VK_LoongArch_Invalid)
64106c3fb27SDimitry Andric     return Error(getLoc(), "unrecognized operand modifier");
642bdd1243dSDimitry Andric 
643bdd1243dSDimitry Andric   getParser().Lex(); // Eat the identifier
64406c3fb27SDimitry Andric   if (getLexer().getKind() != AsmToken::LParen)
64506c3fb27SDimitry Andric     return Error(getLoc(), "expected '('");
646bdd1243dSDimitry Andric   getParser().Lex(); // Eat '('
647bdd1243dSDimitry Andric 
648bdd1243dSDimitry Andric   const MCExpr *SubExpr;
64906c3fb27SDimitry Andric   if (getParser().parseParenExpression(SubExpr, E))
65006c3fb27SDimitry Andric     return ParseStatus::Failure;
651bdd1243dSDimitry Andric 
652bdd1243dSDimitry Andric   const MCExpr *ModExpr = LoongArchMCExpr::create(SubExpr, VK, getContext());
653bdd1243dSDimitry Andric   Operands.push_back(LoongArchOperand::createImm(ModExpr, S, E));
65406c3fb27SDimitry Andric   return ParseStatus::Success;
655bdd1243dSDimitry Andric }
656bdd1243dSDimitry Andric 
65706c3fb27SDimitry Andric ParseStatus LoongArchAsmParser::parseSImm26Operand(OperandVector &Operands) {
658bdd1243dSDimitry Andric   SMLoc S = getLoc();
659bdd1243dSDimitry Andric   const MCExpr *Res;
660bdd1243dSDimitry Andric 
661bdd1243dSDimitry Andric   if (getLexer().getKind() == AsmToken::Percent)
662bdd1243dSDimitry Andric     return parseOperandWithModifier(Operands);
663bdd1243dSDimitry Andric 
664bdd1243dSDimitry Andric   if (getLexer().getKind() != AsmToken::Identifier)
66506c3fb27SDimitry Andric     return ParseStatus::NoMatch;
666bdd1243dSDimitry Andric 
667bdd1243dSDimitry Andric   StringRef Identifier;
668bdd1243dSDimitry Andric   if (getParser().parseIdentifier(Identifier))
66906c3fb27SDimitry Andric     return ParseStatus::Failure;
670bdd1243dSDimitry Andric 
671bdd1243dSDimitry Andric   SMLoc E = SMLoc::getFromPointer(S.getPointer() + Identifier.size());
672bdd1243dSDimitry Andric 
673bdd1243dSDimitry Andric   MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
674bdd1243dSDimitry Andric   Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
675bdd1243dSDimitry Andric   Res = LoongArchMCExpr::create(Res, LoongArchMCExpr::VK_LoongArch_CALL,
676bdd1243dSDimitry Andric                                 getContext());
677bdd1243dSDimitry Andric   Operands.push_back(LoongArchOperand::createImm(Res, S, E));
67806c3fb27SDimitry Andric   return ParseStatus::Success;
679bdd1243dSDimitry Andric }
680bdd1243dSDimitry Andric 
68106c3fb27SDimitry Andric ParseStatus LoongArchAsmParser::parseAtomicMemOp(OperandVector &Operands) {
682bdd1243dSDimitry Andric   // Parse "$r*".
68306c3fb27SDimitry Andric   if (!parseRegister(Operands).isSuccess())
68406c3fb27SDimitry Andric     return ParseStatus::NoMatch;
685bdd1243dSDimitry Andric 
686bdd1243dSDimitry Andric   // If there is a next operand and it is 0, ignore it. Otherwise print a
687bdd1243dSDimitry Andric   // diagnostic message.
68806c3fb27SDimitry Andric   if (parseOptionalToken(AsmToken::Comma)) {
689bdd1243dSDimitry Andric     int64_t ImmVal;
690bdd1243dSDimitry Andric     SMLoc ImmStart = getLoc();
691bdd1243dSDimitry Andric     if (getParser().parseIntToken(ImmVal, "expected optional integer offset"))
69206c3fb27SDimitry Andric       return ParseStatus::Failure;
69306c3fb27SDimitry Andric     if (ImmVal)
69406c3fb27SDimitry Andric       return Error(ImmStart, "optional integer offset must be 0");
695bdd1243dSDimitry Andric   }
696bdd1243dSDimitry Andric 
69706c3fb27SDimitry Andric   return ParseStatus::Success;
698bdd1243dSDimitry Andric }
69981ad6265SDimitry Andric /// Looks at a token type and creates the relevant operand from this
70081ad6265SDimitry Andric /// information, adding to Operands. Return true upon an error.
70181ad6265SDimitry Andric bool LoongArchAsmParser::parseOperand(OperandVector &Operands,
70281ad6265SDimitry Andric                                       StringRef Mnemonic) {
703bdd1243dSDimitry Andric   // Check if the current operand has a custom associated parser, if so, try to
704bdd1243dSDimitry Andric   // custom parse the operand, or fallback to the general approach.
70506c3fb27SDimitry Andric   ParseStatus Result =
706bdd1243dSDimitry Andric       MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/true);
70706c3fb27SDimitry Andric   if (Result.isSuccess())
708bdd1243dSDimitry Andric     return false;
70906c3fb27SDimitry Andric   if (Result.isFailure())
710bdd1243dSDimitry Andric     return true;
711bdd1243dSDimitry Andric 
71206c3fb27SDimitry Andric   if (parseRegister(Operands).isSuccess() ||
71306c3fb27SDimitry Andric       parseImmediate(Operands).isSuccess())
71481ad6265SDimitry Andric     return false;
71581ad6265SDimitry Andric 
71681ad6265SDimitry Andric   // Finally we have exhausted all options and must declare defeat.
71706c3fb27SDimitry Andric   return Error(getLoc(), "unknown operand");
71881ad6265SDimitry Andric }
71981ad6265SDimitry Andric 
72081ad6265SDimitry Andric bool LoongArchAsmParser::ParseInstruction(ParseInstructionInfo &Info,
72181ad6265SDimitry Andric                                           StringRef Name, SMLoc NameLoc,
72281ad6265SDimitry Andric                                           OperandVector &Operands) {
72381ad6265SDimitry Andric   // First operand in MCInst is instruction mnemonic.
72481ad6265SDimitry Andric   Operands.push_back(LoongArchOperand::createToken(Name, NameLoc));
72581ad6265SDimitry Andric 
72681ad6265SDimitry Andric   // If there are no more operands, then finish.
72781ad6265SDimitry Andric   if (parseOptionalToken(AsmToken::EndOfStatement))
72881ad6265SDimitry Andric     return false;
72981ad6265SDimitry Andric 
73081ad6265SDimitry Andric   // Parse first operand.
73181ad6265SDimitry Andric   if (parseOperand(Operands, Name))
73281ad6265SDimitry Andric     return true;
73381ad6265SDimitry Andric 
73481ad6265SDimitry Andric   // Parse until end of statement, consuming commas between operands.
73581ad6265SDimitry Andric   while (parseOptionalToken(AsmToken::Comma))
73681ad6265SDimitry Andric     if (parseOperand(Operands, Name))
73781ad6265SDimitry Andric       return true;
73881ad6265SDimitry Andric 
73981ad6265SDimitry Andric   // Parse end of statement and return successfully.
74081ad6265SDimitry Andric   if (parseOptionalToken(AsmToken::EndOfStatement))
74181ad6265SDimitry Andric     return false;
74281ad6265SDimitry Andric 
74381ad6265SDimitry Andric   SMLoc Loc = getLexer().getLoc();
74481ad6265SDimitry Andric   getParser().eatToEndOfStatement();
74581ad6265SDimitry Andric   return Error(Loc, "unexpected token");
74681ad6265SDimitry Andric }
74781ad6265SDimitry Andric 
748bdd1243dSDimitry Andric void LoongArchAsmParser::emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg,
749bdd1243dSDimitry Andric                                        const MCExpr *Symbol,
750bdd1243dSDimitry Andric                                        SmallVectorImpl<Inst> &Insts,
751*647cbc5dSDimitry Andric                                        SMLoc IDLoc, MCStreamer &Out,
752*647cbc5dSDimitry Andric                                        bool RelaxHint) {
753bdd1243dSDimitry Andric   MCContext &Ctx = getContext();
754bdd1243dSDimitry Andric   for (LoongArchAsmParser::Inst &Inst : Insts) {
755bdd1243dSDimitry Andric     unsigned Opc = Inst.Opc;
756bdd1243dSDimitry Andric     LoongArchMCExpr::VariantKind VK = Inst.VK;
757*647cbc5dSDimitry Andric     const LoongArchMCExpr *LE =
758*647cbc5dSDimitry Andric         LoongArchMCExpr::create(Symbol, VK, Ctx, RelaxHint);
759bdd1243dSDimitry Andric     switch (Opc) {
760bdd1243dSDimitry Andric     default:
761bdd1243dSDimitry Andric       llvm_unreachable("unexpected opcode");
762bdd1243dSDimitry Andric     case LoongArch::PCALAU12I:
763bdd1243dSDimitry Andric     case LoongArch::LU12I_W:
764bdd1243dSDimitry Andric       Out.emitInstruction(MCInstBuilder(Opc).addReg(DestReg).addExpr(LE),
765bdd1243dSDimitry Andric                           getSTI());
766bdd1243dSDimitry Andric       break;
767bdd1243dSDimitry Andric     case LoongArch::ORI:
768bdd1243dSDimitry Andric     case LoongArch::ADDI_W:
769bdd1243dSDimitry Andric     case LoongArch::LD_W:
770bdd1243dSDimitry Andric     case LoongArch::LD_D: {
771bdd1243dSDimitry Andric       if (VK == LoongArchMCExpr::VK_LoongArch_None) {
772bdd1243dSDimitry Andric         Out.emitInstruction(
773bdd1243dSDimitry Andric             MCInstBuilder(Opc).addReg(DestReg).addReg(DestReg).addImm(0),
774bdd1243dSDimitry Andric             getSTI());
775bdd1243dSDimitry Andric         continue;
776bdd1243dSDimitry Andric       }
777bdd1243dSDimitry Andric       Out.emitInstruction(
778bdd1243dSDimitry Andric           MCInstBuilder(Opc).addReg(DestReg).addReg(DestReg).addExpr(LE),
779bdd1243dSDimitry Andric           getSTI());
780bdd1243dSDimitry Andric       break;
781bdd1243dSDimitry Andric     }
782bdd1243dSDimitry Andric     case LoongArch::LU32I_D:
783bdd1243dSDimitry Andric       Out.emitInstruction(MCInstBuilder(Opc)
784bdd1243dSDimitry Andric                               .addReg(DestReg == TmpReg ? DestReg : TmpReg)
785bdd1243dSDimitry Andric                               .addReg(DestReg == TmpReg ? DestReg : TmpReg)
786bdd1243dSDimitry Andric                               .addExpr(LE),
787bdd1243dSDimitry Andric                           getSTI());
788bdd1243dSDimitry Andric       break;
789bdd1243dSDimitry Andric     case LoongArch::LU52I_D:
790bdd1243dSDimitry Andric       Out.emitInstruction(
791bdd1243dSDimitry Andric           MCInstBuilder(Opc).addReg(TmpReg).addReg(TmpReg).addExpr(LE),
792bdd1243dSDimitry Andric           getSTI());
793bdd1243dSDimitry Andric       break;
794bdd1243dSDimitry Andric     case LoongArch::ADDI_D:
795bdd1243dSDimitry Andric       Out.emitInstruction(
796bdd1243dSDimitry Andric           MCInstBuilder(Opc)
797bdd1243dSDimitry Andric               .addReg(TmpReg)
798bdd1243dSDimitry Andric               .addReg(DestReg == TmpReg ? TmpReg : LoongArch::R0)
799bdd1243dSDimitry Andric               .addExpr(LE),
800bdd1243dSDimitry Andric           getSTI());
801bdd1243dSDimitry Andric       break;
802bdd1243dSDimitry Andric     case LoongArch::ADD_D:
803bdd1243dSDimitry Andric     case LoongArch::LDX_D:
804bdd1243dSDimitry Andric       Out.emitInstruction(
805bdd1243dSDimitry Andric           MCInstBuilder(Opc).addReg(DestReg).addReg(DestReg).addReg(TmpReg),
806bdd1243dSDimitry Andric           getSTI());
807bdd1243dSDimitry Andric       break;
808bdd1243dSDimitry Andric     }
809bdd1243dSDimitry Andric   }
810bdd1243dSDimitry Andric }
811bdd1243dSDimitry Andric 
812bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressAbs(MCInst &Inst, SMLoc IDLoc,
813bdd1243dSDimitry Andric                                             MCStreamer &Out) {
814bdd1243dSDimitry Andric   // la.abs $rd, sym
815bdd1243dSDimitry Andric   // expands to:
816bdd1243dSDimitry Andric   //   lu12i.w $rd, %abs_hi20(sym)
817bdd1243dSDimitry Andric   //   ori     $rd, $rd, %abs_lo12(sym)
818bdd1243dSDimitry Andric   //
819bdd1243dSDimitry Andric   // for 64bit appends:
820bdd1243dSDimitry Andric   //   lu32i.d $rd, %abs64_lo20(sym)
821bdd1243dSDimitry Andric   //   lu52i.d $rd, $rd, %abs64_hi12(sym)
822bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
823bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOpcode() == LoongArch::PseudoLA_ABS
824bdd1243dSDimitry Andric                              ? Inst.getOperand(1).getExpr()
825bdd1243dSDimitry Andric                              : Inst.getOperand(2).getExpr();
826bdd1243dSDimitry Andric   InstSeq Insts;
827bdd1243dSDimitry Andric 
828bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
829bdd1243dSDimitry Andric       LoongArch::LU12I_W, LoongArchMCExpr::VK_LoongArch_ABS_HI20));
830bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
831bdd1243dSDimitry Andric       LoongArch::ORI, LoongArchMCExpr::VK_LoongArch_ABS_LO12));
832bdd1243dSDimitry Andric 
833bdd1243dSDimitry Andric   if (is64Bit()) {
834bdd1243dSDimitry Andric     Insts.push_back(LoongArchAsmParser::Inst(
835bdd1243dSDimitry Andric         LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_ABS64_LO20));
836bdd1243dSDimitry Andric     Insts.push_back(LoongArchAsmParser::Inst(
837bdd1243dSDimitry Andric         LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_ABS64_HI12));
838bdd1243dSDimitry Andric   }
839bdd1243dSDimitry Andric 
840bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
841bdd1243dSDimitry Andric }
842bdd1243dSDimitry Andric 
843bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressPcrel(MCInst &Inst, SMLoc IDLoc,
844bdd1243dSDimitry Andric                                               MCStreamer &Out) {
845bdd1243dSDimitry Andric   // la.pcrel $rd, sym
846bdd1243dSDimitry Andric   // expands to:
847bdd1243dSDimitry Andric   //   pcalau12i $rd, %pc_hi20(sym)
848bdd1243dSDimitry Andric   //   addi.w/d  $rd, rd, %pc_lo12(sym)
849bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
850bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(1).getExpr();
851bdd1243dSDimitry Andric   InstSeq Insts;
852bdd1243dSDimitry Andric   unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
853bdd1243dSDimitry Andric 
854bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
855bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_PCALA_HI20));
856bdd1243dSDimitry Andric   Insts.push_back(
857bdd1243dSDimitry Andric       LoongArchAsmParser::Inst(ADDI, LoongArchMCExpr::VK_LoongArch_PCALA_LO12));
858bdd1243dSDimitry Andric 
859*647cbc5dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out, true);
860bdd1243dSDimitry Andric }
861bdd1243dSDimitry Andric 
862bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressPcrelLarge(MCInst &Inst, SMLoc IDLoc,
863bdd1243dSDimitry Andric                                                    MCStreamer &Out) {
864bdd1243dSDimitry Andric   // la.pcrel $rd, $rj, sym
865bdd1243dSDimitry Andric   // expands to:
866bdd1243dSDimitry Andric   //   pcalau12i $rd, %pc_hi20(sym)
867bdd1243dSDimitry Andric   //   addi.d    $rj, $r0, %pc_lo12(sym)
868bdd1243dSDimitry Andric   //   lu32i.d   $rj, %pc64_lo20(sym)
869bdd1243dSDimitry Andric   //   lu52i.d   $rj, $rj, %pc64_hi12(sym)
870bdd1243dSDimitry Andric   //   add.d     $rd, $rd, $rj
871bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
872bdd1243dSDimitry Andric   MCRegister TmpReg = Inst.getOperand(1).getReg();
873bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(2).getExpr();
874bdd1243dSDimitry Andric   InstSeq Insts;
875bdd1243dSDimitry Andric 
876bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
877bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_PCALA_HI20));
878bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
879bdd1243dSDimitry Andric       LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_PCALA_LO12));
880bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
881bdd1243dSDimitry Andric       LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_PCALA64_LO20));
882bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
883bdd1243dSDimitry Andric       LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_PCALA64_HI12));
884bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(LoongArch::ADD_D));
885bdd1243dSDimitry Andric 
886bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
887bdd1243dSDimitry Andric }
888bdd1243dSDimitry Andric 
889bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressGot(MCInst &Inst, SMLoc IDLoc,
890bdd1243dSDimitry Andric                                             MCStreamer &Out) {
891bdd1243dSDimitry Andric   // la.got $rd, sym
892bdd1243dSDimitry Andric   // expands to:
893bdd1243dSDimitry Andric   //   pcalau12i $rd, %got_pc_hi20(sym)
894bdd1243dSDimitry Andric   //   ld.w/d    $rd, $rd, %got_pc_lo12(sym)
895bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
896bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(1).getExpr();
897bdd1243dSDimitry Andric   InstSeq Insts;
898bdd1243dSDimitry Andric   unsigned LD = is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
899bdd1243dSDimitry Andric 
900bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
901bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20));
902bdd1243dSDimitry Andric   Insts.push_back(
903bdd1243dSDimitry Andric       LoongArchAsmParser::Inst(LD, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
904bdd1243dSDimitry Andric 
905*647cbc5dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out, true);
906bdd1243dSDimitry Andric }
907bdd1243dSDimitry Andric 
908bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressGotLarge(MCInst &Inst, SMLoc IDLoc,
909bdd1243dSDimitry Andric                                                  MCStreamer &Out) {
910bdd1243dSDimitry Andric   // la.got $rd, $rj, sym
911bdd1243dSDimitry Andric   // expands to:
912bdd1243dSDimitry Andric   //   pcalau12i $rd, %got_pc_hi20(sym)
913bdd1243dSDimitry Andric   //   addi.d    $rj, $r0, %got_pc_lo12(sym)
914bdd1243dSDimitry Andric   //   lu32i.d   $rj, %got64_pc_lo20(sym)
915bdd1243dSDimitry Andric   //   lu52i.d   $rj, $rj, %got64_pc_hi12(sym)
916bdd1243dSDimitry Andric   //   ldx.d     $rd, $rd, $rj
917bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
918bdd1243dSDimitry Andric   MCRegister TmpReg = Inst.getOperand(1).getReg();
919bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(2).getExpr();
920bdd1243dSDimitry Andric   InstSeq Insts;
921bdd1243dSDimitry Andric 
922bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
923bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20));
924bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
925bdd1243dSDimitry Andric       LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
926bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
927bdd1243dSDimitry Andric       LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20));
928bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
929bdd1243dSDimitry Andric       LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12));
930bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(LoongArch::LDX_D));
931bdd1243dSDimitry Andric 
932bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
933bdd1243dSDimitry Andric }
934bdd1243dSDimitry Andric 
935bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSLE(MCInst &Inst, SMLoc IDLoc,
936bdd1243dSDimitry Andric                                               MCStreamer &Out) {
937bdd1243dSDimitry Andric   // la.tls.le $rd, sym
938bdd1243dSDimitry Andric   // expands to:
939bdd1243dSDimitry Andric   //   lu12i.w $rd, %le_hi20(sym)
940bdd1243dSDimitry Andric   //   ori     $rd, $rd, %le_lo12(sym)
941bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
942bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(1).getExpr();
943bdd1243dSDimitry Andric   InstSeq Insts;
944bdd1243dSDimitry Andric 
945bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
946bdd1243dSDimitry Andric       LoongArch::LU12I_W, LoongArchMCExpr::VK_LoongArch_TLS_LE_HI20));
947bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
948bdd1243dSDimitry Andric       LoongArch::ORI, LoongArchMCExpr::VK_LoongArch_TLS_LE_LO12));
949bdd1243dSDimitry Andric 
950bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
951bdd1243dSDimitry Andric }
952bdd1243dSDimitry Andric 
953bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSIE(MCInst &Inst, SMLoc IDLoc,
954bdd1243dSDimitry Andric                                               MCStreamer &Out) {
955bdd1243dSDimitry Andric   // la.tls.ie $rd, sym
956bdd1243dSDimitry Andric   // expands to:
957bdd1243dSDimitry Andric   //   pcalau12i $rd, %ie_pc_hi20(sym)
958bdd1243dSDimitry Andric   //   ld.w/d    $rd, $rd, %ie_pc_lo12(sym)
959bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
960bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(1).getExpr();
961bdd1243dSDimitry Andric   InstSeq Insts;
962bdd1243dSDimitry Andric   unsigned LD = is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
963bdd1243dSDimitry Andric 
964bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
965bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20));
966bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
967bdd1243dSDimitry Andric       LD, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12));
968bdd1243dSDimitry Andric 
969bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
970bdd1243dSDimitry Andric }
971bdd1243dSDimitry Andric 
972bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSIELarge(MCInst &Inst, SMLoc IDLoc,
973bdd1243dSDimitry Andric                                                    MCStreamer &Out) {
974bdd1243dSDimitry Andric   // la.tls.ie $rd, $rj, sym
975bdd1243dSDimitry Andric   // expands to:
976bdd1243dSDimitry Andric   //   pcalau12i $rd, %ie_pc_hi20(sym)
977bdd1243dSDimitry Andric   //   addi.d    $rj, $r0, %ie_pc_lo12(sym)
978bdd1243dSDimitry Andric   //   lu32i.d   $rj, %ie64_pc_lo20(sym)
979bdd1243dSDimitry Andric   //   lu52i.d   $rj, $rj, %ie64_pc_hi12(sym)
980bdd1243dSDimitry Andric   //   ldx.d     $rd, $rd, $rj
981bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
982bdd1243dSDimitry Andric   MCRegister TmpReg = Inst.getOperand(1).getReg();
983bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(2).getExpr();
984bdd1243dSDimitry Andric   InstSeq Insts;
985bdd1243dSDimitry Andric 
986bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
987bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20));
988bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
989bdd1243dSDimitry Andric       LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12));
990bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
991bdd1243dSDimitry Andric       LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_LO20));
992bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
993bdd1243dSDimitry Andric       LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_HI12));
994bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(LoongArch::LDX_D));
995bdd1243dSDimitry Andric 
996bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
997bdd1243dSDimitry Andric }
998bdd1243dSDimitry Andric 
999bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSLD(MCInst &Inst, SMLoc IDLoc,
1000bdd1243dSDimitry Andric                                               MCStreamer &Out) {
1001bdd1243dSDimitry Andric   // la.tls.ld $rd, sym
1002bdd1243dSDimitry Andric   // expands to:
1003bdd1243dSDimitry Andric   //   pcalau12i $rd, %ld_pc_hi20(sym)
1004bdd1243dSDimitry Andric   //   addi.w/d  $rd, $rd, %got_pc_lo12(sym)
1005bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
1006bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(1).getExpr();
1007bdd1243dSDimitry Andric   InstSeq Insts;
1008bdd1243dSDimitry Andric   unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
1009bdd1243dSDimitry Andric 
1010bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1011bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20));
1012bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1013bdd1243dSDimitry Andric       ADDI, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
1014bdd1243dSDimitry Andric 
1015bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
1016bdd1243dSDimitry Andric }
1017bdd1243dSDimitry Andric 
1018bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSLDLarge(MCInst &Inst, SMLoc IDLoc,
1019bdd1243dSDimitry Andric                                                    MCStreamer &Out) {
1020bdd1243dSDimitry Andric   // la.tls.ld $rd, $rj, sym
1021bdd1243dSDimitry Andric   // expands to:
1022bdd1243dSDimitry Andric   //   pcalau12i $rd, %ld_pc_hi20(sym)
1023bdd1243dSDimitry Andric   //   addi.d    $rj, $r0, %got_pc_lo12(sym)
1024bdd1243dSDimitry Andric   //   lu32i.d   $rj, %got64_pc_lo20(sym)
1025bdd1243dSDimitry Andric   //   lu52i.d   $rj, $rj, %got64_pc_hi12(sym)
1026bdd1243dSDimitry Andric   //   add.d     $rd, $rd, $rj
1027bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
1028bdd1243dSDimitry Andric   MCRegister TmpReg = Inst.getOperand(1).getReg();
1029bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(2).getExpr();
1030bdd1243dSDimitry Andric   InstSeq Insts;
1031bdd1243dSDimitry Andric 
1032bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1033bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20));
1034bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1035bdd1243dSDimitry Andric       LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
1036bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1037bdd1243dSDimitry Andric       LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20));
1038bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1039bdd1243dSDimitry Andric       LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12));
1040bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(LoongArch::ADD_D));
1041bdd1243dSDimitry Andric 
1042bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
1043bdd1243dSDimitry Andric }
1044bdd1243dSDimitry Andric 
1045bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSGD(MCInst &Inst, SMLoc IDLoc,
1046bdd1243dSDimitry Andric                                               MCStreamer &Out) {
1047bdd1243dSDimitry Andric   // la.tls.gd $rd, sym
1048bdd1243dSDimitry Andric   // expands to:
1049bdd1243dSDimitry Andric   //   pcalau12i $rd, %gd_pc_hi20(sym)
1050bdd1243dSDimitry Andric   //   addi.w/d  $rd, $rd, %got_pc_lo12(sym)
1051bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
1052bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(1).getExpr();
1053bdd1243dSDimitry Andric   InstSeq Insts;
1054bdd1243dSDimitry Andric   unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
1055bdd1243dSDimitry Andric 
1056bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1057bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20));
1058bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1059bdd1243dSDimitry Andric       ADDI, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
1060bdd1243dSDimitry Andric 
1061bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
1062bdd1243dSDimitry Andric }
1063bdd1243dSDimitry Andric 
1064bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadAddressTLSGDLarge(MCInst &Inst, SMLoc IDLoc,
1065bdd1243dSDimitry Andric                                                    MCStreamer &Out) {
1066bdd1243dSDimitry Andric   // la.tls.gd $rd, $rj, sym
1067bdd1243dSDimitry Andric   // expands to:
1068bdd1243dSDimitry Andric   //   pcalau12i $rd, %gd_pc_hi20(sym)
1069bdd1243dSDimitry Andric   //   addi.d    $rj, $r0, %got_pc_lo12(sym)
1070bdd1243dSDimitry Andric   //   lu32i.d   $rj, %got64_pc_lo20(sym)
1071bdd1243dSDimitry Andric   //   lu52i.d   $rj, $rj, %got64_pc_hi12(sym)
1072bdd1243dSDimitry Andric   //   add.d     $rd, $rd, $rj
1073bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
1074bdd1243dSDimitry Andric   MCRegister TmpReg = Inst.getOperand(1).getReg();
1075bdd1243dSDimitry Andric   const MCExpr *Symbol = Inst.getOperand(2).getExpr();
1076bdd1243dSDimitry Andric   InstSeq Insts;
1077bdd1243dSDimitry Andric 
1078bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1079bdd1243dSDimitry Andric       LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20));
1080bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1081bdd1243dSDimitry Andric       LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
1082bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1083bdd1243dSDimitry Andric       LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20));
1084bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(
1085bdd1243dSDimitry Andric       LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12));
1086bdd1243dSDimitry Andric   Insts.push_back(LoongArchAsmParser::Inst(LoongArch::ADD_D));
1087bdd1243dSDimitry Andric 
1088bdd1243dSDimitry Andric   emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
1089bdd1243dSDimitry Andric }
1090bdd1243dSDimitry Andric 
1091bdd1243dSDimitry Andric void LoongArchAsmParser::emitLoadImm(MCInst &Inst, SMLoc IDLoc,
1092bdd1243dSDimitry Andric                                      MCStreamer &Out) {
1093bdd1243dSDimitry Andric   MCRegister DestReg = Inst.getOperand(0).getReg();
1094bdd1243dSDimitry Andric   int64_t Imm = Inst.getOperand(1).getImm();
1095bdd1243dSDimitry Andric   MCRegister SrcReg = LoongArch::R0;
1096bdd1243dSDimitry Andric 
1097bdd1243dSDimitry Andric   if (Inst.getOpcode() == LoongArch::PseudoLI_W)
1098bdd1243dSDimitry Andric     Imm = SignExtend64<32>(Imm);
1099bdd1243dSDimitry Andric 
1100bdd1243dSDimitry Andric   for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Imm)) {
1101bdd1243dSDimitry Andric     unsigned Opc = Inst.Opc;
1102bdd1243dSDimitry Andric     if (Opc == LoongArch::LU12I_W)
1103bdd1243dSDimitry Andric       Out.emitInstruction(MCInstBuilder(Opc).addReg(DestReg).addImm(Inst.Imm),
1104bdd1243dSDimitry Andric                           getSTI());
1105bdd1243dSDimitry Andric     else
1106bdd1243dSDimitry Andric       Out.emitInstruction(
1107bdd1243dSDimitry Andric           MCInstBuilder(Opc).addReg(DestReg).addReg(SrcReg).addImm(Inst.Imm),
1108bdd1243dSDimitry Andric           getSTI());
1109bdd1243dSDimitry Andric     SrcReg = DestReg;
1110bdd1243dSDimitry Andric   }
1111bdd1243dSDimitry Andric }
1112bdd1243dSDimitry Andric 
111381ad6265SDimitry Andric bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
111481ad6265SDimitry Andric                                             OperandVector &Operands,
111581ad6265SDimitry Andric                                             MCStreamer &Out) {
111681ad6265SDimitry Andric   Inst.setLoc(IDLoc);
1117bdd1243dSDimitry Andric   switch (Inst.getOpcode()) {
1118bdd1243dSDimitry Andric   default:
1119bdd1243dSDimitry Andric     break;
1120bdd1243dSDimitry Andric   case LoongArch::PseudoLA_ABS:
1121bdd1243dSDimitry Andric   case LoongArch::PseudoLA_ABS_LARGE:
1122bdd1243dSDimitry Andric     emitLoadAddressAbs(Inst, IDLoc, Out);
1123bdd1243dSDimitry Andric     return false;
1124bdd1243dSDimitry Andric   case LoongArch::PseudoLA_PCREL:
1125bdd1243dSDimitry Andric     emitLoadAddressPcrel(Inst, IDLoc, Out);
1126bdd1243dSDimitry Andric     return false;
1127bdd1243dSDimitry Andric   case LoongArch::PseudoLA_PCREL_LARGE:
1128bdd1243dSDimitry Andric     emitLoadAddressPcrelLarge(Inst, IDLoc, Out);
1129bdd1243dSDimitry Andric     return false;
1130bdd1243dSDimitry Andric   case LoongArch::PseudoLA_GOT:
1131bdd1243dSDimitry Andric     emitLoadAddressGot(Inst, IDLoc, Out);
1132bdd1243dSDimitry Andric     return false;
1133bdd1243dSDimitry Andric   case LoongArch::PseudoLA_GOT_LARGE:
1134bdd1243dSDimitry Andric     emitLoadAddressGotLarge(Inst, IDLoc, Out);
1135bdd1243dSDimitry Andric     return false;
1136bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_LE:
1137bdd1243dSDimitry Andric     emitLoadAddressTLSLE(Inst, IDLoc, Out);
1138bdd1243dSDimitry Andric     return false;
1139bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_IE:
1140bdd1243dSDimitry Andric     emitLoadAddressTLSIE(Inst, IDLoc, Out);
1141bdd1243dSDimitry Andric     return false;
1142bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_IE_LARGE:
1143bdd1243dSDimitry Andric     emitLoadAddressTLSIELarge(Inst, IDLoc, Out);
1144bdd1243dSDimitry Andric     return false;
1145bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_LD:
1146bdd1243dSDimitry Andric     emitLoadAddressTLSLD(Inst, IDLoc, Out);
1147bdd1243dSDimitry Andric     return false;
1148bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_LD_LARGE:
1149bdd1243dSDimitry Andric     emitLoadAddressTLSLDLarge(Inst, IDLoc, Out);
1150bdd1243dSDimitry Andric     return false;
1151bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_GD:
1152bdd1243dSDimitry Andric     emitLoadAddressTLSGD(Inst, IDLoc, Out);
1153bdd1243dSDimitry Andric     return false;
1154bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_GD_LARGE:
1155bdd1243dSDimitry Andric     emitLoadAddressTLSGDLarge(Inst, IDLoc, Out);
1156bdd1243dSDimitry Andric     return false;
1157bdd1243dSDimitry Andric   case LoongArch::PseudoLI_W:
1158bdd1243dSDimitry Andric   case LoongArch::PseudoLI_D:
1159bdd1243dSDimitry Andric     emitLoadImm(Inst, IDLoc, Out);
1160bdd1243dSDimitry Andric     return false;
1161bdd1243dSDimitry Andric   }
116281ad6265SDimitry Andric   Out.emitInstruction(Inst, getSTI());
116381ad6265SDimitry Andric   return false;
116481ad6265SDimitry Andric }
116581ad6265SDimitry Andric 
116681ad6265SDimitry Andric unsigned LoongArchAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
1167bdd1243dSDimitry Andric   unsigned Opc = Inst.getOpcode();
1168bdd1243dSDimitry Andric   switch (Opc) {
116981ad6265SDimitry Andric   default:
1170bdd1243dSDimitry Andric     if (Opc >= LoongArch::AMADD_D && Opc <= LoongArch::AMXOR_W) {
1171bdd1243dSDimitry Andric       unsigned Rd = Inst.getOperand(0).getReg();
1172bdd1243dSDimitry Andric       unsigned Rk = Inst.getOperand(1).getReg();
1173bdd1243dSDimitry Andric       unsigned Rj = Inst.getOperand(2).getReg();
1174bdd1243dSDimitry Andric       if ((Rd == Rk || Rd == Rj) && Rd != LoongArch::R0)
1175bdd1243dSDimitry Andric         return Match_RequiresAMORdDifferRkRj;
1176bdd1243dSDimitry Andric     }
117781ad6265SDimitry Andric     break;
1178bdd1243dSDimitry Andric   case LoongArch::PseudoLA_PCREL_LARGE:
1179bdd1243dSDimitry Andric   case LoongArch::PseudoLA_GOT_LARGE:
1180bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_IE_LARGE:
1181bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_LD_LARGE:
1182bdd1243dSDimitry Andric   case LoongArch::PseudoLA_TLS_GD_LARGE: {
1183bdd1243dSDimitry Andric     unsigned Rd = Inst.getOperand(0).getReg();
1184bdd1243dSDimitry Andric     unsigned Rj = Inst.getOperand(1).getReg();
1185bdd1243dSDimitry Andric     if (Rd == Rj)
1186bdd1243dSDimitry Andric       return Match_RequiresLAORdDifferRj;
1187bdd1243dSDimitry Andric     break;
1188bdd1243dSDimitry Andric   }
118906c3fb27SDimitry Andric   case LoongArch::CSRXCHG:
119006c3fb27SDimitry Andric   case LoongArch::GCSRXCHG: {
119181ad6265SDimitry Andric     unsigned Rj = Inst.getOperand(2).getReg();
119281ad6265SDimitry Andric     if (Rj == LoongArch::R0 || Rj == LoongArch::R1)
119381ad6265SDimitry Andric       return Match_RequiresOpnd2NotR0R1;
119481ad6265SDimitry Andric     return Match_Success;
119581ad6265SDimitry Andric   }
119681ad6265SDimitry Andric   case LoongArch::BSTRINS_W:
119781ad6265SDimitry Andric   case LoongArch::BSTRINS_D:
119881ad6265SDimitry Andric   case LoongArch::BSTRPICK_W:
119981ad6265SDimitry Andric   case LoongArch::BSTRPICK_D: {
120081ad6265SDimitry Andric     unsigned Opc = Inst.getOpcode();
120181ad6265SDimitry Andric     const signed Msb =
120281ad6265SDimitry Andric         (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D)
120381ad6265SDimitry Andric             ? Inst.getOperand(3).getImm()
120481ad6265SDimitry Andric             : Inst.getOperand(2).getImm();
120581ad6265SDimitry Andric     const signed Lsb =
120681ad6265SDimitry Andric         (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D)
120781ad6265SDimitry Andric             ? Inst.getOperand(4).getImm()
120881ad6265SDimitry Andric             : Inst.getOperand(3).getImm();
120981ad6265SDimitry Andric     if (Msb < Lsb)
121081ad6265SDimitry Andric       return Match_RequiresMsbNotLessThanLsb;
121181ad6265SDimitry Andric     return Match_Success;
121281ad6265SDimitry Andric   }
121381ad6265SDimitry Andric   }
121481ad6265SDimitry Andric 
121581ad6265SDimitry Andric   return Match_Success;
121681ad6265SDimitry Andric }
121781ad6265SDimitry Andric 
121881ad6265SDimitry Andric unsigned
121981ad6265SDimitry Andric LoongArchAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
122081ad6265SDimitry Andric                                                unsigned Kind) {
122181ad6265SDimitry Andric   LoongArchOperand &Op = static_cast<LoongArchOperand &>(AsmOp);
122281ad6265SDimitry Andric   if (!Op.isReg())
122381ad6265SDimitry Andric     return Match_InvalidOperand;
122481ad6265SDimitry Andric 
122581ad6265SDimitry Andric   MCRegister Reg = Op.getReg();
122681ad6265SDimitry Andric   // As the parser couldn't differentiate an FPR32 from an FPR64, coerce the
122781ad6265SDimitry Andric   // register from FPR32 to FPR64 if necessary.
122881ad6265SDimitry Andric   if (LoongArchMCRegisterClasses[LoongArch::FPR32RegClassID].contains(Reg) &&
122981ad6265SDimitry Andric       Kind == MCK_FPR64) {
123081ad6265SDimitry Andric     Op.setReg(convertFPR32ToFPR64(Reg));
123181ad6265SDimitry Andric     return Match_Success;
123281ad6265SDimitry Andric   }
123381ad6265SDimitry Andric 
123481ad6265SDimitry Andric   return Match_InvalidOperand;
123581ad6265SDimitry Andric }
123681ad6265SDimitry Andric 
123781ad6265SDimitry Andric bool LoongArchAsmParser::generateImmOutOfRangeError(
123881ad6265SDimitry Andric     OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper,
123906c3fb27SDimitry Andric     const Twine &Msg = "immediate must be an integer in the range") {
124081ad6265SDimitry Andric   SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
124181ad6265SDimitry Andric   return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]");
124281ad6265SDimitry Andric }
124381ad6265SDimitry Andric 
124481ad6265SDimitry Andric bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
124581ad6265SDimitry Andric                                                  OperandVector &Operands,
124681ad6265SDimitry Andric                                                  MCStreamer &Out,
124781ad6265SDimitry Andric                                                  uint64_t &ErrorInfo,
124881ad6265SDimitry Andric                                                  bool MatchingInlineAsm) {
124981ad6265SDimitry Andric   MCInst Inst;
125081ad6265SDimitry Andric   FeatureBitset MissingFeatures;
125181ad6265SDimitry Andric 
125281ad6265SDimitry Andric   auto Result = MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
125381ad6265SDimitry Andric                                      MatchingInlineAsm);
125481ad6265SDimitry Andric   switch (Result) {
125581ad6265SDimitry Andric   default:
125681ad6265SDimitry Andric     break;
125781ad6265SDimitry Andric   case Match_Success:
125881ad6265SDimitry Andric     return processInstruction(Inst, IDLoc, Operands, Out);
125981ad6265SDimitry Andric   case Match_MissingFeature: {
126081ad6265SDimitry Andric     assert(MissingFeatures.any() && "Unknown missing features!");
126181ad6265SDimitry Andric     bool FirstFeature = true;
126281ad6265SDimitry Andric     std::string Msg = "instruction requires the following:";
126381ad6265SDimitry Andric     for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
126481ad6265SDimitry Andric       if (MissingFeatures[i]) {
126581ad6265SDimitry Andric         Msg += FirstFeature ? " " : ", ";
126681ad6265SDimitry Andric         Msg += getSubtargetFeatureName(i);
126781ad6265SDimitry Andric         FirstFeature = false;
126881ad6265SDimitry Andric       }
126981ad6265SDimitry Andric     }
127081ad6265SDimitry Andric     return Error(IDLoc, Msg);
127181ad6265SDimitry Andric   }
127281ad6265SDimitry Andric   case Match_MnemonicFail: {
127381ad6265SDimitry Andric     FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
127481ad6265SDimitry Andric     std::string Suggestion = LoongArchMnemonicSpellCheck(
127581ad6265SDimitry Andric         ((LoongArchOperand &)*Operands[0]).getToken(), FBS, 0);
127681ad6265SDimitry Andric     return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion);
127781ad6265SDimitry Andric   }
127881ad6265SDimitry Andric   case Match_InvalidOperand: {
127981ad6265SDimitry Andric     SMLoc ErrorLoc = IDLoc;
128081ad6265SDimitry Andric     if (ErrorInfo != ~0ULL) {
128181ad6265SDimitry Andric       if (ErrorInfo >= Operands.size())
128281ad6265SDimitry Andric         return Error(ErrorLoc, "too few operands for instruction");
128381ad6265SDimitry Andric 
128481ad6265SDimitry Andric       ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
128581ad6265SDimitry Andric       if (ErrorLoc == SMLoc())
128681ad6265SDimitry Andric         ErrorLoc = IDLoc;
128781ad6265SDimitry Andric     }
128881ad6265SDimitry Andric     return Error(ErrorLoc, "invalid operand for instruction");
128981ad6265SDimitry Andric   }
129081ad6265SDimitry Andric   }
129181ad6265SDimitry Andric 
129281ad6265SDimitry Andric   // Handle the case when the error message is of specific type
129381ad6265SDimitry Andric   // other than the generic Match_InvalidOperand, and the
129481ad6265SDimitry Andric   // corresponding operand is missing.
129581ad6265SDimitry Andric   if (Result > FIRST_TARGET_MATCH_RESULT_TY) {
129681ad6265SDimitry Andric     SMLoc ErrorLoc = IDLoc;
129781ad6265SDimitry Andric     if (ErrorInfo != ~0ULL && ErrorInfo >= Operands.size())
129881ad6265SDimitry Andric       return Error(ErrorLoc, "too few operands for instruction");
129981ad6265SDimitry Andric   }
130081ad6265SDimitry Andric 
130181ad6265SDimitry Andric   switch (Result) {
130281ad6265SDimitry Andric   default:
130381ad6265SDimitry Andric     break;
130481ad6265SDimitry Andric   case Match_RequiresMsbNotLessThanLsb: {
130581ad6265SDimitry Andric     SMLoc ErrorStart = Operands[3]->getStartLoc();
130681ad6265SDimitry Andric     return Error(ErrorStart, "msb is less than lsb",
130781ad6265SDimitry Andric                  SMRange(ErrorStart, Operands[4]->getEndLoc()));
130881ad6265SDimitry Andric   }
130981ad6265SDimitry Andric   case Match_RequiresOpnd2NotR0R1:
131081ad6265SDimitry Andric     return Error(Operands[2]->getStartLoc(), "must not be $r0 or $r1");
1311bdd1243dSDimitry Andric   case Match_RequiresAMORdDifferRkRj:
1312bdd1243dSDimitry Andric     return Error(Operands[1]->getStartLoc(),
1313bdd1243dSDimitry Andric                  "$rd must be different from both $rk and $rj");
1314bdd1243dSDimitry Andric   case Match_RequiresLAORdDifferRj:
1315bdd1243dSDimitry Andric     return Error(Operands[1]->getStartLoc(), "$rd must be different from $rj");
131606c3fb27SDimitry Andric   case Match_InvalidUImm1:
131706c3fb27SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
131806c3fb27SDimitry Andric                                       /*Upper=*/(1 << 1) - 1);
131981ad6265SDimitry Andric   case Match_InvalidUImm2:
132081ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
132181ad6265SDimitry Andric                                       /*Upper=*/(1 << 2) - 1);
132281ad6265SDimitry Andric   case Match_InvalidUImm2plus1:
132381ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/1,
132481ad6265SDimitry Andric                                       /*Upper=*/(1 << 2));
132581ad6265SDimitry Andric   case Match_InvalidUImm3:
132681ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
132781ad6265SDimitry Andric                                       /*Upper=*/(1 << 3) - 1);
132806c3fb27SDimitry Andric   case Match_InvalidUImm4:
132906c3fb27SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
133006c3fb27SDimitry Andric                                       /*Upper=*/(1 << 4) - 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);
133706c3fb27SDimitry Andric   case Match_InvalidUImm7:
133806c3fb27SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
133906c3fb27SDimitry Andric                                       /*Upper=*/(1 << 7) - 1);
134006c3fb27SDimitry Andric   case Match_InvalidUImm8:
134106c3fb27SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
134206c3fb27SDimitry Andric                                       /*Upper=*/(1 << 8) - 1);
134381ad6265SDimitry Andric   case Match_InvalidUImm12:
134481ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
134581ad6265SDimitry Andric                                       /*Upper=*/(1 << 12) - 1);
1346bdd1243dSDimitry Andric   case Match_InvalidUImm12ori:
1347bdd1243dSDimitry Andric     return generateImmOutOfRangeError(
1348bdd1243dSDimitry Andric         Operands, ErrorInfo, /*Lower=*/0,
1349bdd1243dSDimitry Andric         /*Upper=*/(1 << 12) - 1,
1350bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %abs_lo12) or an "
1351bdd1243dSDimitry Andric         "integer in the range");
135206c3fb27SDimitry Andric   case Match_InvalidUImm14:
135306c3fb27SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
135406c3fb27SDimitry Andric                                       /*Upper=*/(1 << 14) - 1);
135581ad6265SDimitry Andric   case Match_InvalidUImm15:
135681ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
135781ad6265SDimitry Andric                                       /*Upper=*/(1 << 15) - 1);
135806c3fb27SDimitry Andric   case Match_InvalidSImm5:
135906c3fb27SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 4),
136006c3fb27SDimitry Andric                                       /*Upper=*/(1 << 4) - 1);
136106c3fb27SDimitry Andric   case Match_InvalidSImm8:
136206c3fb27SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 7),
136306c3fb27SDimitry Andric                                       /*Upper=*/(1 << 7) - 1);
136406c3fb27SDimitry Andric   case Match_InvalidSImm8lsl1:
136506c3fb27SDimitry Andric     return generateImmOutOfRangeError(
136606c3fb27SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 8), /*Upper=*/(1 << 8) - 2,
136706c3fb27SDimitry Andric         "immediate must be a multiple of 2 in the range");
136806c3fb27SDimitry Andric   case Match_InvalidSImm8lsl2:
136906c3fb27SDimitry Andric     return generateImmOutOfRangeError(
137006c3fb27SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 9), /*Upper=*/(1 << 9) - 4,
137106c3fb27SDimitry Andric         "immediate must be a multiple of 4 in the range");
137206c3fb27SDimitry Andric   case Match_InvalidSImm10:
137306c3fb27SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 9),
137406c3fb27SDimitry Andric                                       /*Upper=*/(1 << 9) - 1);
137506c3fb27SDimitry Andric   case Match_InvalidSImm8lsl3:
137606c3fb27SDimitry Andric     return generateImmOutOfRangeError(
137706c3fb27SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 10), /*Upper=*/(1 << 10) - 8,
137806c3fb27SDimitry Andric         "immediate must be a multiple of 8 in the range");
137906c3fb27SDimitry Andric   case Match_InvalidSImm9lsl3:
138006c3fb27SDimitry Andric     return generateImmOutOfRangeError(
138106c3fb27SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 11), /*Upper=*/(1 << 11) - 8,
138206c3fb27SDimitry Andric         "immediate must be a multiple of 8 in the range");
138306c3fb27SDimitry Andric   case Match_InvalidSImm10lsl2:
138406c3fb27SDimitry Andric     return generateImmOutOfRangeError(
138506c3fb27SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 11), /*Upper=*/(1 << 11) - 4,
138606c3fb27SDimitry Andric         "immediate must be a multiple of 4 in the range");
138706c3fb27SDimitry Andric   case Match_InvalidSImm11lsl1:
138806c3fb27SDimitry Andric     return generateImmOutOfRangeError(
138906c3fb27SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 11), /*Upper=*/(1 << 11) - 2,
139006c3fb27SDimitry Andric         "immediate must be a multiple of 2 in the range");
139181ad6265SDimitry Andric   case Match_InvalidSImm12:
139281ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 11),
139381ad6265SDimitry Andric                                       /*Upper=*/(1 << 11) - 1);
1394bdd1243dSDimitry Andric   case Match_InvalidSImm12addlike:
1395bdd1243dSDimitry Andric     return generateImmOutOfRangeError(
1396bdd1243dSDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 11),
1397bdd1243dSDimitry Andric         /*Upper=*/(1 << 11) - 1,
1398bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %pc_lo12) or an integer "
1399bdd1243dSDimitry Andric         "in the range");
1400bdd1243dSDimitry Andric   case Match_InvalidSImm12lu52id:
1401bdd1243dSDimitry Andric     return generateImmOutOfRangeError(
1402bdd1243dSDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 11),
1403bdd1243dSDimitry Andric         /*Upper=*/(1 << 11) - 1,
1404bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %pc64_hi12) or an "
1405bdd1243dSDimitry Andric         "integer in the range");
140606c3fb27SDimitry Andric   case Match_InvalidSImm13:
140706c3fb27SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 12),
140806c3fb27SDimitry Andric                                       /*Upper=*/(1 << 12) - 1);
140981ad6265SDimitry Andric   case Match_InvalidSImm14lsl2:
141081ad6265SDimitry Andric     return generateImmOutOfRangeError(
141181ad6265SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 15), /*Upper=*/(1 << 15) - 4,
141281ad6265SDimitry Andric         "immediate must be a multiple of 4 in the range");
141381ad6265SDimitry Andric   case Match_InvalidSImm16:
141481ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 15),
141581ad6265SDimitry Andric                                       /*Upper=*/(1 << 15) - 1);
141681ad6265SDimitry Andric   case Match_InvalidSImm16lsl2:
141781ad6265SDimitry Andric     return generateImmOutOfRangeError(
141881ad6265SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 17), /*Upper=*/(1 << 17) - 4,
1419bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %b16) or an integer "
1420bdd1243dSDimitry Andric         "in the range");
142181ad6265SDimitry Andric   case Match_InvalidSImm20:
142281ad6265SDimitry Andric     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 19),
142381ad6265SDimitry Andric                                       /*Upper=*/(1 << 19) - 1);
1424bdd1243dSDimitry Andric   case Match_InvalidSImm20lu12iw:
1425bdd1243dSDimitry Andric     return generateImmOutOfRangeError(
1426bdd1243dSDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 19),
1427bdd1243dSDimitry Andric         /*Upper=*/(1 << 19) - 1,
1428bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %abs_hi20) or an integer "
1429bdd1243dSDimitry Andric         "in the range");
1430bdd1243dSDimitry Andric   case Match_InvalidSImm20lu32id:
1431bdd1243dSDimitry Andric     return generateImmOutOfRangeError(
1432bdd1243dSDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 19),
1433bdd1243dSDimitry Andric         /*Upper=*/(1 << 19) - 1,
1434bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %abs64_lo20) or an "
1435bdd1243dSDimitry Andric         "integer in the range");
1436bdd1243dSDimitry Andric   case Match_InvalidSImm20pcalau12i:
1437bdd1243dSDimitry Andric     return generateImmOutOfRangeError(
1438bdd1243dSDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 19),
1439bdd1243dSDimitry Andric         /*Upper=*/(1 << 19) - 1,
1440bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %pc_hi20) or an integer "
1441bdd1243dSDimitry Andric         "in the range");
144281ad6265SDimitry Andric   case Match_InvalidSImm21lsl2:
144381ad6265SDimitry Andric     return generateImmOutOfRangeError(
144481ad6265SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4,
1445bdd1243dSDimitry Andric         "operand must be a symbol with modifier (e.g. %b21) or an integer "
1446bdd1243dSDimitry Andric         "in the range");
1447bdd1243dSDimitry Andric   case Match_InvalidSImm26Operand:
144881ad6265SDimitry Andric     return generateImmOutOfRangeError(
144981ad6265SDimitry Andric         Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4,
1450bdd1243dSDimitry Andric         "operand must be a bare symbol name or an immediate must be a multiple "
1451bdd1243dSDimitry Andric         "of 4 in the range");
1452bdd1243dSDimitry Andric   case Match_InvalidImm32: {
1453bdd1243dSDimitry Andric     SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
1454bdd1243dSDimitry Andric     return Error(ErrorLoc, "operand must be a 32 bit immediate");
1455bdd1243dSDimitry Andric   }
1456bdd1243dSDimitry Andric   case Match_InvalidBareSymbol: {
1457bdd1243dSDimitry Andric     SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
1458bdd1243dSDimitry Andric     return Error(ErrorLoc, "operand must be a bare symbol name");
1459bdd1243dSDimitry Andric   }
146081ad6265SDimitry Andric   }
146181ad6265SDimitry Andric   llvm_unreachable("Unknown match type detected!");
146281ad6265SDimitry Andric }
146381ad6265SDimitry Andric 
146481ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() {
146581ad6265SDimitry Andric   RegisterMCAsmParser<LoongArchAsmParser> X(getTheLoongArch32Target());
146681ad6265SDimitry Andric   RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target());
146781ad6265SDimitry Andric }
1468