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" 1081ad6265SDimitry Andric #include "MCTargetDesc/LoongArchMCTargetDesc.h" 1181ad6265SDimitry Andric #include "TargetInfo/LoongArchTargetInfo.h" 1281ad6265SDimitry Andric #include "llvm/MC/MCContext.h" 1381ad6265SDimitry Andric #include "llvm/MC/MCInstrInfo.h" 1481ad6265SDimitry Andric #include "llvm/MC/MCParser/MCAsmLexer.h" 1581ad6265SDimitry Andric #include "llvm/MC/MCParser/MCParsedAsmOperand.h" 1681ad6265SDimitry Andric #include "llvm/MC/MCParser/MCTargetAsmParser.h" 1781ad6265SDimitry Andric #include "llvm/MC/MCRegisterInfo.h" 1881ad6265SDimitry Andric #include "llvm/MC/MCStreamer.h" 1981ad6265SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h" 2081ad6265SDimitry Andric #include "llvm/MC/TargetRegistry.h" 2181ad6265SDimitry Andric #include "llvm/Support/Casting.h" 2281ad6265SDimitry Andric 2381ad6265SDimitry Andric using namespace llvm; 2481ad6265SDimitry Andric 2581ad6265SDimitry Andric #define DEBUG_TYPE "loongarch-asm-parser" 2681ad6265SDimitry Andric 2781ad6265SDimitry Andric namespace { 2881ad6265SDimitry Andric class LoongArchAsmParser : public MCTargetAsmParser { 2981ad6265SDimitry Andric SMLoc getLoc() const { return getParser().getTok().getLoc(); } 3081ad6265SDimitry Andric 3181ad6265SDimitry Andric /// Parse a register as used in CFI directives. 3281ad6265SDimitry Andric bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; 3381ad6265SDimitry Andric OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc, 3481ad6265SDimitry Andric SMLoc &EndLoc) override; 3581ad6265SDimitry Andric 3681ad6265SDimitry Andric bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, 3781ad6265SDimitry Andric SMLoc NameLoc, OperandVector &Operands) override; 3881ad6265SDimitry Andric 3981ad6265SDimitry Andric bool ParseDirective(AsmToken DirectiveID) override { return true; } 4081ad6265SDimitry Andric 4181ad6265SDimitry Andric bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, 4281ad6265SDimitry Andric OperandVector &Operands, MCStreamer &Out, 4381ad6265SDimitry Andric uint64_t &ErrorInfo, 4481ad6265SDimitry Andric bool MatchingInlineAsm) override; 4581ad6265SDimitry Andric 4681ad6265SDimitry Andric unsigned checkTargetMatchPredicate(MCInst &Inst) override; 4781ad6265SDimitry Andric 4881ad6265SDimitry Andric unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, 4981ad6265SDimitry Andric unsigned Kind) override; 5081ad6265SDimitry Andric 5181ad6265SDimitry Andric bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo, 5281ad6265SDimitry Andric int64_t Lower, int64_t Upper, Twine Msg); 5381ad6265SDimitry Andric 5481ad6265SDimitry Andric /// Helper for processing MC instructions that have been successfully matched 5581ad6265SDimitry Andric /// by MatchAndEmitInstruction. 5681ad6265SDimitry Andric bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands, 5781ad6265SDimitry Andric MCStreamer &Out); 5881ad6265SDimitry Andric 5981ad6265SDimitry Andric // Auto-generated instruction matching functions. 6081ad6265SDimitry Andric #define GET_ASSEMBLER_HEADER 6181ad6265SDimitry Andric #include "LoongArchGenAsmMatcher.inc" 6281ad6265SDimitry Andric 6381ad6265SDimitry Andric OperandMatchResultTy parseRegister(OperandVector &Operands); 6481ad6265SDimitry Andric OperandMatchResultTy parseImmediate(OperandVector &Operands); 6581ad6265SDimitry Andric 6681ad6265SDimitry Andric bool parseOperand(OperandVector &Operands, StringRef Mnemonic); 6781ad6265SDimitry Andric 6881ad6265SDimitry Andric public: 6981ad6265SDimitry Andric enum LoongArchMatchResultTy { 7081ad6265SDimitry Andric Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, 7181ad6265SDimitry Andric Match_RequiresMsbNotLessThanLsb, 7281ad6265SDimitry Andric Match_RequiresOpnd2NotR0R1, 7381ad6265SDimitry Andric #define GET_OPERAND_DIAGNOSTIC_TYPES 7481ad6265SDimitry Andric #include "LoongArchGenAsmMatcher.inc" 7581ad6265SDimitry Andric #undef GET_OPERAND_DIAGNOSTIC_TYPES 7681ad6265SDimitry Andric }; 7781ad6265SDimitry Andric 7881ad6265SDimitry Andric LoongArchAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, 7981ad6265SDimitry Andric const MCInstrInfo &MII, const MCTargetOptions &Options) 8081ad6265SDimitry Andric : MCTargetAsmParser(Options, STI, MII) { 8181ad6265SDimitry Andric Parser.addAliasForDirective(".half", ".2byte"); 8281ad6265SDimitry Andric Parser.addAliasForDirective(".hword", ".2byte"); 8381ad6265SDimitry Andric Parser.addAliasForDirective(".word", ".4byte"); 8481ad6265SDimitry Andric Parser.addAliasForDirective(".dword", ".8byte"); 8581ad6265SDimitry Andric 8681ad6265SDimitry Andric // Initialize the set of available features. 8781ad6265SDimitry Andric setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); 8881ad6265SDimitry Andric } 8981ad6265SDimitry Andric }; 9081ad6265SDimitry Andric 9181ad6265SDimitry Andric // Instances of this class represent a parsed LoongArch machine instruction. 9281ad6265SDimitry Andric class LoongArchOperand : public MCParsedAsmOperand { 9381ad6265SDimitry Andric enum class KindTy { 9481ad6265SDimitry Andric Token, 9581ad6265SDimitry Andric Register, 9681ad6265SDimitry Andric Immediate, 9781ad6265SDimitry Andric } Kind; 9881ad6265SDimitry Andric 9981ad6265SDimitry Andric struct RegOp { 10081ad6265SDimitry Andric MCRegister RegNum; 10181ad6265SDimitry Andric }; 10281ad6265SDimitry Andric 10381ad6265SDimitry Andric struct ImmOp { 10481ad6265SDimitry Andric const MCExpr *Val; 10581ad6265SDimitry Andric }; 10681ad6265SDimitry Andric 10781ad6265SDimitry Andric SMLoc StartLoc, EndLoc; 10881ad6265SDimitry Andric union { 10981ad6265SDimitry Andric StringRef Tok; 11081ad6265SDimitry Andric struct RegOp Reg; 11181ad6265SDimitry Andric struct ImmOp Imm; 11281ad6265SDimitry Andric }; 11381ad6265SDimitry Andric 11481ad6265SDimitry Andric public: 11581ad6265SDimitry Andric LoongArchOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} 11681ad6265SDimitry Andric 11781ad6265SDimitry Andric bool isToken() const override { return Kind == KindTy::Token; } 11881ad6265SDimitry Andric bool isReg() const override { return Kind == KindTy::Register; } 11981ad6265SDimitry Andric bool isImm() const override { return Kind == KindTy::Immediate; } 12081ad6265SDimitry Andric bool isMem() const override { return false; } 12181ad6265SDimitry Andric void setReg(MCRegister PhysReg) { Reg.RegNum = PhysReg; } 12281ad6265SDimitry Andric 12381ad6265SDimitry Andric static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm) { 12481ad6265SDimitry Andric if (auto CE = dyn_cast<MCConstantExpr>(Expr)) { 12581ad6265SDimitry Andric Imm = CE->getValue(); 12681ad6265SDimitry Andric return true; 12781ad6265SDimitry Andric } 12881ad6265SDimitry Andric 12981ad6265SDimitry Andric return false; 13081ad6265SDimitry Andric } 13181ad6265SDimitry Andric 13281ad6265SDimitry Andric template <unsigned N, int P = 0> bool isUImm() const { 13381ad6265SDimitry Andric if (!isImm()) 13481ad6265SDimitry Andric return false; 13581ad6265SDimitry Andric 13681ad6265SDimitry Andric int64_t Imm; 13781ad6265SDimitry Andric bool IsConstantImm = evaluateConstantImm(getImm(), Imm); 13881ad6265SDimitry Andric return IsConstantImm && isUInt<N>(Imm - P); 13981ad6265SDimitry Andric } 14081ad6265SDimitry Andric 14181ad6265SDimitry Andric template <unsigned N, unsigned S = 0> bool isSImm() const { 14281ad6265SDimitry Andric if (!isImm()) 14381ad6265SDimitry Andric return false; 14481ad6265SDimitry Andric 14581ad6265SDimitry Andric int64_t Imm; 14681ad6265SDimitry Andric bool IsConstantImm = evaluateConstantImm(getImm(), Imm); 14781ad6265SDimitry Andric return IsConstantImm && isShiftedInt<N, S>(Imm); 14881ad6265SDimitry Andric } 14981ad6265SDimitry Andric 15081ad6265SDimitry Andric bool isUImm2() const { return isUImm<2>(); } 15181ad6265SDimitry Andric bool isUImm2plus1() const { return isUImm<2, 1>(); } 15281ad6265SDimitry Andric bool isUImm3() const { return isUImm<3>(); } 15381ad6265SDimitry Andric bool isUImm5() const { return isUImm<5>(); } 15481ad6265SDimitry Andric bool isUImm6() const { return isUImm<6>(); } 15581ad6265SDimitry Andric bool isUImm8() const { return isUImm<8>(); } 15681ad6265SDimitry Andric bool isUImm12() const { return isUImm<12>(); } 15781ad6265SDimitry Andric bool isUImm14() const { return isUImm<14>(); } 15881ad6265SDimitry Andric bool isUImm15() const { return isUImm<15>(); } 15981ad6265SDimitry Andric bool isSImm12() const { return isSImm<12>(); } 16081ad6265SDimitry Andric bool isSImm14lsl2() const { return isSImm<14, 2>(); } 16181ad6265SDimitry Andric bool isSImm16() const { return isSImm<16>(); } 16281ad6265SDimitry Andric bool isSImm16lsl2() const { return isSImm<16, 2>(); } 16381ad6265SDimitry Andric bool isSImm20() const { return isSImm<20>(); } 16481ad6265SDimitry Andric bool isSImm21lsl2() const { return isSImm<21, 2>(); } 16581ad6265SDimitry Andric bool isSImm26lsl2() const { return isSImm<26, 2>(); } 16681ad6265SDimitry Andric 16781ad6265SDimitry Andric /// Gets location of the first token of this operand. 16881ad6265SDimitry Andric SMLoc getStartLoc() const override { return StartLoc; } 16981ad6265SDimitry Andric /// Gets location of the last token of this operand. 17081ad6265SDimitry Andric SMLoc getEndLoc() const override { return EndLoc; } 17181ad6265SDimitry Andric 17281ad6265SDimitry Andric unsigned getReg() const override { 17381ad6265SDimitry Andric assert(Kind == KindTy::Register && "Invalid type access!"); 17481ad6265SDimitry Andric return Reg.RegNum.id(); 17581ad6265SDimitry Andric } 17681ad6265SDimitry Andric 17781ad6265SDimitry Andric const MCExpr *getImm() const { 17881ad6265SDimitry Andric assert(Kind == KindTy::Immediate && "Invalid type access!"); 17981ad6265SDimitry Andric return Imm.Val; 18081ad6265SDimitry Andric } 18181ad6265SDimitry Andric 18281ad6265SDimitry Andric StringRef getToken() const { 18381ad6265SDimitry Andric assert(Kind == KindTy::Token && "Invalid type access!"); 18481ad6265SDimitry Andric return Tok; 18581ad6265SDimitry Andric } 18681ad6265SDimitry Andric 18781ad6265SDimitry Andric void print(raw_ostream &OS) const override { 18881ad6265SDimitry Andric auto RegName = [](unsigned Reg) { 18981ad6265SDimitry Andric if (Reg) 19081ad6265SDimitry Andric return LoongArchInstPrinter::getRegisterName(Reg); 19181ad6265SDimitry Andric else 19281ad6265SDimitry Andric return "noreg"; 19381ad6265SDimitry Andric }; 19481ad6265SDimitry Andric 19581ad6265SDimitry Andric switch (Kind) { 19681ad6265SDimitry Andric case KindTy::Immediate: 19781ad6265SDimitry Andric OS << *getImm(); 19881ad6265SDimitry Andric break; 19981ad6265SDimitry Andric case KindTy::Register: 20081ad6265SDimitry Andric OS << "<register " << RegName(getReg()) << ">"; 20181ad6265SDimitry Andric break; 20281ad6265SDimitry Andric case KindTy::Token: 20381ad6265SDimitry Andric OS << "'" << getToken() << "'"; 20481ad6265SDimitry Andric break; 20581ad6265SDimitry Andric } 20681ad6265SDimitry Andric } 20781ad6265SDimitry Andric 20881ad6265SDimitry Andric static std::unique_ptr<LoongArchOperand> createToken(StringRef Str, SMLoc S) { 20981ad6265SDimitry Andric auto Op = std::make_unique<LoongArchOperand>(KindTy::Token); 21081ad6265SDimitry Andric Op->Tok = Str; 21181ad6265SDimitry Andric Op->StartLoc = S; 21281ad6265SDimitry Andric Op->EndLoc = S; 21381ad6265SDimitry Andric return Op; 21481ad6265SDimitry Andric } 21581ad6265SDimitry Andric 21681ad6265SDimitry Andric static std::unique_ptr<LoongArchOperand> createReg(unsigned RegNo, SMLoc S, 21781ad6265SDimitry Andric SMLoc E) { 21881ad6265SDimitry Andric auto Op = std::make_unique<LoongArchOperand>(KindTy::Register); 21981ad6265SDimitry Andric Op->Reg.RegNum = RegNo; 22081ad6265SDimitry Andric Op->StartLoc = S; 22181ad6265SDimitry Andric Op->EndLoc = E; 22281ad6265SDimitry Andric return Op; 22381ad6265SDimitry Andric } 22481ad6265SDimitry Andric 22581ad6265SDimitry Andric static std::unique_ptr<LoongArchOperand> createImm(const MCExpr *Val, SMLoc S, 22681ad6265SDimitry Andric SMLoc E) { 22781ad6265SDimitry Andric auto Op = std::make_unique<LoongArchOperand>(KindTy::Immediate); 22881ad6265SDimitry Andric Op->Imm.Val = Val; 22981ad6265SDimitry Andric Op->StartLoc = S; 23081ad6265SDimitry Andric Op->EndLoc = E; 23181ad6265SDimitry Andric return Op; 23281ad6265SDimitry Andric } 23381ad6265SDimitry Andric 23481ad6265SDimitry Andric void addExpr(MCInst &Inst, const MCExpr *Expr) const { 23581ad6265SDimitry Andric if (auto CE = dyn_cast<MCConstantExpr>(Expr)) 23681ad6265SDimitry Andric Inst.addOperand(MCOperand::createImm(CE->getValue())); 23781ad6265SDimitry Andric else 23881ad6265SDimitry Andric Inst.addOperand(MCOperand::createExpr(Expr)); 23981ad6265SDimitry Andric } 24081ad6265SDimitry Andric 24181ad6265SDimitry Andric // Used by the TableGen Code. 24281ad6265SDimitry Andric void addRegOperands(MCInst &Inst, unsigned N) const { 24381ad6265SDimitry Andric assert(N == 1 && "Invalid number of operands!"); 24481ad6265SDimitry Andric Inst.addOperand(MCOperand::createReg(getReg())); 24581ad6265SDimitry Andric } 24681ad6265SDimitry Andric void addImmOperands(MCInst &Inst, unsigned N) const { 24781ad6265SDimitry Andric assert(N == 1 && "Invalid number of operands!"); 24881ad6265SDimitry Andric addExpr(Inst, getImm()); 24981ad6265SDimitry Andric } 25081ad6265SDimitry Andric }; 251*972a253aSDimitry Andric } // end namespace 25281ad6265SDimitry Andric 25381ad6265SDimitry Andric #define GET_REGISTER_MATCHER 25481ad6265SDimitry Andric #define GET_SUBTARGET_FEATURE_NAME 25581ad6265SDimitry Andric #define GET_MATCHER_IMPLEMENTATION 25681ad6265SDimitry Andric #define GET_MNEMONIC_SPELL_CHECKER 25781ad6265SDimitry Andric #include "LoongArchGenAsmMatcher.inc" 25881ad6265SDimitry Andric 25981ad6265SDimitry Andric static MCRegister convertFPR32ToFPR64(MCRegister Reg) { 26081ad6265SDimitry Andric assert(Reg >= LoongArch::F0 && Reg <= LoongArch::F31 && "Invalid register"); 26181ad6265SDimitry Andric return Reg - LoongArch::F0 + LoongArch::F0_64; 26281ad6265SDimitry Andric } 26381ad6265SDimitry Andric 26481ad6265SDimitry Andric // Attempts to match Name as a register (either using the default name or 26581ad6265SDimitry Andric // alternative ABI names), setting RegNo to the matching register. Upon 26681ad6265SDimitry Andric // failure, returns true and sets RegNo to 0. 26781ad6265SDimitry Andric static bool matchRegisterNameHelper(MCRegister &RegNo, StringRef Name) { 26881ad6265SDimitry Andric RegNo = MatchRegisterName(Name); 26981ad6265SDimitry Andric // The 32-bit and 64-bit FPRs have the same asm name. Check that the initial 27081ad6265SDimitry Andric // match always matches the 32-bit variant, and not the 64-bit one. 27181ad6265SDimitry Andric assert(!(RegNo >= LoongArch::F0_64 && RegNo <= LoongArch::F31_64)); 27281ad6265SDimitry Andric // The default FPR register class is based on the tablegen enum ordering. 27381ad6265SDimitry Andric static_assert(LoongArch::F0 < LoongArch::F0_64, 27481ad6265SDimitry Andric "FPR matching must be updated"); 27581ad6265SDimitry Andric if (RegNo == LoongArch::NoRegister) 27681ad6265SDimitry Andric RegNo = MatchRegisterAltName(Name); 27781ad6265SDimitry Andric 27881ad6265SDimitry Andric return RegNo == LoongArch::NoRegister; 27981ad6265SDimitry Andric } 28081ad6265SDimitry Andric 28181ad6265SDimitry Andric bool LoongArchAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, 28281ad6265SDimitry Andric SMLoc &EndLoc) { 28381ad6265SDimitry Andric return Error(getLoc(), "invalid register number"); 28481ad6265SDimitry Andric } 28581ad6265SDimitry Andric 28681ad6265SDimitry Andric OperandMatchResultTy LoongArchAsmParser::tryParseRegister(unsigned &RegNo, 28781ad6265SDimitry Andric SMLoc &StartLoc, 28881ad6265SDimitry Andric SMLoc &EndLoc) { 28981ad6265SDimitry Andric llvm_unreachable("Unimplemented function."); 29081ad6265SDimitry Andric } 29181ad6265SDimitry Andric 29281ad6265SDimitry Andric OperandMatchResultTy 29381ad6265SDimitry Andric LoongArchAsmParser::parseRegister(OperandVector &Operands) { 29481ad6265SDimitry Andric if (getLexer().getTok().isNot(AsmToken::Dollar)) 29581ad6265SDimitry Andric return MatchOperand_NoMatch; 29681ad6265SDimitry Andric 29781ad6265SDimitry Andric // Eat the $ prefix. 29881ad6265SDimitry Andric getLexer().Lex(); 29981ad6265SDimitry Andric if (getLexer().getKind() != AsmToken::Identifier) 30081ad6265SDimitry Andric return MatchOperand_NoMatch; 30181ad6265SDimitry Andric 30281ad6265SDimitry Andric StringRef Name = getLexer().getTok().getIdentifier(); 30381ad6265SDimitry Andric MCRegister RegNo; 30481ad6265SDimitry Andric matchRegisterNameHelper(RegNo, Name); 30581ad6265SDimitry Andric if (RegNo == LoongArch::NoRegister) 30681ad6265SDimitry Andric return MatchOperand_NoMatch; 30781ad6265SDimitry Andric 30881ad6265SDimitry Andric SMLoc S = getLoc(); 30981ad6265SDimitry Andric SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size()); 31081ad6265SDimitry Andric getLexer().Lex(); 31181ad6265SDimitry Andric Operands.push_back(LoongArchOperand::createReg(RegNo, S, E)); 31281ad6265SDimitry Andric 31381ad6265SDimitry Andric return MatchOperand_Success; 31481ad6265SDimitry Andric } 31581ad6265SDimitry Andric 31681ad6265SDimitry Andric OperandMatchResultTy 31781ad6265SDimitry Andric LoongArchAsmParser::parseImmediate(OperandVector &Operands) { 31881ad6265SDimitry Andric SMLoc S = getLoc(); 31981ad6265SDimitry Andric SMLoc E; 32081ad6265SDimitry Andric const MCExpr *Res; 32181ad6265SDimitry Andric 32281ad6265SDimitry Andric if (getParser().parseExpression(Res, E)) 32381ad6265SDimitry Andric return MatchOperand_ParseFail; 32481ad6265SDimitry Andric 32581ad6265SDimitry Andric Operands.push_back(LoongArchOperand::createImm(Res, S, E)); 32681ad6265SDimitry Andric return MatchOperand_Success; 32781ad6265SDimitry Andric } 32881ad6265SDimitry Andric 32981ad6265SDimitry Andric /// Looks at a token type and creates the relevant operand from this 33081ad6265SDimitry Andric /// information, adding to Operands. Return true upon an error. 33181ad6265SDimitry Andric bool LoongArchAsmParser::parseOperand(OperandVector &Operands, 33281ad6265SDimitry Andric StringRef Mnemonic) { 33381ad6265SDimitry Andric if (parseRegister(Operands) == MatchOperand_Success || 33481ad6265SDimitry Andric parseImmediate(Operands) == MatchOperand_Success) 33581ad6265SDimitry Andric return false; 33681ad6265SDimitry Andric 33781ad6265SDimitry Andric // Finally we have exhausted all options and must declare defeat. 33881ad6265SDimitry Andric Error(getLoc(), "unknown operand"); 33981ad6265SDimitry Andric return true; 34081ad6265SDimitry Andric } 34181ad6265SDimitry Andric 34281ad6265SDimitry Andric bool LoongArchAsmParser::ParseInstruction(ParseInstructionInfo &Info, 34381ad6265SDimitry Andric StringRef Name, SMLoc NameLoc, 34481ad6265SDimitry Andric OperandVector &Operands) { 34581ad6265SDimitry Andric // First operand in MCInst is instruction mnemonic. 34681ad6265SDimitry Andric Operands.push_back(LoongArchOperand::createToken(Name, NameLoc)); 34781ad6265SDimitry Andric 34881ad6265SDimitry Andric // If there are no more operands, then finish. 34981ad6265SDimitry Andric if (parseOptionalToken(AsmToken::EndOfStatement)) 35081ad6265SDimitry Andric return false; 35181ad6265SDimitry Andric 35281ad6265SDimitry Andric // Parse first operand. 35381ad6265SDimitry Andric if (parseOperand(Operands, Name)) 35481ad6265SDimitry Andric return true; 35581ad6265SDimitry Andric 35681ad6265SDimitry Andric // Parse until end of statement, consuming commas between operands. 35781ad6265SDimitry Andric while (parseOptionalToken(AsmToken::Comma)) 35881ad6265SDimitry Andric if (parseOperand(Operands, Name)) 35981ad6265SDimitry Andric return true; 36081ad6265SDimitry Andric 36181ad6265SDimitry Andric // Parse end of statement and return successfully. 36281ad6265SDimitry Andric if (parseOptionalToken(AsmToken::EndOfStatement)) 36381ad6265SDimitry Andric return false; 36481ad6265SDimitry Andric 36581ad6265SDimitry Andric SMLoc Loc = getLexer().getLoc(); 36681ad6265SDimitry Andric getParser().eatToEndOfStatement(); 36781ad6265SDimitry Andric return Error(Loc, "unexpected token"); 36881ad6265SDimitry Andric } 36981ad6265SDimitry Andric 37081ad6265SDimitry Andric bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, 37181ad6265SDimitry Andric OperandVector &Operands, 37281ad6265SDimitry Andric MCStreamer &Out) { 37381ad6265SDimitry Andric Inst.setLoc(IDLoc); 37481ad6265SDimitry Andric Out.emitInstruction(Inst, getSTI()); 37581ad6265SDimitry Andric return false; 37681ad6265SDimitry Andric } 37781ad6265SDimitry Andric 37881ad6265SDimitry Andric unsigned LoongArchAsmParser::checkTargetMatchPredicate(MCInst &Inst) { 37981ad6265SDimitry Andric switch (Inst.getOpcode()) { 38081ad6265SDimitry Andric default: 38181ad6265SDimitry Andric break; 38281ad6265SDimitry Andric case LoongArch::CSRXCHG: { 38381ad6265SDimitry Andric unsigned Rj = Inst.getOperand(2).getReg(); 38481ad6265SDimitry Andric if (Rj == LoongArch::R0 || Rj == LoongArch::R1) 38581ad6265SDimitry Andric return Match_RequiresOpnd2NotR0R1; 38681ad6265SDimitry Andric return Match_Success; 38781ad6265SDimitry Andric } 38881ad6265SDimitry Andric case LoongArch::BSTRINS_W: 38981ad6265SDimitry Andric case LoongArch::BSTRINS_D: 39081ad6265SDimitry Andric case LoongArch::BSTRPICK_W: 39181ad6265SDimitry Andric case LoongArch::BSTRPICK_D: { 39281ad6265SDimitry Andric unsigned Opc = Inst.getOpcode(); 39381ad6265SDimitry Andric const signed Msb = 39481ad6265SDimitry Andric (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D) 39581ad6265SDimitry Andric ? Inst.getOperand(3).getImm() 39681ad6265SDimitry Andric : Inst.getOperand(2).getImm(); 39781ad6265SDimitry Andric const signed Lsb = 39881ad6265SDimitry Andric (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D) 39981ad6265SDimitry Andric ? Inst.getOperand(4).getImm() 40081ad6265SDimitry Andric : Inst.getOperand(3).getImm(); 40181ad6265SDimitry Andric if (Msb < Lsb) 40281ad6265SDimitry Andric return Match_RequiresMsbNotLessThanLsb; 40381ad6265SDimitry Andric return Match_Success; 40481ad6265SDimitry Andric } 40581ad6265SDimitry Andric } 40681ad6265SDimitry Andric 40781ad6265SDimitry Andric return Match_Success; 40881ad6265SDimitry Andric } 40981ad6265SDimitry Andric 41081ad6265SDimitry Andric unsigned 41181ad6265SDimitry Andric LoongArchAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, 41281ad6265SDimitry Andric unsigned Kind) { 41381ad6265SDimitry Andric LoongArchOperand &Op = static_cast<LoongArchOperand &>(AsmOp); 41481ad6265SDimitry Andric if (!Op.isReg()) 41581ad6265SDimitry Andric return Match_InvalidOperand; 41681ad6265SDimitry Andric 41781ad6265SDimitry Andric MCRegister Reg = Op.getReg(); 41881ad6265SDimitry Andric // As the parser couldn't differentiate an FPR32 from an FPR64, coerce the 41981ad6265SDimitry Andric // register from FPR32 to FPR64 if necessary. 42081ad6265SDimitry Andric if (LoongArchMCRegisterClasses[LoongArch::FPR32RegClassID].contains(Reg) && 42181ad6265SDimitry Andric Kind == MCK_FPR64) { 42281ad6265SDimitry Andric Op.setReg(convertFPR32ToFPR64(Reg)); 42381ad6265SDimitry Andric return Match_Success; 42481ad6265SDimitry Andric } 42581ad6265SDimitry Andric 42681ad6265SDimitry Andric return Match_InvalidOperand; 42781ad6265SDimitry Andric } 42881ad6265SDimitry Andric 42981ad6265SDimitry Andric bool LoongArchAsmParser::generateImmOutOfRangeError( 43081ad6265SDimitry Andric OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper, 43181ad6265SDimitry Andric Twine Msg = "immediate must be an integer in the range") { 43281ad6265SDimitry Andric SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); 43381ad6265SDimitry Andric return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]"); 43481ad6265SDimitry Andric } 43581ad6265SDimitry Andric 43681ad6265SDimitry Andric bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, 43781ad6265SDimitry Andric OperandVector &Operands, 43881ad6265SDimitry Andric MCStreamer &Out, 43981ad6265SDimitry Andric uint64_t &ErrorInfo, 44081ad6265SDimitry Andric bool MatchingInlineAsm) { 44181ad6265SDimitry Andric MCInst Inst; 44281ad6265SDimitry Andric FeatureBitset MissingFeatures; 44381ad6265SDimitry Andric 44481ad6265SDimitry Andric auto Result = MatchInstructionImpl(Operands, Inst, ErrorInfo, MissingFeatures, 44581ad6265SDimitry Andric MatchingInlineAsm); 44681ad6265SDimitry Andric switch (Result) { 44781ad6265SDimitry Andric default: 44881ad6265SDimitry Andric break; 44981ad6265SDimitry Andric case Match_Success: 45081ad6265SDimitry Andric return processInstruction(Inst, IDLoc, Operands, Out); 45181ad6265SDimitry Andric case Match_MissingFeature: { 45281ad6265SDimitry Andric assert(MissingFeatures.any() && "Unknown missing features!"); 45381ad6265SDimitry Andric bool FirstFeature = true; 45481ad6265SDimitry Andric std::string Msg = "instruction requires the following:"; 45581ad6265SDimitry Andric for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) { 45681ad6265SDimitry Andric if (MissingFeatures[i]) { 45781ad6265SDimitry Andric Msg += FirstFeature ? " " : ", "; 45881ad6265SDimitry Andric Msg += getSubtargetFeatureName(i); 45981ad6265SDimitry Andric FirstFeature = false; 46081ad6265SDimitry Andric } 46181ad6265SDimitry Andric } 46281ad6265SDimitry Andric return Error(IDLoc, Msg); 46381ad6265SDimitry Andric } 46481ad6265SDimitry Andric case Match_MnemonicFail: { 46581ad6265SDimitry Andric FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits()); 46681ad6265SDimitry Andric std::string Suggestion = LoongArchMnemonicSpellCheck( 46781ad6265SDimitry Andric ((LoongArchOperand &)*Operands[0]).getToken(), FBS, 0); 46881ad6265SDimitry Andric return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion); 46981ad6265SDimitry Andric } 47081ad6265SDimitry Andric case Match_InvalidOperand: { 47181ad6265SDimitry Andric SMLoc ErrorLoc = IDLoc; 47281ad6265SDimitry Andric if (ErrorInfo != ~0ULL) { 47381ad6265SDimitry Andric if (ErrorInfo >= Operands.size()) 47481ad6265SDimitry Andric return Error(ErrorLoc, "too few operands for instruction"); 47581ad6265SDimitry Andric 47681ad6265SDimitry Andric ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); 47781ad6265SDimitry Andric if (ErrorLoc == SMLoc()) 47881ad6265SDimitry Andric ErrorLoc = IDLoc; 47981ad6265SDimitry Andric } 48081ad6265SDimitry Andric return Error(ErrorLoc, "invalid operand for instruction"); 48181ad6265SDimitry Andric } 48281ad6265SDimitry Andric } 48381ad6265SDimitry Andric 48481ad6265SDimitry Andric // Handle the case when the error message is of specific type 48581ad6265SDimitry Andric // other than the generic Match_InvalidOperand, and the 48681ad6265SDimitry Andric // corresponding operand is missing. 48781ad6265SDimitry Andric if (Result > FIRST_TARGET_MATCH_RESULT_TY) { 48881ad6265SDimitry Andric SMLoc ErrorLoc = IDLoc; 48981ad6265SDimitry Andric if (ErrorInfo != ~0ULL && ErrorInfo >= Operands.size()) 49081ad6265SDimitry Andric return Error(ErrorLoc, "too few operands for instruction"); 49181ad6265SDimitry Andric } 49281ad6265SDimitry Andric 49381ad6265SDimitry Andric switch (Result) { 49481ad6265SDimitry Andric default: 49581ad6265SDimitry Andric break; 49681ad6265SDimitry Andric case Match_RequiresMsbNotLessThanLsb: { 49781ad6265SDimitry Andric SMLoc ErrorStart = Operands[3]->getStartLoc(); 49881ad6265SDimitry Andric return Error(ErrorStart, "msb is less than lsb", 49981ad6265SDimitry Andric SMRange(ErrorStart, Operands[4]->getEndLoc())); 50081ad6265SDimitry Andric } 50181ad6265SDimitry Andric case Match_RequiresOpnd2NotR0R1: 50281ad6265SDimitry Andric return Error(Operands[2]->getStartLoc(), "must not be $r0 or $r1"); 50381ad6265SDimitry Andric case Match_InvalidUImm2: 50481ad6265SDimitry Andric return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, 50581ad6265SDimitry Andric /*Upper=*/(1 << 2) - 1); 50681ad6265SDimitry Andric case Match_InvalidUImm2plus1: 50781ad6265SDimitry Andric return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/1, 50881ad6265SDimitry Andric /*Upper=*/(1 << 2)); 50981ad6265SDimitry Andric case Match_InvalidUImm3: 51081ad6265SDimitry Andric return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, 51181ad6265SDimitry Andric /*Upper=*/(1 << 3) - 1); 51281ad6265SDimitry Andric case Match_InvalidUImm5: 51381ad6265SDimitry Andric return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, 51481ad6265SDimitry Andric /*Upper=*/(1 << 5) - 1); 51581ad6265SDimitry Andric case Match_InvalidUImm6: 51681ad6265SDimitry Andric return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, 51781ad6265SDimitry Andric /*Upper=*/(1 << 6) - 1); 51881ad6265SDimitry Andric case Match_InvalidUImm12: 51981ad6265SDimitry Andric return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, 52081ad6265SDimitry Andric /*Upper=*/(1 << 12) - 1); 52181ad6265SDimitry Andric case Match_InvalidUImm15: 52281ad6265SDimitry Andric return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, 52381ad6265SDimitry Andric /*Upper=*/(1 << 15) - 1); 52481ad6265SDimitry Andric case Match_InvalidSImm12: 52581ad6265SDimitry Andric return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 11), 52681ad6265SDimitry Andric /*Upper=*/(1 << 11) - 1); 52781ad6265SDimitry Andric case Match_InvalidSImm14lsl2: 52881ad6265SDimitry Andric return generateImmOutOfRangeError( 52981ad6265SDimitry Andric Operands, ErrorInfo, /*Lower=*/-(1 << 15), /*Upper=*/(1 << 15) - 4, 53081ad6265SDimitry Andric "immediate must be a multiple of 4 in the range"); 53181ad6265SDimitry Andric case Match_InvalidSImm16: 53281ad6265SDimitry Andric return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 15), 53381ad6265SDimitry Andric /*Upper=*/(1 << 15) - 1); 53481ad6265SDimitry Andric case Match_InvalidSImm16lsl2: 53581ad6265SDimitry Andric return generateImmOutOfRangeError( 53681ad6265SDimitry Andric Operands, ErrorInfo, /*Lower=*/-(1 << 17), /*Upper=*/(1 << 17) - 4, 53781ad6265SDimitry Andric "immediate must be a multiple of 4 in the range"); 53881ad6265SDimitry Andric case Match_InvalidSImm20: 53981ad6265SDimitry Andric return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/-(1 << 19), 54081ad6265SDimitry Andric /*Upper=*/(1 << 19) - 1); 54181ad6265SDimitry Andric case Match_InvalidSImm21lsl2: 54281ad6265SDimitry Andric return generateImmOutOfRangeError( 54381ad6265SDimitry Andric Operands, ErrorInfo, /*Lower=*/-(1 << 22), /*Upper=*/(1 << 22) - 4, 54481ad6265SDimitry Andric "immediate must be a multiple of 4 in the range"); 54581ad6265SDimitry Andric case Match_InvalidSImm26lsl2: 54681ad6265SDimitry Andric return generateImmOutOfRangeError( 54781ad6265SDimitry Andric Operands, ErrorInfo, /*Lower=*/-(1 << 27), /*Upper=*/(1 << 27) - 4, 54881ad6265SDimitry Andric "immediate must be a multiple of 4 in the range"); 54981ad6265SDimitry Andric } 55081ad6265SDimitry Andric llvm_unreachable("Unknown match type detected!"); 55181ad6265SDimitry Andric } 55281ad6265SDimitry Andric 55381ad6265SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLoongArchAsmParser() { 55481ad6265SDimitry Andric RegisterMCAsmParser<LoongArchAsmParser> X(getTheLoongArch32Target()); 55581ad6265SDimitry Andric RegisterMCAsmParser<LoongArchAsmParser> Y(getTheLoongArch64Target()); 55681ad6265SDimitry Andric } 557