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