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