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