123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422 |
- // LoongArchAsmParser.cpp - Parse LoongArch assembly to MCInst instructions -=//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "MCTargetDesc/LoongArchInstPrinter.h"
- #include "MCTargetDesc/LoongArchMCExpr.h"
- #include "MCTargetDesc/LoongArchMCTargetDesc.h"
- #include "MCTargetDesc/LoongArchMatInt.h"
- #include "TargetInfo/LoongArchTargetInfo.h"
- #include "llvm/MC/MCContext.h"
- #include "llvm/MC/MCInstBuilder.h"
- #include "llvm/MC/MCInstrInfo.h"
- #include "llvm/MC/MCParser/MCAsmLexer.h"
- #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
- #include "llvm/MC/MCParser/MCTargetAsmParser.h"
- #include "llvm/MC/MCRegisterInfo.h"
- #include "llvm/MC/MCStreamer.h"
- #include "llvm/MC/MCSubtargetInfo.h"
- #include "llvm/MC/MCValue.h"
- #include "llvm/MC/TargetRegistry.h"
- #include "llvm/Support/Casting.h"
- using namespace llvm;
- #define DEBUG_TYPE "loongarch-asm-parser"
- namespace {
- class LoongArchAsmParser : public MCTargetAsmParser {
- SMLoc getLoc() const { return getParser().getTok().getLoc(); }
- bool is64Bit() const { return getSTI().hasFeature(LoongArch::Feature64Bit); }
- struct Inst {
- unsigned Opc;
- LoongArchMCExpr::VariantKind VK;
- Inst(unsigned Opc,
- LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None)
- : Opc(Opc), VK(VK) {}
- };
- using InstSeq = SmallVector<Inst>;
- /// Parse a register as used in CFI directives.
- bool parseRegister(MCRegister &RegNo, SMLoc &StartLoc,
- SMLoc &EndLoc) override;
- OperandMatchResultTy tryParseRegister(MCRegister &RegNo, SMLoc &StartLoc,
- SMLoc &EndLoc) override;
- bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
- SMLoc NameLoc, OperandVector &Operands) override;
- bool ParseDirective(AsmToken DirectiveID) override { return true; }
- bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
- OperandVector &Operands, MCStreamer &Out,
- uint64_t &ErrorInfo,
- bool MatchingInlineAsm) override;
- unsigned checkTargetMatchPredicate(MCInst &Inst) override;
- unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
- unsigned Kind) override;
- bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo,
- int64_t Lower, int64_t Upper, Twine Msg);
- /// Helper for processing MC instructions that have been successfully matched
- /// by MatchAndEmitInstruction.
- bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands,
- MCStreamer &Out);
- // Auto-generated instruction matching functions.
- #define GET_ASSEMBLER_HEADER
- #include "LoongArchGenAsmMatcher.inc"
- OperandMatchResultTy parseRegister(OperandVector &Operands);
- OperandMatchResultTy parseImmediate(OperandVector &Operands);
- OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands);
- OperandMatchResultTy parseSImm26Operand(OperandVector &Operands);
- OperandMatchResultTy parseAtomicMemOp(OperandVector &Operands);
- bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
- // Helper to emit the sequence of instructions generated by the
- // "emitLoadAddress*" functions.
- void emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg,
- const MCExpr *Symbol, SmallVectorImpl<Inst> &Insts,
- SMLoc IDLoc, MCStreamer &Out);
- // Helper to emit pseudo instruction "la.abs $rd, sym".
- void emitLoadAddressAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- // Helper to emit pseudo instruction "la.pcrel $rd, sym".
- void emitLoadAddressPcrel(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- // Helper to emit pseudo instruction "la.pcrel $rd, $rj, sym".
- void emitLoadAddressPcrelLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- // Helper to emit pseudo instruction "la.got $rd, sym".
- void emitLoadAddressGot(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- // Helper to emit pseudo instruction "la.got $rd, $rj, sym".
- void emitLoadAddressGotLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- // Helper to emit pseudo instruction "la.tls.le $rd, sym".
- void emitLoadAddressTLSLE(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- // Helper to emit pseudo instruction "la.tls.ie $rd, sym".
- void emitLoadAddressTLSIE(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- // Helper to emit pseudo instruction "la.tls.ie $rd, $rj, sym".
- void emitLoadAddressTLSIELarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- // Helper to emit pseudo instruction "la.tls.ld $rd, sym".
- void emitLoadAddressTLSLD(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- // Helper to emit pseudo instruction "la.tls.ld $rd, $rj, sym".
- void emitLoadAddressTLSLDLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- // Helper to emit pseudo instruction "la.tls.gd $rd, sym".
- void emitLoadAddressTLSGD(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- // Helper to emit pseudo instruction "la.tls.gd $rd, $rj, sym".
- void emitLoadAddressTLSGDLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- // Helper to emit pseudo instruction "li.w/d $rd, $imm".
- void emitLoadImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
- public:
- enum LoongArchMatchResultTy {
- Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
- Match_RequiresMsbNotLessThanLsb,
- Match_RequiresOpnd2NotR0R1,
- Match_RequiresAMORdDifferRkRj,
- Match_RequiresLAORdDifferRj,
- #define GET_OPERAND_DIAGNOSTIC_TYPES
- #include "LoongArchGenAsmMatcher.inc"
- #undef GET_OPERAND_DIAGNOSTIC_TYPES
- };
- static bool classifySymbolRef(const MCExpr *Expr,
- LoongArchMCExpr::VariantKind &Kind);
- LoongArchAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
- const MCInstrInfo &MII, const MCTargetOptions &Options)
- : MCTargetAsmParser(Options, STI, MII) {
- Parser.addAliasForDirective(".half", ".2byte");
- Parser.addAliasForDirective(".hword", ".2byte");
- Parser.addAliasForDirective(".word", ".4byte");
- Parser.addAliasForDirective(".dword", ".8byte");
- // Initialize the set of available features.
- setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
- }
- };
- // Instances of this class represent a parsed LoongArch machine instruction.
- class LoongArchOperand : public MCParsedAsmOperand {
- enum class KindTy {
- Token,
- Register,
- Immediate,
- } Kind;
- struct RegOp {
- MCRegister RegNum;
- };
- struct ImmOp {
- const MCExpr *Val;
- };
- SMLoc StartLoc, EndLoc;
- union {
- StringRef Tok;
- struct RegOp Reg;
- struct ImmOp Imm;
- };
- public:
- LoongArchOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
- bool isToken() const override { return Kind == KindTy::Token; }
- bool isReg() const override { return Kind == KindTy::Register; }
- bool isImm() const override { return Kind == KindTy::Immediate; }
- bool isMem() const override { return false; }
- void setReg(MCRegister PhysReg) { Reg.RegNum = PhysReg; }
- bool isGPR() const {
- return Kind == KindTy::Register &&
- LoongArchMCRegisterClasses[LoongArch::GPRRegClassID].contains(
- Reg.RegNum);
- }
- static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm,
- LoongArchMCExpr::VariantKind &VK) {
- if (auto *LE = dyn_cast<LoongArchMCExpr>(Expr)) {
- VK = LE->getKind();
- return false;
- }
- if (auto CE = dyn_cast<MCConstantExpr>(Expr)) {
- Imm = CE->getValue();
- return true;
- }
- return false;
- }
- template <unsigned N, int P = 0> bool isUImm() const {
- if (!isImm())
- return false;
- int64_t Imm;
- LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
- bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
- return IsConstantImm && isUInt<N>(Imm - P) &&
- VK == LoongArchMCExpr::VK_LoongArch_None;
- }
- template <unsigned N, unsigned S = 0> bool isSImm() const {
- if (!isImm())
- return false;
- int64_t Imm;
- LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
- bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
- return IsConstantImm && isShiftedInt<N, S>(Imm) &&
- VK == LoongArchMCExpr::VK_LoongArch_None;
- }
- bool isBareSymbol() const {
- int64_t Imm;
- LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
- // Must be of 'immediate' type but not a constant.
- if (!isImm() || evaluateConstantImm(getImm(), Imm, VK))
- return false;
- return LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
- VK == LoongArchMCExpr::VK_LoongArch_None;
- }
- bool isUImm2() const { return isUImm<2>(); }
- bool isUImm2plus1() const { return isUImm<2, 1>(); }
- bool isUImm3() const { return isUImm<3>(); }
- bool isUImm5() const { return isUImm<5>(); }
- bool isUImm6() const { return isUImm<6>(); }
- bool isUImm8() const { return isUImm<8>(); }
- bool isSImm12() const { return isSImm<12>(); }
- bool isSImm12addlike() const {
- if (!isImm())
- return false;
- int64_t Imm;
- LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
- bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
- bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
- VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12 ||
- VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12;
- return IsConstantImm
- ? isInt<12>(Imm) && IsValidKind
- : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
- IsValidKind;
- }
- bool isSImm12lu52id() const {
- if (!isImm())
- return false;
- int64_t Imm;
- LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
- bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
- bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
- VK == LoongArchMCExpr::VK_LoongArch_ABS64_HI12 ||
- VK == LoongArchMCExpr::VK_LoongArch_PCALA64_HI12 ||
- VK == LoongArchMCExpr::VK_LoongArch_GOT64_HI12 ||
- VK == LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_LE64_HI12 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_HI12 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_HI12;
- return IsConstantImm
- ? isInt<12>(Imm) && IsValidKind
- : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
- IsValidKind;
- }
- bool isUImm12() const { return isUImm<12>(); }
- bool isUImm12ori() const {
- if (!isImm())
- return false;
- int64_t Imm;
- LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
- bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
- bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
- VK == LoongArchMCExpr::VK_LoongArch_ABS_LO12 ||
- VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12 ||
- VK == LoongArchMCExpr::VK_LoongArch_GOT_LO12 ||
- VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_LO12 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_LO12 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12;
- return IsConstantImm
- ? isUInt<12>(Imm) && IsValidKind
- : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
- IsValidKind;
- }
- bool isUImm14() const { return isUImm<14>(); }
- bool isUImm15() const { return isUImm<15>(); }
- bool isSImm14lsl2() const { return isSImm<14, 2>(); }
- bool isSImm16() const { return isSImm<16>(); }
- bool isSImm16lsl2() const {
- if (!isImm())
- return false;
- int64_t Imm;
- LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
- bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
- bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
- VK == LoongArchMCExpr::VK_LoongArch_B16 ||
- VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12;
- return IsConstantImm
- ? isShiftedInt<16, 2>(Imm) && IsValidKind
- : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
- IsValidKind;
- }
- bool isSImm20() const { return isSImm<20>(); }
- bool isSImm20pcalau12i() const {
- if (!isImm())
- return false;
- int64_t Imm;
- LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
- bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
- bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
- VK == LoongArchMCExpr::VK_LoongArch_PCALA_HI20 ||
- VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20;
- return IsConstantImm
- ? isInt<20>(Imm) && IsValidKind
- : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
- IsValidKind;
- }
- bool isSImm20lu12iw() const {
- if (!isImm())
- return false;
- int64_t Imm;
- LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
- bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
- bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
- VK == LoongArchMCExpr::VK_LoongArch_ABS_HI20 ||
- VK == LoongArchMCExpr::VK_LoongArch_GOT_HI20 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_GD_HI20 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_LD_HI20 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_HI20 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_HI20;
- return IsConstantImm
- ? isInt<20>(Imm) && IsValidKind
- : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
- IsValidKind;
- }
- bool isSImm20lu32id() const {
- if (!isImm())
- return false;
- int64_t Imm;
- LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
- bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
- bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
- VK == LoongArchMCExpr::VK_LoongArch_ABS64_LO20 ||
- VK == LoongArchMCExpr::VK_LoongArch_PCALA64_LO20 ||
- VK == LoongArchMCExpr::VK_LoongArch_GOT64_LO20 ||
- VK == LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_LO20 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_LO20 ||
- VK == LoongArchMCExpr::VK_LoongArch_TLS_LE64_LO20;
- return IsConstantImm
- ? isInt<20>(Imm) && IsValidKind
- : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
- IsValidKind;
- }
- bool isSImm21lsl2() const {
- if (!isImm())
- return false;
- int64_t Imm;
- LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
- bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
- bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
- VK == LoongArchMCExpr::VK_LoongArch_B21;
- return IsConstantImm
- ? isShiftedInt<21, 2>(Imm) && IsValidKind
- : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
- IsValidKind;
- }
- bool isSImm26Operand() const {
- if (!isImm())
- return false;
- int64_t Imm;
- LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None;
- bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
- bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
- VK == LoongArchMCExpr::VK_LoongArch_CALL ||
- VK == LoongArchMCExpr::VK_LoongArch_CALL_PLT ||
- VK == LoongArchMCExpr::VK_LoongArch_B26;
- return IsConstantImm
- ? isShiftedInt<26, 2>(Imm) && IsValidKind
- : LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
- IsValidKind;
- }
- bool isImm32() const { return isSImm<32>() || isUImm<32>(); }
- /// Gets location of the first token of this operand.
- SMLoc getStartLoc() const override { return StartLoc; }
- /// Gets location of the last token of this operand.
- SMLoc getEndLoc() const override { return EndLoc; }
- unsigned getReg() const override {
- assert(Kind == KindTy::Register && "Invalid type access!");
- return Reg.RegNum.id();
- }
- const MCExpr *getImm() const {
- assert(Kind == KindTy::Immediate && "Invalid type access!");
- return Imm.Val;
- }
- StringRef getToken() const {
- assert(Kind == KindTy::Token && "Invalid type access!");
- return Tok;
- }
- void print(raw_ostream &OS) const override {
- auto RegName = [](MCRegister Reg) {
- if (Reg)
- return LoongArchInstPrinter::getRegisterName(Reg);
- else
- return "noreg";
- };
- switch (Kind) {
- case KindTy::Immediate:
- OS << *getImm();
- break;
- case KindTy::Register:
- OS << "<register " << RegName(getReg()) << ">";
- break;
- case KindTy::Token:
- OS << "'" << getToken() << "'";
- break;
- }
- }
- static std::unique_ptr<LoongArchOperand> createToken(StringRef Str, SMLoc S) {
- auto Op = std::make_unique<LoongArchOperand>(KindTy::Token);
- Op->Tok = Str;
- Op->StartLoc = S;
- Op->EndLoc = S;
- return Op;
- }
- static std::unique_ptr<LoongArchOperand> createReg(unsigned RegNo, SMLoc S,
- SMLoc E) {
- auto Op = std::make_unique<LoongArchOperand>(KindTy::Register);
- Op->Reg.RegNum = RegNo;
- Op->StartLoc = S;
- Op->EndLoc = E;
- return Op;
- }
- static std::unique_ptr<LoongArchOperand> createImm(const MCExpr *Val, SMLoc S,
- SMLoc E) {
- auto Op = std::make_unique<LoongArchOperand>(KindTy::Immediate);
- Op->Imm.Val = Val;
- Op->StartLoc = S;
- Op->EndLoc = E;
- return Op;
- }
- void addExpr(MCInst &Inst, const MCExpr *Expr) const {
- if (auto CE = dyn_cast<MCConstantExpr>(Expr))
- Inst.addOperand(MCOperand::createImm(CE->getValue()));
- else
- Inst.addOperand(MCOperand::createExpr(Expr));
- }
- // Used by the TableGen Code.
- void addRegOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- Inst.addOperand(MCOperand::createReg(getReg()));
- }
- void addImmOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
- addExpr(Inst, getImm());
- }
- };
- } // end namespace
- #define GET_REGISTER_MATCHER
- #define GET_SUBTARGET_FEATURE_NAME
- #define GET_MATCHER_IMPLEMENTATION
- #define GET_MNEMONIC_SPELL_CHECKER
- #include "LoongArchGenAsmMatcher.inc"
- static MCRegister convertFPR32ToFPR64(MCRegister Reg) {
- assert(Reg >= LoongArch::F0 && Reg <= LoongArch::F31 && "Invalid register");
- return Reg - LoongArch::F0 + LoongArch::F0_64;
- }
- // Attempts to match Name as a register (either using the default name or
- // alternative ABI names), setting RegNo to the matching register. Upon
- // failure, returns true and sets RegNo to 0.
- static bool matchRegisterNameHelper(MCRegister &RegNo, StringRef Name) {
- RegNo = MatchRegisterName(Name);
- // The 32-bit and 64-bit FPRs have the same asm name. Check that the initial
- // match always matches the 32-bit variant, and not the 64-bit one.
- assert(!(RegNo >= LoongArch::F0_64 && RegNo <= LoongArch::F31_64));
- // The default FPR register class is based on the tablegen enum ordering.
- static_assert(LoongArch::F0 < LoongArch::F0_64,
- "FPR matching must be updated");
- if (RegNo == LoongArch::NoRegister)
- RegNo = MatchRegisterAltName(Name);
- return RegNo == LoongArch::NoRegister;
- }
- bool LoongArchAsmParser::parseRegister(MCRegister &RegNo, SMLoc &StartLoc,
- SMLoc &EndLoc) {
- return Error(getLoc(), "invalid register number");
- }
- OperandMatchResultTy LoongArchAsmParser::tryParseRegister(MCRegister &RegNo,
- SMLoc &StartLoc,
- SMLoc &EndLoc) {
- llvm_unreachable("Unimplemented function.");
- }
- bool LoongArchAsmParser::classifySymbolRef(const MCExpr *Expr,
- LoongArchMCExpr::VariantKind &Kind) {
- Kind = LoongArchMCExpr::VK_LoongArch_None;
- if (const LoongArchMCExpr *RE = dyn_cast<LoongArchMCExpr>(Expr)) {
- Kind = RE->getKind();
- Expr = RE->getSubExpr();
- }
- MCValue Res;
- if (Expr->evaluateAsRelocatable(Res, nullptr, nullptr))
- return Res.getRefKind() == LoongArchMCExpr::VK_LoongArch_None;
- return false;
- }
- OperandMatchResultTy
- LoongArchAsmParser::parseRegister(OperandVector &Operands) {
- if (getLexer().getTok().isNot(AsmToken::Dollar))
- return MatchOperand_NoMatch;
- // Eat the $ prefix.
- getLexer().Lex();
- if (getLexer().getKind() != AsmToken::Identifier)
- return MatchOperand_NoMatch;
- StringRef Name = getLexer().getTok().getIdentifier();
- MCRegister RegNo;
- matchRegisterNameHelper(RegNo, Name);
- if (RegNo == LoongArch::NoRegister)
- return MatchOperand_NoMatch;
- SMLoc S = getLoc();
- SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size());
- getLexer().Lex();
- Operands.push_back(LoongArchOperand::createReg(RegNo, S, E));
- return MatchOperand_Success;
- }
- OperandMatchResultTy
- LoongArchAsmParser::parseImmediate(OperandVector &Operands) {
- SMLoc S = getLoc();
- SMLoc E;
- const MCExpr *Res;
- switch (getLexer().getKind()) {
- default:
- return MatchOperand_NoMatch;
- case AsmToken::LParen:
- case AsmToken::Dot:
- case AsmToken::Minus:
- case AsmToken::Plus:
- case AsmToken::Exclaim:
- case AsmToken::Tilde:
- case AsmToken::Integer:
- case AsmToken::String:
- case AsmToken::Identifier:
- if (getParser().parseExpression(Res, E))
- return MatchOperand_ParseFail;
- break;
- case AsmToken::Percent:
- return parseOperandWithModifier(Operands);
- }
- Operands.push_back(LoongArchOperand::createImm(Res, S, E));
- return MatchOperand_Success;
- }
- OperandMatchResultTy
- LoongArchAsmParser::parseOperandWithModifier(OperandVector &Operands) {
- SMLoc S = getLoc();
- SMLoc E;
- if (getLexer().getKind() != AsmToken::Percent) {
- Error(getLoc(), "expected '%' for operand modifier");
- return MatchOperand_ParseFail;
- }
- getParser().Lex(); // Eat '%'
- if (getLexer().getKind() != AsmToken::Identifier) {
- Error(getLoc(), "expected valid identifier for operand modifier");
- return MatchOperand_ParseFail;
- }
- StringRef Identifier = getParser().getTok().getIdentifier();
- LoongArchMCExpr::VariantKind VK =
- LoongArchMCExpr::getVariantKindForName(Identifier);
- if (VK == LoongArchMCExpr::VK_LoongArch_Invalid) {
- Error(getLoc(), "unrecognized operand modifier");
- return MatchOperand_ParseFail;
- }
- getParser().Lex(); // Eat the identifier
- if (getLexer().getKind() != AsmToken::LParen) {
- Error(getLoc(), "expected '('");
- return MatchOperand_ParseFail;
- }
- getParser().Lex(); // Eat '('
- const MCExpr *SubExpr;
- if (getParser().parseParenExpression(SubExpr, E)) {
- return MatchOperand_ParseFail;
- }
- const MCExpr *ModExpr = LoongArchMCExpr::create(SubExpr, VK, getContext());
- Operands.push_back(LoongArchOperand::createImm(ModExpr, S, E));
- return MatchOperand_Success;
- }
- OperandMatchResultTy
- LoongArchAsmParser::parseSImm26Operand(OperandVector &Operands) {
- SMLoc S = getLoc();
- const MCExpr *Res;
- if (getLexer().getKind() == AsmToken::Percent)
- return parseOperandWithModifier(Operands);
- if (getLexer().getKind() != AsmToken::Identifier)
- return MatchOperand_NoMatch;
- StringRef Identifier;
- if (getParser().parseIdentifier(Identifier))
- return MatchOperand_ParseFail;
- SMLoc E = SMLoc::getFromPointer(S.getPointer() + Identifier.size());
- MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
- Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
- Res = LoongArchMCExpr::create(Res, LoongArchMCExpr::VK_LoongArch_CALL,
- getContext());
- Operands.push_back(LoongArchOperand::createImm(Res, S, E));
- return MatchOperand_Success;
- }
- OperandMatchResultTy
- LoongArchAsmParser::parseAtomicMemOp(OperandVector &Operands) {
- // Parse "$r*".
- if (parseRegister(Operands) != MatchOperand_Success)
- return MatchOperand_NoMatch;
- // If there is a next operand and it is 0, ignore it. Otherwise print a
- // diagnostic message.
- if (getLexer().is(AsmToken::Comma)) {
- getLexer().Lex(); // Consume comma token.
- int64_t ImmVal;
- SMLoc ImmStart = getLoc();
- if (getParser().parseIntToken(ImmVal, "expected optional integer offset"))
- return MatchOperand_ParseFail;
- if (ImmVal) {
- Error(ImmStart, "optional integer offset must be 0");
- return MatchOperand_ParseFail;
- }
- }
- return MatchOperand_Success;
- }
- /// Looks at a token type and creates the relevant operand from this
- /// information, adding to Operands. Return true upon an error.
- bool LoongArchAsmParser::parseOperand(OperandVector &Operands,
- StringRef Mnemonic) {
- // Check if the current operand has a custom associated parser, if so, try to
- // custom parse the operand, or fallback to the general approach.
- OperandMatchResultTy Result =
- MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/true);
- if (Result == MatchOperand_Success)
- return false;
- if (Result == MatchOperand_ParseFail)
- return true;
- if (parseRegister(Operands) == MatchOperand_Success ||
- parseImmediate(Operands) == MatchOperand_Success)
- return false;
- // Finally we have exhausted all options and must declare defeat.
- Error(getLoc(), "unknown operand");
- return true;
- }
- bool LoongArchAsmParser::ParseInstruction(ParseInstructionInfo &Info,
- StringRef Name, SMLoc NameLoc,
- OperandVector &Operands) {
- // First operand in MCInst is instruction mnemonic.
- Operands.push_back(LoongArchOperand::createToken(Name, NameLoc));
- // If there are no more operands, then finish.
- if (parseOptionalToken(AsmToken::EndOfStatement))
- return false;
- // Parse first operand.
- if (parseOperand(Operands, Name))
- return true;
- // Parse until end of statement, consuming commas between operands.
- while (parseOptionalToken(AsmToken::Comma))
- if (parseOperand(Operands, Name))
- return true;
- // Parse end of statement and return successfully.
- if (parseOptionalToken(AsmToken::EndOfStatement))
- return false;
- SMLoc Loc = getLexer().getLoc();
- getParser().eatToEndOfStatement();
- return Error(Loc, "unexpected token");
- }
- void LoongArchAsmParser::emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg,
- const MCExpr *Symbol,
- SmallVectorImpl<Inst> &Insts,
- SMLoc IDLoc, MCStreamer &Out) {
- MCContext &Ctx = getContext();
- for (LoongArchAsmParser::Inst &Inst : Insts) {
- unsigned Opc = Inst.Opc;
- LoongArchMCExpr::VariantKind VK = Inst.VK;
- const LoongArchMCExpr *LE = LoongArchMCExpr::create(Symbol, VK, Ctx);
- switch (Opc) {
- default:
- llvm_unreachable("unexpected opcode");
- case LoongArch::PCALAU12I:
- case LoongArch::LU12I_W:
- Out.emitInstruction(MCInstBuilder(Opc).addReg(DestReg).addExpr(LE),
- getSTI());
- break;
- case LoongArch::ORI:
- case LoongArch::ADDI_W:
- case LoongArch::LD_W:
- case LoongArch::LD_D: {
- if (VK == LoongArchMCExpr::VK_LoongArch_None) {
- Out.emitInstruction(
- MCInstBuilder(Opc).addReg(DestReg).addReg(DestReg).addImm(0),
- getSTI());
- continue;
- }
- Out.emitInstruction(
- MCInstBuilder(Opc).addReg(DestReg).addReg(DestReg).addExpr(LE),
- getSTI());
- break;
- }
- case LoongArch::LU32I_D:
- Out.emitInstruction(MCInstBuilder(Opc)
- .addReg(DestReg == TmpReg ? DestReg : TmpReg)
- .addReg(DestReg == TmpReg ? DestReg : TmpReg)
- .addExpr(LE),
- getSTI());
- break;
- case LoongArch::LU52I_D:
- Out.emitInstruction(
- MCInstBuilder(Opc).addReg(TmpReg).addReg(TmpReg).addExpr(LE),
- getSTI());
- break;
- case LoongArch::ADDI_D:
- Out.emitInstruction(
- MCInstBuilder(Opc)
- .addReg(TmpReg)
- .addReg(DestReg == TmpReg ? TmpReg : LoongArch::R0)
- .addExpr(LE),
- getSTI());
- break;
- case LoongArch::ADD_D:
- case LoongArch::LDX_D:
- Out.emitInstruction(
- MCInstBuilder(Opc).addReg(DestReg).addReg(DestReg).addReg(TmpReg),
- getSTI());
- break;
- }
- }
- }
- void LoongArchAsmParser::emitLoadAddressAbs(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- // la.abs $rd, sym
- // expands to:
- // lu12i.w $rd, %abs_hi20(sym)
- // ori $rd, $rd, %abs_lo12(sym)
- //
- // for 64bit appends:
- // lu32i.d $rd, %abs64_lo20(sym)
- // lu52i.d $rd, $rd, %abs64_hi12(sym)
- MCRegister DestReg = Inst.getOperand(0).getReg();
- const MCExpr *Symbol = Inst.getOpcode() == LoongArch::PseudoLA_ABS
- ? Inst.getOperand(1).getExpr()
- : Inst.getOperand(2).getExpr();
- InstSeq Insts;
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU12I_W, LoongArchMCExpr::VK_LoongArch_ABS_HI20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::ORI, LoongArchMCExpr::VK_LoongArch_ABS_LO12));
- if (is64Bit()) {
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_ABS64_LO20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_ABS64_HI12));
- }
- emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
- }
- void LoongArchAsmParser::emitLoadAddressPcrel(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- // la.pcrel $rd, sym
- // expands to:
- // pcalau12i $rd, %pc_hi20(sym)
- // addi.w/d $rd, rd, %pc_lo12(sym)
- MCRegister DestReg = Inst.getOperand(0).getReg();
- const MCExpr *Symbol = Inst.getOperand(1).getExpr();
- InstSeq Insts;
- unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_PCALA_HI20));
- Insts.push_back(
- LoongArchAsmParser::Inst(ADDI, LoongArchMCExpr::VK_LoongArch_PCALA_LO12));
- emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
- }
- void LoongArchAsmParser::emitLoadAddressPcrelLarge(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- // la.pcrel $rd, $rj, sym
- // expands to:
- // pcalau12i $rd, %pc_hi20(sym)
- // addi.d $rj, $r0, %pc_lo12(sym)
- // lu32i.d $rj, %pc64_lo20(sym)
- // lu52i.d $rj, $rj, %pc64_hi12(sym)
- // add.d $rd, $rd, $rj
- MCRegister DestReg = Inst.getOperand(0).getReg();
- MCRegister TmpReg = Inst.getOperand(1).getReg();
- const MCExpr *Symbol = Inst.getOperand(2).getExpr();
- InstSeq Insts;
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_PCALA_HI20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_PCALA_LO12));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_PCALA64_LO20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_PCALA64_HI12));
- Insts.push_back(LoongArchAsmParser::Inst(LoongArch::ADD_D));
- emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
- }
- void LoongArchAsmParser::emitLoadAddressGot(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- // la.got $rd, sym
- // expands to:
- // pcalau12i $rd, %got_pc_hi20(sym)
- // ld.w/d $rd, $rd, %got_pc_lo12(sym)
- MCRegister DestReg = Inst.getOperand(0).getReg();
- const MCExpr *Symbol = Inst.getOperand(1).getExpr();
- InstSeq Insts;
- unsigned LD = is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20));
- Insts.push_back(
- LoongArchAsmParser::Inst(LD, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
- emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
- }
- void LoongArchAsmParser::emitLoadAddressGotLarge(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- // la.got $rd, $rj, sym
- // expands to:
- // pcalau12i $rd, %got_pc_hi20(sym)
- // addi.d $rj, $r0, %got_pc_lo12(sym)
- // lu32i.d $rj, %got64_pc_lo20(sym)
- // lu52i.d $rj, $rj, %got64_pc_hi12(sym)
- // ldx.d $rd, $rd, $rj
- MCRegister DestReg = Inst.getOperand(0).getReg();
- MCRegister TmpReg = Inst.getOperand(1).getReg();
- const MCExpr *Symbol = Inst.getOperand(2).getExpr();
- InstSeq Insts;
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12));
- Insts.push_back(LoongArchAsmParser::Inst(LoongArch::LDX_D));
- emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
- }
- void LoongArchAsmParser::emitLoadAddressTLSLE(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- // la.tls.le $rd, sym
- // expands to:
- // lu12i.w $rd, %le_hi20(sym)
- // ori $rd, $rd, %le_lo12(sym)
- MCRegister DestReg = Inst.getOperand(0).getReg();
- const MCExpr *Symbol = Inst.getOperand(1).getExpr();
- InstSeq Insts;
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU12I_W, LoongArchMCExpr::VK_LoongArch_TLS_LE_HI20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::ORI, LoongArchMCExpr::VK_LoongArch_TLS_LE_LO12));
- emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
- }
- void LoongArchAsmParser::emitLoadAddressTLSIE(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- // la.tls.ie $rd, sym
- // expands to:
- // pcalau12i $rd, %ie_pc_hi20(sym)
- // ld.w/d $rd, $rd, %ie_pc_lo12(sym)
- MCRegister DestReg = Inst.getOperand(0).getReg();
- const MCExpr *Symbol = Inst.getOperand(1).getExpr();
- InstSeq Insts;
- unsigned LD = is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LD, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12));
- emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
- }
- void LoongArchAsmParser::emitLoadAddressTLSIELarge(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- // la.tls.ie $rd, $rj, sym
- // expands to:
- // pcalau12i $rd, %ie_pc_hi20(sym)
- // addi.d $rj, $r0, %ie_pc_lo12(sym)
- // lu32i.d $rj, %ie64_pc_lo20(sym)
- // lu52i.d $rj, $rj, %ie64_pc_hi12(sym)
- // ldx.d $rd, $rd, $rj
- MCRegister DestReg = Inst.getOperand(0).getReg();
- MCRegister TmpReg = Inst.getOperand(1).getReg();
- const MCExpr *Symbol = Inst.getOperand(2).getExpr();
- InstSeq Insts;
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_LO20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_HI12));
- Insts.push_back(LoongArchAsmParser::Inst(LoongArch::LDX_D));
- emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
- }
- void LoongArchAsmParser::emitLoadAddressTLSLD(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- // la.tls.ld $rd, sym
- // expands to:
- // pcalau12i $rd, %ld_pc_hi20(sym)
- // addi.w/d $rd, $rd, %got_pc_lo12(sym)
- MCRegister DestReg = Inst.getOperand(0).getReg();
- const MCExpr *Symbol = Inst.getOperand(1).getExpr();
- InstSeq Insts;
- unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20));
- Insts.push_back(LoongArchAsmParser::Inst(
- ADDI, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
- emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
- }
- void LoongArchAsmParser::emitLoadAddressTLSLDLarge(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- // la.tls.ld $rd, $rj, sym
- // expands to:
- // pcalau12i $rd, %ld_pc_hi20(sym)
- // addi.d $rj, $r0, %got_pc_lo12(sym)
- // lu32i.d $rj, %got64_pc_lo20(sym)
- // lu52i.d $rj, $rj, %got64_pc_hi12(sym)
- // add.d $rd, $rd, $rj
- MCRegister DestReg = Inst.getOperand(0).getReg();
- MCRegister TmpReg = Inst.getOperand(1).getReg();
- const MCExpr *Symbol = Inst.getOperand(2).getExpr();
- InstSeq Insts;
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12));
- Insts.push_back(LoongArchAsmParser::Inst(LoongArch::ADD_D));
- emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
- }
- void LoongArchAsmParser::emitLoadAddressTLSGD(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- // la.tls.gd $rd, sym
- // expands to:
- // pcalau12i $rd, %gd_pc_hi20(sym)
- // addi.w/d $rd, $rd, %got_pc_lo12(sym)
- MCRegister DestReg = Inst.getOperand(0).getReg();
- const MCExpr *Symbol = Inst.getOperand(1).getExpr();
- InstSeq Insts;
- unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20));
- Insts.push_back(LoongArchAsmParser::Inst(
- ADDI, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
- emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
- }
- void LoongArchAsmParser::emitLoadAddressTLSGDLarge(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- // la.tls.gd $rd, $rj, sym
- // expands to:
- // pcalau12i $rd, %gd_pc_hi20(sym)
- // addi.d $rj, $r0, %got_pc_lo12(sym)
- // lu32i.d $rj, %got64_pc_lo20(sym)
- // lu52i.d $rj, $rj, %got64_pc_hi12(sym)
- // add.d $rd, $rd, $rj
- MCRegister DestReg = Inst.getOperand(0).getReg();
- MCRegister TmpReg = Inst.getOperand(1).getReg();
- const MCExpr *Symbol = Inst.getOperand(2).getExpr();
- InstSeq Insts;
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20));
- Insts.push_back(LoongArchAsmParser::Inst(
- LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12));
- Insts.push_back(LoongArchAsmParser::Inst(LoongArch::ADD_D));
- emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
- }
- void LoongArchAsmParser::emitLoadImm(MCInst &Inst, SMLoc IDLoc,
- MCStreamer &Out) {
- MCRegister DestReg = Inst.getOperand(0).getReg();
- int64_t Imm = Inst.getOperand(1).getImm();
- MCRegister SrcReg = LoongArch::R0;
- if (Inst.getOpcode() == LoongArch::PseudoLI_W)
- Imm = SignExtend64<32>(Imm);
- for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Imm)) {
- unsigned Opc = Inst.Opc;
- if (Opc == LoongArch::LU12I_W)
- Out.emitInstruction(MCInstBuilder(Opc).addReg(DestReg).addImm(Inst.Imm),
- getSTI());
- else
- Out.emitInstruction(
- MCInstBuilder(Opc).addReg(DestReg).addReg(SrcReg).addImm(Inst.Imm),
- getSTI());
- SrcReg = DestReg;
- }
- }
- bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
- OperandVector &Operands,
- MCStreamer &Out) {
- Inst.setLoc(IDLoc);
- switch (Inst.getOpcode()) {
- default:
- break;
- case LoongArch::PseudoLA_ABS:
- case LoongArch::PseudoLA_ABS_LARGE:
- emitLoadAddressAbs(Inst, IDLoc, Out);
- return false;
- case LoongArch::PseudoLA_PCREL:
- emitLoadAddressPcrel(Inst, IDLoc, Out);
- return false;
- case LoongArch::PseudoLA_PCREL_LARGE:
- emitLoadAddressPcrelLarge(Inst, IDLoc, Out);
- return false;
- case LoongArch::PseudoLA_GOT:
- emitLoadAddressGot(Inst, IDLoc, Out);
- return false;
- case LoongArch::PseudoLA_GOT_LARGE:
- emitLoadAddressGotLarge(Inst, IDLoc, Out);
- return false;
- case LoongArch::PseudoLA_TLS_LE:
- emitLoadAddressTLSLE(Inst, IDLoc, Out);
- return false;
- case LoongArch::PseudoLA_TLS_IE:
- emitLoadAddressTLSIE(Inst, IDLoc, Out);
- return false;
- case LoongArch::PseudoLA_TLS_IE_LARGE:
- emitLoadAddressTLSIELarge(Inst, IDLoc, Out);
- return false;
- case LoongArch::PseudoLA_TLS_LD:
- emitLoadAddressTLSLD(Inst, IDLoc, Out);
- return false;
- case LoongArch::PseudoLA_TLS_LD_LARGE:
- emitLoadAddressTLSLDLarge(Inst, IDLoc, Out);
- return false;
- case LoongArch::PseudoLA_TLS_GD:
- emitLoadAddressTLSGD(Inst, IDLoc, Out);
- return false;
- case LoongArch::PseudoLA_TLS_GD_LARGE:
- emitLoadAddressTLSGDLarge(Inst, IDLoc, Out);
- return false;
- case LoongArch::PseudoLI_W:
- case LoongArch::PseudoLI_D:
- emitLoadImm(Inst, IDLoc, Out);
- return false;
- }
- Out.emitInstruction(Inst, getSTI());
- return false;
- }
- unsigned LoongArchAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
- unsigned Opc = Inst.getOpcode();
- switch (Opc) {
- default:
- if (Opc >= LoongArch::AMADD_D && Opc <= LoongArch::AMXOR_W) {
- unsigned Rd = Inst.getOperand(0).getReg();
- unsigned Rk = Inst.getOperand(1).getReg();
- unsigned Rj = Inst.getOperand(2).getReg();
- if ((Rd == Rk || Rd == Rj) && Rd != LoongArch::R0)
- return Match_RequiresAMORdDifferRkRj;
- }
- break;
- case LoongArch::PseudoLA_PCREL_LARGE:
- case LoongArch::PseudoLA_GOT_LARGE:
- case LoongArch::PseudoLA_TLS_IE_LARGE:
- case LoongArch::PseudoLA_TLS_LD_LARGE:
- case LoongArch::PseudoLA_TLS_GD_LARGE: {
- unsigned Rd = Inst.getOperand(0).getReg();
- unsigned Rj = Inst.getOperand(1).getReg();
- if (Rd == Rj)
- return Match_RequiresLAORdDifferRj;
- break;
- }
- case LoongArch::CSRXCHG: {
- unsigned Rj = Inst.getOperand(2).getReg();
- if (Rj == LoongArch::R0 || Rj == LoongArch::R1)
- return Match_RequiresOpnd2NotR0R1;
- return Match_Success;
- }
- case LoongArch::BSTRINS_W:
- case LoongArch::BSTRINS_D:
- case LoongArch::BSTRPICK_W:
- case LoongArch::BSTRPICK_D: {
- unsigned Opc = Inst.getOpcode();
- const signed Msb =
- (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D)
- ? Inst.getOperand(3).getImm()
- : Inst.getOperand(2).getImm();
- const signed Lsb =
- (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D)
- ? Inst.getOperand(4).getImm()
- : Inst.getOperand(3).getImm();
- if (Msb < Lsb)
- return Match_RequiresMsbNotLessThanLsb;
- return Match_Success;
- }
- }
- return Match_Success;
- }
- unsigned
- LoongArchAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
- unsigned Kind) {
- LoongArchOperand &Op = static_cast<LoongArchOperand &>(AsmOp);
- if (!Op.isReg())
- return Match_InvalidOperand;
- MCRegister Reg = Op.getReg();
- // As the parser couldn't differentiate an FPR32 from an FPR64, coerce the
- // register from FPR32 to FPR64 if necessary.
- if (LoongArchMCRegisterClasses[LoongArch::FPR32RegClassID].contains(Reg) &&
- Kind == MCK_FPR64) {
- Op.setReg(convertFPR32ToFPR64(Reg));
- return Match_Success;
- }
- return Match_InvalidOperand;
- }
- bool LoongArchAsmParser::generateImmOutOfRangeError(
- OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper,
- Twine Msg = "immediate must be an integer in the range") {
- SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
- return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]");
- }
- bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
- OperandVector &Operands,
- MCStreamer &Out,
- uint64_t &ErrorInfo,
- bool MatchingInlineAsm) {
- MCInst Inst;
- FeatureBitset MissingFeatures;
- auto Result = MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures,
- MatchingInlineAsm);
- switch (Result) {
- default:
- break;
- case Match_Success:
- return processInstruction(Inst, IDLoc, Operands, Out);
- case Match_MissingFeature: {
- assert(MissingFeatures.any() && "Unknown missing features!");
- bool FirstFeature = true;
- std::string Msg = "instruction requires the following:";
- for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) {
- if (MissingFeatures[i]) {
- Msg += FirstFeature ? " " : ", ";
- Msg += getSubtargetFeatureName(i);
- FirstFeature = false;
- }
- }
- return Error(IDLoc, Msg);
- }
- case Match_MnemonicFail: {
- FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits());
- std::string Suggestion = LoongArchMnemonicSpellCheck(
- ((LoongArchOperand &)*Operands[0]).getToken(), FBS, 0);
- return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion);
- }
- case Match_InvalidOperand: {
- SMLoc ErrorLoc = IDLoc;
- if (ErrorInfo != ~0ULL) {
- if (ErrorInfo >= Operands.size())
- return Error(ErrorLoc, "too few operands for instruction");
- ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
- if (ErrorLoc == SMLoc())
- ErrorLoc = IDLoc;
- }
- return Error(ErrorLoc, "invalid operand for instruction");
- }
- }
- // Handle the case when the error message is of specific type
- // other than the generic Match_InvalidOperand, and the
- // corresponding operand is missing.
- if (Result > FIRST_TARGET_MATCH_RESULT_TY) {
- SMLoc ErrorLoc = IDLoc;
- if (ErrorInfo != ~0ULL && ErrorInfo >= Operands.size())
- return Error(ErrorLoc, "too few operands for instruction");
- }
- switch (Result) {
- default:
- break;
- case Match_RequiresMsbNotLessThanLsb: {
- SMLoc ErrorStart = Operands[3]->getStartLoc();
- return Error(ErrorStart, "msb is less than lsb",
- SMRange(ErrorStart, Operands[4]->getEndLoc()));
- }
- case Match_RequiresOpnd2NotR0R1:
- return Error(Operands[2]->getStartLoc(), "must not be $r0 or $r1");
- case Match_RequiresAMORdDifferRkRj:
- return Error(Operands[1]->getStartLoc(),
- "$rd must be different from both $rk and $rj");
- case Match_RequiresLAORdDifferRj:
- return Error(Operands[1]->getStartLoc(), "$rd must be different from $rj");
- case Match_InvalidUImm2:
- return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
- /*Upper=*/(1 << 2) - 1);
- case Match_InvalidUImm2plus1:
- return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/1,
- /*Upper=*/(1 << 2));
- case Match_InvalidUImm3:
- return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
- /*Upper=*/(1 << 3) - 1);
- case Match_InvalidUImm5:
- return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
- /*Upper=*/(1 << 5) - 1);
- case Match_InvalidUImm6:
- return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
- /*Upper=*/(1 << 6) - 1);
- case Match_InvalidUImm12:
- return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
- /*Upper=*/(1 << 12) - 1);
- case Match_InvalidUImm12ori:
- return generateImmOutOfRangeError(
- Operands, ErrorInfo, /*Lower=*/0,
- /*Upper=*/(1 << 12) - 1,
- "operand must be a symbol with modifier (e.g. %abs_lo12) or an "
- "integer in the range");
- case Match_InvalidUImm15:
- return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
- /*Upper=*/(1 << 15) - 1);
- case Match_InvalidSImm12:
- return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 11),
- /*Upper=*/(1 << 11) - 1);
- case Match_InvalidSImm12addlike:
- return generateImmOutOfRangeError(
- Operands, ErrorInfo, /*Lower=*/-(1 << 11),
- /*Upper=*/(1 << 11) - 1,
- "operand must be a symbol with modifier (e.g. %pc_lo12) or an integer "
- "in the range");
- case Match_InvalidSImm12lu52id:
- return generateImmOutOfRangeError(
- Operands, ErrorInfo, /*Lower=*/-(1 << 11),
- /*Upper=*/(1 << 11) - 1,
- "operand must be a symbol with modifier (e.g. %pc64_hi12) or an "
- "integer in the range");
- case Match_InvalidSImm14lsl2:
- return generateImmOutOfRangeError(
- Operands, ErrorInfo, /*Lower=*/-(1 << 15), /*Upper=*/(1 << 15) - 4,
- "immediate must be a multiple of 4 in the range");
- case Match_InvalidSImm16:
- return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 15),
- /*Upper=*/(1 << 15) - 1);
- case Match_InvalidSImm16lsl2:
- return generateImmOutOfRangeError(
- Operands, ErrorInfo, /*Lower=*/-(1 << 17), /*Upper=*/(1 << 17) - 4,
- "operand must be a symbol with modifier (e.g. %b16) or an integer "
- "in the range");
- case Match_InvalidSImm20:
- return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 19),
- /*Upper=*/(1 << 19) - 1);
- case Match_InvalidSImm20lu12iw:
- return generateImmOutOfRangeError(
- Operands, ErrorInfo, /*Lower=*/-(1 << 19),
- /*Upper=*/(1 << 19) - 1,
- "operand must be a symbol with modifier (e.g. %abs_hi20) or an integer "
- "in the range");
- case Match_InvalidSImm20lu32id:
- return generateImmOutOfRangeError(
- Operands, ErrorInfo, /*Lower=*/-(1 << 19),
- /*Upper=*/(1 << 19) - 1,
- "operand must be a symbol with modifier (e.g. %abs64_lo20) or an "
- "integer in the range");
- case Match_InvalidSImm20pcalau12i:
- return generateImmOutOfRangeError(
- Operands, ErrorInfo, /*Lower=*/-(1 << 19),
- /*Upper=*/(1 << 19) - 1,
- "operand must be a symbol with modifier (e.g. %pc_hi20) or an integer "
- "in the range");
- case Match_InvalidSImm21lsl2:
- return generateImmOutOfRangeError(
- Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4,
- "operand must be a symbol with modifier (e.g. %b21) or an integer "
- "in the range");
- case Match_InvalidSImm26Operand:
- return generateImmOutOfRangeError(
- Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4,
- "operand must be a bare symbol name or an immediate must be a multiple "
- "of 4 in the range");
- case Match_InvalidImm32: {
- SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
- return Error(ErrorLoc, "operand must be a 32 bit immediate");
- }
- case Match_InvalidBareSymbol: {
- SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc();
- return Error(ErrorLoc, "operand must be a bare symbol name");
- }
- }
- llvm_unreachable("Unknown match type detected!");
- }
- extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() {
- RegisterMCAsmParser<LoongArchAsmParser> X(getTheLoongArch32Target());
- RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target());
- }
|