|  | //===---- CSKYAsmParser.cpp - Parse CSKY 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/CSKYInstPrinter.h" | 
|  | #include "MCTargetDesc/CSKYMCAsmInfo.h" | 
|  | #include "MCTargetDesc/CSKYMCTargetDesc.h" | 
|  | #include "MCTargetDesc/CSKYTargetStreamer.h" | 
|  | #include "TargetInfo/CSKYTargetInfo.h" | 
|  | #include "llvm/ADT/STLExtras.h" | 
|  | #include "llvm/ADT/Statistic.h" | 
|  | #include "llvm/ADT/StringExtras.h" | 
|  | #include "llvm/ADT/StringSwitch.h" | 
|  | #include "llvm/BinaryFormat/ELF.h" | 
|  | #include "llvm/CodeGen/Register.h" | 
|  | #include "llvm/MC/MCContext.h" | 
|  | #include "llvm/MC/MCExpr.h" | 
|  | #include "llvm/MC/MCInst.h" | 
|  | #include "llvm/MC/MCInstrInfo.h" | 
|  | #include "llvm/MC/MCParser/AsmLexer.h" | 
|  | #include "llvm/MC/MCParser/MCParsedAsmOperand.h" | 
|  | #include "llvm/MC/MCParser/MCTargetAsmParser.h" | 
|  | #include "llvm/MC/MCRegisterInfo.h" | 
|  | #include "llvm/MC/MCSectionELF.h" | 
|  | #include "llvm/MC/MCStreamer.h" | 
|  | #include "llvm/MC/MCSubtargetInfo.h" | 
|  | #include "llvm/MC/TargetRegistry.h" | 
|  | #include "llvm/Support/CSKYAttributes.h" | 
|  | #include "llvm/Support/Casting.h" | 
|  | #include "llvm/Support/CommandLine.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  | #include "llvm/TargetParser/CSKYTargetParser.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "csky-asm-parser" | 
|  |  | 
|  | // Include the auto-generated portion of the compress emitter. | 
|  | #define GEN_COMPRESS_INSTR | 
|  | #include "CSKYGenCompressInstEmitter.inc" | 
|  |  | 
|  | STATISTIC(CSKYNumInstrsCompressed, | 
|  | "Number of C-SKY Compressed instructions emitted"); | 
|  |  | 
|  | static cl::opt<bool> | 
|  | EnableCompressedInst("enable-csky-asm-compressed-inst", cl::Hidden, | 
|  | cl::init(false), | 
|  | cl::desc("Enable C-SKY asm compressed instruction")); | 
|  |  | 
|  | namespace { | 
|  | struct CSKYOperand; | 
|  |  | 
|  | class CSKYAsmParser : public MCTargetAsmParser { | 
|  |  | 
|  | const MCRegisterInfo *MRI; | 
|  |  | 
|  | unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, | 
|  | unsigned Kind) override; | 
|  |  | 
|  | bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo, | 
|  | int64_t Lower, int64_t Upper, | 
|  | const Twine &Msg); | 
|  |  | 
|  | SMLoc getLoc() const { return getParser().getTok().getLoc(); } | 
|  |  | 
|  | bool matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, | 
|  | OperandVector &Operands, MCStreamer &Out, | 
|  | uint64_t &ErrorInfo, | 
|  | bool MatchingInlineAsm) override; | 
|  |  | 
|  | bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, SMLoc &EndLoc) override; | 
|  |  | 
|  | bool parseInstruction(ParseInstructionInfo &Info, StringRef Name, | 
|  | SMLoc NameLoc, OperandVector &Operands) override; | 
|  |  | 
|  | ParseStatus parseDirective(AsmToken DirectiveID) override; | 
|  |  | 
|  | // Helper to actually emit an instruction to the MCStreamer. Also, when | 
|  | // possible, compression of the instruction is performed. | 
|  | void emitToStreamer(MCStreamer &S, const MCInst &Inst); | 
|  |  | 
|  | ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc, | 
|  | SMLoc &EndLoc) override; | 
|  |  | 
|  | bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands, | 
|  | MCStreamer &Out); | 
|  | bool processLRW(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); | 
|  | bool processJSRI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); | 
|  | bool processJMPI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out); | 
|  |  | 
|  | CSKYTargetStreamer &getTargetStreamer() { | 
|  | assert(getParser().getStreamer().getTargetStreamer() && | 
|  | "do not have a target streamer"); | 
|  | MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); | 
|  | return static_cast<CSKYTargetStreamer &>(TS); | 
|  | } | 
|  |  | 
|  | // Auto-generated instruction matching functions | 
|  | #define GET_ASSEMBLER_HEADER | 
|  | #include "CSKYGenAsmMatcher.inc" | 
|  |  | 
|  | ParseStatus parseImmediate(OperandVector &Operands); | 
|  | ParseStatus parseRegister(OperandVector &Operands); | 
|  | ParseStatus parseBaseRegImm(OperandVector &Operands); | 
|  | ParseStatus parseCSKYSymbol(OperandVector &Operands); | 
|  | ParseStatus parseConstpoolSymbol(OperandVector &Operands); | 
|  | ParseStatus parseDataSymbol(OperandVector &Operands); | 
|  | ParseStatus parsePSRFlag(OperandVector &Operands); | 
|  | ParseStatus parseRegSeq(OperandVector &Operands); | 
|  | ParseStatus parseRegList(OperandVector &Operands); | 
|  |  | 
|  | bool parseOperand(OperandVector &Operands, StringRef Mnemonic); | 
|  |  | 
|  | bool parseDirectiveAttribute(); | 
|  |  | 
|  | public: | 
|  | enum CSKYMatchResultTy { | 
|  | Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, | 
|  | Match_RequiresSameSrcAndDst, | 
|  | Match_InvalidRegOutOfRange, | 
|  | #define GET_OPERAND_DIAGNOSTIC_TYPES | 
|  | #include "CSKYGenAsmMatcher.inc" | 
|  | #undef GET_OPERAND_DIAGNOSTIC_TYPES | 
|  | }; | 
|  |  | 
|  | CSKYAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, | 
|  | const MCInstrInfo &MII, const MCTargetOptions &Options) | 
|  | : MCTargetAsmParser(Options, STI, MII) { | 
|  |  | 
|  | MCAsmParserExtension::Initialize(Parser); | 
|  |  | 
|  | // Cache the MCRegisterInfo. | 
|  | MRI = getContext().getRegisterInfo(); | 
|  |  | 
|  | setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); | 
|  | getTargetStreamer().emitTargetAttributes(STI); | 
|  | } | 
|  | }; | 
|  |  | 
|  | /// Instances of this class represent a parsed machine instruction. | 
|  | struct CSKYOperand : public MCParsedAsmOperand { | 
|  |  | 
|  | enum KindTy { | 
|  | Token, | 
|  | Register, | 
|  | Immediate, | 
|  | RegisterSeq, | 
|  | CPOP, | 
|  | RegisterList | 
|  | } Kind; | 
|  |  | 
|  | struct RegOp { | 
|  | MCRegister RegNum; | 
|  | }; | 
|  |  | 
|  | struct ImmOp { | 
|  | const MCExpr *Val; | 
|  | }; | 
|  |  | 
|  | struct ConstpoolOp { | 
|  | const MCExpr *Val; | 
|  | }; | 
|  |  | 
|  | struct RegSeqOp { | 
|  | MCRegister RegNumFrom; | 
|  | MCRegister RegNumTo; | 
|  | }; | 
|  |  | 
|  | struct RegListOp { | 
|  | MCRegister List1From; | 
|  | MCRegister List1To; | 
|  | MCRegister List2From; | 
|  | MCRegister List2To; | 
|  | MCRegister List3From; | 
|  | MCRegister List3To; | 
|  | MCRegister List4From; | 
|  | MCRegister List4To; | 
|  | }; | 
|  |  | 
|  | SMLoc StartLoc, EndLoc; | 
|  | union { | 
|  | StringRef Tok; | 
|  | RegOp Reg; | 
|  | ImmOp Imm; | 
|  | ConstpoolOp CPool; | 
|  | RegSeqOp RegSeq; | 
|  | RegListOp RegList; | 
|  | }; | 
|  |  | 
|  | CSKYOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} | 
|  |  | 
|  | public: | 
|  | CSKYOperand(const CSKYOperand &o) : MCParsedAsmOperand() { | 
|  | Kind = o.Kind; | 
|  | StartLoc = o.StartLoc; | 
|  | EndLoc = o.EndLoc; | 
|  | switch (Kind) { | 
|  | case Register: | 
|  | Reg = o.Reg; | 
|  | break; | 
|  | case RegisterSeq: | 
|  | RegSeq = o.RegSeq; | 
|  | break; | 
|  | case CPOP: | 
|  | CPool = o.CPool; | 
|  | break; | 
|  | case Immediate: | 
|  | Imm = o.Imm; | 
|  | break; | 
|  | case Token: | 
|  | Tok = o.Tok; | 
|  | break; | 
|  | case RegisterList: | 
|  | RegList = o.RegList; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool isToken() const override { return Kind == Token; } | 
|  | bool isReg() const override { return Kind == Register; } | 
|  | bool isImm() const override { return Kind == Immediate; } | 
|  | bool isRegisterSeq() const { return Kind == RegisterSeq; } | 
|  | bool isRegisterList() const { return Kind == RegisterList; } | 
|  | bool isConstPoolOp() const { return Kind == CPOP; } | 
|  |  | 
|  | bool isMem() const override { return false; } | 
|  |  | 
|  | static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm) { | 
|  | if (auto CE = dyn_cast<MCConstantExpr>(Expr)) { | 
|  | Imm = CE->getValue(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | template <unsigned num, unsigned shift = 0> bool isUImm() const { | 
|  | if (!isImm()) | 
|  | return false; | 
|  |  | 
|  | int64_t Imm; | 
|  | bool IsConstantImm = evaluateConstantImm(getImm(), Imm); | 
|  | return IsConstantImm && isShiftedUInt<num, shift>(Imm); | 
|  | } | 
|  |  | 
|  | template <unsigned num> bool isOImm() const { | 
|  | if (!isImm()) | 
|  | return false; | 
|  |  | 
|  | int64_t Imm; | 
|  | bool IsConstantImm = evaluateConstantImm(getImm(), Imm); | 
|  | return IsConstantImm && isUInt<num>(Imm - 1); | 
|  | } | 
|  |  | 
|  | template <unsigned num, unsigned shift = 0> bool isSImm() const { | 
|  | if (!isImm()) | 
|  | return false; | 
|  |  | 
|  | int64_t Imm; | 
|  | bool IsConstantImm = evaluateConstantImm(getImm(), Imm); | 
|  | return IsConstantImm && isShiftedInt<num, shift>(Imm); | 
|  | } | 
|  |  | 
|  | bool isUImm1() const { return isUImm<1>(); } | 
|  | bool isUImm2() const { return isUImm<2>(); } | 
|  | bool isUImm3() const { return isUImm<3>(); } | 
|  | bool isUImm4() const { return isUImm<4>(); } | 
|  | bool isUImm5() const { return isUImm<5>(); } | 
|  | bool isUImm6() const { return isUImm<6>(); } | 
|  | bool isUImm7() const { return isUImm<7>(); } | 
|  | bool isUImm8() const { return isUImm<8>(); } | 
|  | bool isUImm12() const { return isUImm<12>(); } | 
|  | bool isUImm16() const { return isUImm<16>(); } | 
|  | bool isUImm20() const { return isUImm<20>(); } | 
|  | bool isUImm24() const { return isUImm<24>(); } | 
|  |  | 
|  | bool isOImm3() const { return isOImm<3>(); } | 
|  | bool isOImm4() const { return isOImm<4>(); } | 
|  | bool isOImm5() const { return isOImm<5>(); } | 
|  | bool isOImm6() const { return isOImm<6>(); } | 
|  | bool isOImm8() const { return isOImm<8>(); } | 
|  | bool isOImm12() const { return isOImm<12>(); } | 
|  | bool isOImm16() const { return isOImm<16>(); } | 
|  |  | 
|  | bool isSImm8() const { return isSImm<8>(); } | 
|  |  | 
|  | bool isUImm5Shift1() { return isUImm<5, 1>(); } | 
|  | bool isUImm5Shift2() { return isUImm<5, 2>(); } | 
|  | bool isUImm7Shift1() { return isUImm<7, 1>(); } | 
|  | bool isUImm7Shift2() { return isUImm<7, 2>(); } | 
|  | bool isUImm7Shift3() { return isUImm<7, 3>(); } | 
|  | bool isUImm8Shift2() { return isUImm<8, 2>(); } | 
|  | bool isUImm8Shift3() { return isUImm<8, 3>(); } | 
|  | bool isUImm8Shift8() { return isUImm<8, 8>(); } | 
|  | bool isUImm8Shift16() { return isUImm<8, 16>(); } | 
|  | bool isUImm8Shift24() { return isUImm<8, 24>(); } | 
|  | bool isUImm12Shift1() { return isUImm<12, 1>(); } | 
|  | bool isUImm12Shift2() { return isUImm<12, 2>(); } | 
|  | bool isUImm16Shift8() { return isUImm<16, 8>(); } | 
|  | bool isUImm16Shift16() { return isUImm<16, 16>(); } | 
|  | bool isUImm24Shift8() { return isUImm<24, 8>(); } | 
|  |  | 
|  | bool isSImm16Shift1() { return isSImm<16, 1>(); } | 
|  |  | 
|  | bool isCSKYSymbol() const { return isImm(); } | 
|  |  | 
|  | bool isConstpool() const { return isConstPoolOp(); } | 
|  | bool isDataSymbol() const { return isConstPoolOp(); } | 
|  |  | 
|  | bool isPSRFlag() const { | 
|  | int64_t Imm; | 
|  | // Must be of 'immediate' type and a constant. | 
|  | if (!isImm() || !evaluateConstantImm(getImm(), Imm)) | 
|  | return false; | 
|  |  | 
|  | return isUInt<5>(Imm); | 
|  | } | 
|  |  | 
|  | template <unsigned MIN, unsigned MAX> bool isRegSeqTemplate() const { | 
|  | if (!isRegisterSeq()) | 
|  | return false; | 
|  |  | 
|  | std::pair<unsigned, unsigned> regSeq = getRegSeq(); | 
|  |  | 
|  | return MIN <= regSeq.first && regSeq.first <= regSeq.second && | 
|  | regSeq.second <= MAX; | 
|  | } | 
|  |  | 
|  | bool isRegSeq() const { return isRegSeqTemplate<CSKY::R0, CSKY::R31>(); } | 
|  |  | 
|  | bool isRegSeqV1() const { | 
|  | return isRegSeqTemplate<CSKY::F0_32, CSKY::F15_32>(); | 
|  | } | 
|  |  | 
|  | bool isRegSeqV2() const { | 
|  | return isRegSeqTemplate<CSKY::F0_32, CSKY::F31_32>(); | 
|  | } | 
|  |  | 
|  | static bool isLegalRegList(unsigned from, unsigned to) { | 
|  | if (from == 0 && to == 0) | 
|  | return true; | 
|  |  | 
|  | if (from == to) { | 
|  | if (from != CSKY::R4 && from != CSKY::R15 && from != CSKY::R16 && | 
|  | from != CSKY::R28) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } else { | 
|  | if (from != CSKY::R4 && from != CSKY::R16) | 
|  | return false; | 
|  |  | 
|  | if (from == CSKY::R4 && to > CSKY::R4 && to < CSKY::R12) | 
|  | return true; | 
|  | else if (from == CSKY::R16 && to > CSKY::R16 && to < CSKY::R18) | 
|  | return true; | 
|  | else | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool isRegList() const { | 
|  | if (!isRegisterList()) | 
|  | return false; | 
|  |  | 
|  | auto regList = getRegList(); | 
|  |  | 
|  | if (!isLegalRegList(regList.List1From, regList.List1To)) | 
|  | return false; | 
|  | if (!isLegalRegList(regList.List2From, regList.List2To)) | 
|  | return false; | 
|  | if (!isLegalRegList(regList.List3From, regList.List3To)) | 
|  | return false; | 
|  | if (!isLegalRegList(regList.List4From, regList.List4To)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool isExtImm6() { | 
|  | if (!isImm()) | 
|  | return false; | 
|  |  | 
|  | int64_t Imm; | 
|  | bool IsConstantImm = evaluateConstantImm(getImm(), Imm); | 
|  | if (!IsConstantImm) | 
|  | return false; | 
|  |  | 
|  | int uimm4 = Imm & 0xf; | 
|  |  | 
|  | return isShiftedUInt<6, 0>(Imm) && uimm4 >= 0 && uimm4 <= 14; | 
|  | } | 
|  |  | 
|  | /// 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; } | 
|  |  | 
|  | MCRegister getReg() const override { | 
|  | assert(Kind == Register && "Invalid type access!"); | 
|  | return Reg.RegNum; | 
|  | } | 
|  |  | 
|  | std::pair<MCRegister, MCRegister> getRegSeq() const { | 
|  | assert(Kind == RegisterSeq && "Invalid type access!"); | 
|  | return {RegSeq.RegNumFrom, RegSeq.RegNumTo}; | 
|  | } | 
|  |  | 
|  | RegListOp getRegList() const { | 
|  | assert(Kind == RegisterList && "Invalid type access!"); | 
|  | return RegList; | 
|  | } | 
|  |  | 
|  | const MCExpr *getImm() const { | 
|  | assert(Kind == Immediate && "Invalid type access!"); | 
|  | return Imm.Val; | 
|  | } | 
|  |  | 
|  | const MCExpr *getConstpoolOp() const { | 
|  | assert(Kind == CPOP && "Invalid type access!"); | 
|  | return CPool.Val; | 
|  | } | 
|  |  | 
|  | StringRef getToken() const { | 
|  | assert(Kind == Token && "Invalid type access!"); | 
|  | return Tok; | 
|  | } | 
|  |  | 
|  | void print(raw_ostream &OS, const MCAsmInfo &MAI) const override { | 
|  | auto RegName = [](MCRegister Reg) { | 
|  | if (Reg) | 
|  | return CSKYInstPrinter::getRegisterName(Reg); | 
|  | else | 
|  | return "noreg"; | 
|  | }; | 
|  |  | 
|  | switch (Kind) { | 
|  | case CPOP: | 
|  | MAI.printExpr(OS, *getConstpoolOp()); | 
|  | break; | 
|  | case Immediate: | 
|  | MAI.printExpr(OS, *getImm()); | 
|  | break; | 
|  | case KindTy::Register: | 
|  | OS << "<register " << RegName(getReg()) << ">"; | 
|  | break; | 
|  | case RegisterSeq: | 
|  | OS << "<register-seq "; | 
|  | OS << RegName(getRegSeq().first) << "-" << RegName(getRegSeq().second) | 
|  | << ">"; | 
|  | break; | 
|  | case RegisterList: | 
|  | OS << "<register-list "; | 
|  | OS << RegName(getRegList().List1From) << "-" | 
|  | << RegName(getRegList().List1To) << ","; | 
|  | OS << RegName(getRegList().List2From) << "-" | 
|  | << RegName(getRegList().List2To) << ","; | 
|  | OS << RegName(getRegList().List3From) << "-" | 
|  | << RegName(getRegList().List3To) << ","; | 
|  | OS << RegName(getRegList().List4From) << "-" | 
|  | << RegName(getRegList().List4To); | 
|  | break; | 
|  | case Token: | 
|  | OS << "'" << getToken() << "'"; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | static std::unique_ptr<CSKYOperand> createToken(StringRef Str, SMLoc S) { | 
|  | auto Op = std::make_unique<CSKYOperand>(Token); | 
|  | Op->Tok = Str; | 
|  | Op->StartLoc = S; | 
|  | Op->EndLoc = S; | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | static std::unique_ptr<CSKYOperand> createReg(MCRegister RegNo, SMLoc S, | 
|  | SMLoc E) { | 
|  | auto Op = std::make_unique<CSKYOperand>(Register); | 
|  | Op->Reg.RegNum = RegNo; | 
|  | Op->StartLoc = S; | 
|  | Op->EndLoc = E; | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | static std::unique_ptr<CSKYOperand> | 
|  | createRegSeq(MCRegister RegNoFrom, MCRegister RegNoTo, SMLoc S) { | 
|  | auto Op = std::make_unique<CSKYOperand>(RegisterSeq); | 
|  | Op->RegSeq.RegNumFrom = RegNoFrom; | 
|  | Op->RegSeq.RegNumTo = RegNoTo; | 
|  | Op->StartLoc = S; | 
|  | Op->EndLoc = S; | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | static std::unique_ptr<CSKYOperand> | 
|  | createRegList(const SmallVector<MCRegister, 4> ®list, SMLoc S) { | 
|  | auto Op = std::make_unique<CSKYOperand>(RegisterList); | 
|  | Op->RegList.List1From = 0; | 
|  | Op->RegList.List1To = 0; | 
|  | Op->RegList.List2From = 0; | 
|  | Op->RegList.List2To = 0; | 
|  | Op->RegList.List3From = 0; | 
|  | Op->RegList.List3To = 0; | 
|  | Op->RegList.List4From = 0; | 
|  | Op->RegList.List4To = 0; | 
|  |  | 
|  | for (unsigned i = 0; i < reglist.size(); i += 2) { | 
|  | if (Op->RegList.List1From == 0) { | 
|  | Op->RegList.List1From = reglist[i]; | 
|  | Op->RegList.List1To = reglist[i + 1]; | 
|  | } else if (Op->RegList.List2From == 0) { | 
|  | Op->RegList.List2From = reglist[i]; | 
|  | Op->RegList.List2To = reglist[i + 1]; | 
|  | } else if (Op->RegList.List3From == 0) { | 
|  | Op->RegList.List3From = reglist[i]; | 
|  | Op->RegList.List3To = reglist[i + 1]; | 
|  | } else if (Op->RegList.List4From == 0) { | 
|  | Op->RegList.List4From = reglist[i]; | 
|  | Op->RegList.List4To = reglist[i + 1]; | 
|  | } else { | 
|  | assert(0); | 
|  | } | 
|  | } | 
|  |  | 
|  | Op->StartLoc = S; | 
|  | Op->EndLoc = S; | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | static std::unique_ptr<CSKYOperand> createImm(const MCExpr *Val, SMLoc S, | 
|  | SMLoc E) { | 
|  | auto Op = std::make_unique<CSKYOperand>(Immediate); | 
|  | Op->Imm.Val = Val; | 
|  | Op->StartLoc = S; | 
|  | Op->EndLoc = E; | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | static std::unique_ptr<CSKYOperand> createConstpoolOp(const MCExpr *Val, | 
|  | SMLoc S, SMLoc E) { | 
|  | auto Op = std::make_unique<CSKYOperand>(CPOP); | 
|  | Op->CPool.Val = Val; | 
|  | Op->StartLoc = S; | 
|  | Op->EndLoc = E; | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | void addExpr(MCInst &Inst, const MCExpr *Expr) const { | 
|  | assert(Expr && "Expr shouldn't be null!"); | 
|  | 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()); | 
|  | } | 
|  |  | 
|  | void addConstpoolOperands(MCInst &Inst, unsigned N) const { | 
|  | assert(N == 1 && "Invalid number of operands!"); | 
|  | Inst.addOperand(MCOperand::createExpr(getConstpoolOp())); | 
|  | } | 
|  |  | 
|  | void addRegSeqOperands(MCInst &Inst, unsigned N) const { | 
|  | assert(N == 2 && "Invalid number of operands!"); | 
|  | auto regSeq = getRegSeq(); | 
|  |  | 
|  | Inst.addOperand(MCOperand::createReg(regSeq.first)); | 
|  | Inst.addOperand(MCOperand::createReg(regSeq.second)); | 
|  | } | 
|  |  | 
|  | static unsigned getListValue(unsigned ListFrom, unsigned ListTo) { | 
|  | if (ListFrom == ListTo && ListFrom == CSKY::R15) | 
|  | return (1 << 4); | 
|  | else if (ListFrom == ListTo && ListFrom == CSKY::R28) | 
|  | return (1 << 8); | 
|  | else if (ListFrom == CSKY::R4) | 
|  | return ListTo - ListFrom + 1; | 
|  | else if (ListFrom == CSKY::R16) | 
|  | return ((ListTo - ListFrom + 1) << 5); | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void addRegListOperands(MCInst &Inst, unsigned N) const { | 
|  | assert(N == 1 && "Invalid number of operands!"); | 
|  | auto regList = getRegList(); | 
|  |  | 
|  | unsigned V = 0; | 
|  |  | 
|  | unsigned T = getListValue(regList.List1From, regList.List1To); | 
|  | if (T != 0) | 
|  | V = V | T; | 
|  |  | 
|  | T = getListValue(regList.List2From, regList.List2To); | 
|  | if (T != 0) | 
|  | V = V | T; | 
|  |  | 
|  | T = getListValue(regList.List3From, regList.List3To); | 
|  | if (T != 0) | 
|  | V = V | T; | 
|  |  | 
|  | T = getListValue(regList.List4From, regList.List4To); | 
|  | if (T != 0) | 
|  | V = V | T; | 
|  |  | 
|  | Inst.addOperand(MCOperand::createImm(V)); | 
|  | } | 
|  |  | 
|  | bool isValidForTie(const CSKYOperand &Other) const { | 
|  | if (Kind != Other.Kind) | 
|  | return false; | 
|  |  | 
|  | switch (Kind) { | 
|  | default: | 
|  | llvm_unreachable("Unexpected kind"); | 
|  | return false; | 
|  | case Register: | 
|  | return Reg.RegNum == Other.Reg.RegNum; | 
|  | } | 
|  | } | 
|  | }; | 
|  | } // end anonymous namespace. | 
|  |  | 
|  | #define GET_REGISTER_MATCHER | 
|  | #define GET_SUBTARGET_FEATURE_NAME | 
|  | #define GET_MATCHER_IMPLEMENTATION | 
|  | #define GET_MNEMONIC_SPELL_CHECKER | 
|  | #include "CSKYGenAsmMatcher.inc" | 
|  |  | 
|  | static MCRegister convertFPR32ToFPR64(MCRegister Reg) { | 
|  | assert(Reg >= CSKY::F0_32 && Reg <= CSKY::F31_32 && "Invalid register"); | 
|  | return Reg - CSKY::F0_32 + CSKY::F0_64; | 
|  | } | 
|  |  | 
|  | static std::string CSKYMnemonicSpellCheck(StringRef S, const FeatureBitset &FBS, | 
|  | unsigned VariantID = 0); | 
|  |  | 
|  | bool CSKYAsmParser::generateImmOutOfRangeError( | 
|  | OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper, | 
|  | const Twine &Msg = "immediate must be an integer in the range") { | 
|  | SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); | 
|  | return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]"); | 
|  | } | 
|  |  | 
|  | bool CSKYAsmParser::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!"); | 
|  | ListSeparator LS; | 
|  | std::string Msg = "instruction requires the following: "; | 
|  | for (unsigned i = 0, e = MissingFeatures.size(); i != e; ++i) { | 
|  | if (MissingFeatures[i]) { | 
|  | Msg += LS; | 
|  | Msg += getSubtargetFeatureName(i); | 
|  | } | 
|  | } | 
|  | return Error(IDLoc, Msg); | 
|  | } | 
|  | case Match_MnemonicFail: { | 
|  | FeatureBitset FBS = ComputeAvailableFeatures(getSTI().getFeatureBits()); | 
|  | std::string Suggestion = | 
|  | CSKYMnemonicSpellCheck(((CSKYOperand &)*Operands[0]).getToken(), FBS); | 
|  | return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion); | 
|  | } | 
|  | case Match_InvalidTiedOperand: | 
|  | case Match_InvalidOperand: { | 
|  | SMLoc ErrorLoc = IDLoc; | 
|  | if (ErrorInfo != ~0U) { | 
|  | if (ErrorInfo >= Operands.size()) | 
|  | return Error(ErrorLoc, "too few operands for instruction"); | 
|  |  | 
|  | ErrorLoc = ((CSKYOperand &)*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 != ~0U && ErrorInfo >= Operands.size()) | 
|  | return Error(ErrorLoc, "too few operands for instruction"); | 
|  | } | 
|  |  | 
|  | switch (Result) { | 
|  | default: | 
|  | break; | 
|  | case Match_InvalidSImm8: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 7), | 
|  | (1 << 7) - 1); | 
|  | case Match_InvalidOImm3: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 3)); | 
|  | case Match_InvalidOImm4: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 4)); | 
|  | case Match_InvalidOImm5: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 5)); | 
|  | case Match_InvalidOImm6: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 6)); | 
|  | case Match_InvalidOImm8: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 8)); | 
|  | case Match_InvalidOImm12: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 12)); | 
|  | case Match_InvalidOImm16: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 16)); | 
|  | case Match_InvalidUImm1: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 1) - 1); | 
|  | case Match_InvalidUImm2: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 2) - 1); | 
|  | case Match_InvalidUImm3: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 3) - 1); | 
|  | case Match_InvalidUImm4: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 4) - 1); | 
|  | case Match_InvalidUImm5: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1); | 
|  | case Match_InvalidUImm6: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 6) - 1); | 
|  | case Match_InvalidUImm7: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 7) - 1); | 
|  | case Match_InvalidUImm8: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 8) - 1); | 
|  | case Match_InvalidUImm12: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 12) - 1); | 
|  | case Match_InvalidUImm16: | 
|  | return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 16) - 1); | 
|  | case Match_InvalidUImm5Shift1: | 
|  | return generateImmOutOfRangeError( | 
|  | Operands, ErrorInfo, 0, (1 << 5) - 2, | 
|  | "immediate must be a multiple of 2 bytes in the range"); | 
|  | case Match_InvalidUImm12Shift1: | 
|  | return generateImmOutOfRangeError( | 
|  | Operands, ErrorInfo, 0, (1 << 12) - 2, | 
|  | "immediate must be a multiple of 2 bytes in the range"); | 
|  | case Match_InvalidUImm5Shift2: | 
|  | return generateImmOutOfRangeError( | 
|  | Operands, ErrorInfo, 0, (1 << 5) - 4, | 
|  | "immediate must be a multiple of 4 bytes in the range"); | 
|  | case Match_InvalidUImm7Shift1: | 
|  | return generateImmOutOfRangeError( | 
|  | Operands, ErrorInfo, 0, (1 << 7) - 2, | 
|  | "immediate must be a multiple of 2 bytes in the range"); | 
|  | case Match_InvalidUImm7Shift2: | 
|  | return generateImmOutOfRangeError( | 
|  | Operands, ErrorInfo, 0, (1 << 7) - 4, | 
|  | "immediate must be a multiple of 4 bytes in the range"); | 
|  | case Match_InvalidUImm8Shift2: | 
|  | return generateImmOutOfRangeError( | 
|  | Operands, ErrorInfo, 0, (1 << 8) - 4, | 
|  | "immediate must be a multiple of 4 bytes in the range"); | 
|  | case Match_InvalidUImm8Shift3: | 
|  | return generateImmOutOfRangeError( | 
|  | Operands, ErrorInfo, 0, (1 << 8) - 8, | 
|  | "immediate must be a multiple of 8 bytes in the range"); | 
|  | case Match_InvalidUImm8Shift8: | 
|  | return generateImmOutOfRangeError( | 
|  | Operands, ErrorInfo, 0, (1 << 8) - 256, | 
|  | "immediate must be a multiple of 256 bytes in the range"); | 
|  | case Match_InvalidUImm12Shift2: | 
|  | return generateImmOutOfRangeError( | 
|  | Operands, ErrorInfo, 0, (1 << 12) - 4, | 
|  | "immediate must be a multiple of 4 bytes in the range"); | 
|  | case Match_InvalidCSKYSymbol: { | 
|  | SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); | 
|  | return Error(ErrorLoc, "operand must be a symbol name"); | 
|  | } | 
|  | case Match_InvalidConstpool: { | 
|  | SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); | 
|  | return Error(ErrorLoc, "operand must be a constpool symbol name"); | 
|  | } | 
|  | case Match_InvalidPSRFlag: { | 
|  | SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); | 
|  | return Error(ErrorLoc, "psrset operand is not valid"); | 
|  | } | 
|  | case Match_InvalidRegSeq: { | 
|  | SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); | 
|  | return Error(ErrorLoc, "Register sequence is not valid"); | 
|  | } | 
|  | case Match_InvalidRegOutOfRange: { | 
|  | SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); | 
|  | return Error(ErrorLoc, "register is out of range"); | 
|  | } | 
|  | case Match_RequiresSameSrcAndDst: { | 
|  | SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); | 
|  | return Error(ErrorLoc, "src and dst operand must be same"); | 
|  | } | 
|  | case Match_InvalidRegList: { | 
|  | SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); | 
|  | return Error(ErrorLoc, "invalid register list"); | 
|  | } | 
|  | } | 
|  | LLVM_DEBUG(dbgs() << "Result = " << Result); | 
|  | llvm_unreachable("Unknown match type detected!"); | 
|  | } | 
|  |  | 
|  | bool CSKYAsmParser::processLRW(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out) { | 
|  | Inst.setLoc(IDLoc); | 
|  |  | 
|  | unsigned Opcode; | 
|  | MCOperand Op; | 
|  | if (Inst.getOpcode() == CSKY::PseudoLRW16) | 
|  | Opcode = CSKY::LRW16; | 
|  | else | 
|  | Opcode = CSKY::LRW32; | 
|  |  | 
|  | if (Inst.getOperand(1).isImm()) { | 
|  | if (isUInt<8>(Inst.getOperand(1).getImm()) && | 
|  | Inst.getOperand(0).getReg() <= CSKY::R7) { | 
|  | Opcode = CSKY::MOVI16; | 
|  | } else if (getSTI().hasFeature(CSKY::HasE2) && | 
|  | isUInt<16>(Inst.getOperand(1).getImm())) { | 
|  | Opcode = CSKY::MOVI32; | 
|  | } else { | 
|  | auto *Expr = getTargetStreamer().addConstantPoolEntry( | 
|  | MCConstantExpr::create(Inst.getOperand(1).getImm(), getContext()), | 
|  | Inst.getLoc()); | 
|  | Inst.erase(std::prev(Inst.end())); | 
|  | Inst.addOperand(MCOperand::createExpr(Expr)); | 
|  | } | 
|  | } else { | 
|  | const MCExpr *AdjustExpr = nullptr; | 
|  | if (const auto *CSKYExpr = | 
|  | dyn_cast<MCSpecifierExpr>(Inst.getOperand(1).getExpr())) { | 
|  | if (CSKYExpr->getSpecifier() == CSKY::S_TLSGD || | 
|  | CSKYExpr->getSpecifier() == CSKY::S_TLSIE || | 
|  | CSKYExpr->getSpecifier() == CSKY::S_TLSLDM) { | 
|  | MCSymbol *Dot = getContext().createNamedTempSymbol(); | 
|  | Out.emitLabel(Dot); | 
|  | AdjustExpr = MCSymbolRefExpr::create(Dot, getContext()); | 
|  | } | 
|  | } | 
|  | auto *Expr = getTargetStreamer().addConstantPoolEntry( | 
|  | Inst.getOperand(1).getExpr(), Inst.getLoc(), AdjustExpr); | 
|  | Inst.erase(std::prev(Inst.end())); | 
|  | Inst.addOperand(MCOperand::createExpr(Expr)); | 
|  | } | 
|  |  | 
|  | Inst.setOpcode(Opcode); | 
|  |  | 
|  | Out.emitInstruction(Inst, getSTI()); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool CSKYAsmParser::processJSRI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out) { | 
|  | Inst.setLoc(IDLoc); | 
|  |  | 
|  | if (Inst.getOperand(0).isImm()) { | 
|  | const MCExpr *Expr = getTargetStreamer().addConstantPoolEntry( | 
|  | MCConstantExpr::create(Inst.getOperand(0).getImm(), getContext()), | 
|  | Inst.getLoc()); | 
|  | Inst.setOpcode(CSKY::JSRI32); | 
|  | Inst.erase(std::prev(Inst.end())); | 
|  | Inst.addOperand(MCOperand::createExpr(Expr)); | 
|  | } else { | 
|  | const MCExpr *Expr = getTargetStreamer().addConstantPoolEntry( | 
|  | Inst.getOperand(0).getExpr(), Inst.getLoc()); | 
|  | Inst.setOpcode(CSKY::JBSR32); | 
|  | Inst.addOperand(MCOperand::createExpr(Expr)); | 
|  | } | 
|  |  | 
|  | Out.emitInstruction(Inst, getSTI()); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool CSKYAsmParser::processJMPI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out) { | 
|  | Inst.setLoc(IDLoc); | 
|  |  | 
|  | if (Inst.getOperand(0).isImm()) { | 
|  | const MCExpr *Expr = getTargetStreamer().addConstantPoolEntry( | 
|  | MCConstantExpr::create(Inst.getOperand(0).getImm(), getContext()), | 
|  | Inst.getLoc()); | 
|  | Inst.setOpcode(CSKY::JMPI32); | 
|  | Inst.erase(std::prev(Inst.end())); | 
|  | Inst.addOperand(MCOperand::createExpr(Expr)); | 
|  | } else { | 
|  | const MCExpr *Expr = getTargetStreamer().addConstantPoolEntry( | 
|  | Inst.getOperand(0).getExpr(), Inst.getLoc()); | 
|  | Inst.setOpcode(CSKY::JBR32); | 
|  | Inst.addOperand(MCOperand::createExpr(Expr)); | 
|  | } | 
|  |  | 
|  | Out.emitInstruction(Inst, getSTI()); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool CSKYAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, | 
|  | OperandVector &Operands, | 
|  | MCStreamer &Out) { | 
|  |  | 
|  | switch (Inst.getOpcode()) { | 
|  | default: | 
|  | break; | 
|  | case CSKY::LDQ32: | 
|  | case CSKY::STQ32: | 
|  | if (Inst.getOperand(1).getReg() != CSKY::R4 || | 
|  | Inst.getOperand(2).getReg() != CSKY::R7) { | 
|  | return Error(IDLoc, "Register sequence is not valid. 'r4-r7' expected"); | 
|  | } | 
|  | Inst.setOpcode(Inst.getOpcode() == CSKY::LDQ32 ? CSKY::LDM32 : CSKY::STM32); | 
|  | break; | 
|  | case CSKY::SEXT32: | 
|  | case CSKY::ZEXT32: | 
|  | if (Inst.getOperand(2).getImm() < Inst.getOperand(3).getImm()) | 
|  | return Error(IDLoc, "msb must be greater or equal to lsb"); | 
|  | break; | 
|  | case CSKY::INS32: | 
|  | if (Inst.getOperand(3).getImm() < Inst.getOperand(4).getImm()) | 
|  | return Error(IDLoc, "msb must be greater or equal to lsb"); | 
|  | break; | 
|  | case CSKY::IDLY32: | 
|  | if (Inst.getOperand(0).getImm() > 32 || Inst.getOperand(0).getImm() < 0) | 
|  | return Error(IDLoc, "n must be in range [0,32]"); | 
|  | break; | 
|  | case CSKY::ADDC32: | 
|  | case CSKY::SUBC32: | 
|  | case CSKY::ADDC16: | 
|  | case CSKY::SUBC16: | 
|  | Inst.erase(std::next(Inst.begin())); | 
|  | Inst.erase(std::prev(Inst.end())); | 
|  | Inst.insert(std::next(Inst.begin()), MCOperand::createReg(CSKY::C)); | 
|  | Inst.insert(Inst.end(), MCOperand::createReg(CSKY::C)); | 
|  | break; | 
|  | case CSKY::CMPNEI32: | 
|  | case CSKY::CMPNEI16: | 
|  | case CSKY::CMPNE32: | 
|  | case CSKY::CMPNE16: | 
|  | case CSKY::CMPHSI32: | 
|  | case CSKY::CMPHSI16: | 
|  | case CSKY::CMPHS32: | 
|  | case CSKY::CMPHS16: | 
|  | case CSKY::CMPLTI32: | 
|  | case CSKY::CMPLTI16: | 
|  | case CSKY::CMPLT32: | 
|  | case CSKY::CMPLT16: | 
|  | case CSKY::BTSTI32: | 
|  | Inst.erase(Inst.begin()); | 
|  | Inst.insert(Inst.begin(), MCOperand::createReg(CSKY::C)); | 
|  | break; | 
|  | case CSKY::MVCV32: | 
|  | Inst.erase(std::next(Inst.begin())); | 
|  | Inst.insert(Inst.end(), MCOperand::createReg(CSKY::C)); | 
|  | break; | 
|  | case CSKY::PseudoLRW16: | 
|  | case CSKY::PseudoLRW32: | 
|  | return processLRW(Inst, IDLoc, Out); | 
|  | case CSKY::PseudoJSRI32: | 
|  | return processJSRI(Inst, IDLoc, Out); | 
|  | case CSKY::PseudoJMPI32: | 
|  | return processJMPI(Inst, IDLoc, Out); | 
|  | case CSKY::JBSR32: | 
|  | case CSKY::JBR16: | 
|  | case CSKY::JBT16: | 
|  | case CSKY::JBF16: | 
|  | case CSKY::JBR32: | 
|  | case CSKY::JBT32: | 
|  | case CSKY::JBF32: | 
|  | unsigned Num = Inst.getNumOperands() - 1; | 
|  | assert(Inst.getOperand(Num).isExpr()); | 
|  |  | 
|  | const MCExpr *Expr = getTargetStreamer().addConstantPoolEntry( | 
|  | Inst.getOperand(Num).getExpr(), Inst.getLoc()); | 
|  |  | 
|  | Inst.addOperand(MCOperand::createExpr(Expr)); | 
|  | break; | 
|  | } | 
|  |  | 
|  | emitToStreamer(Out, Inst); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // 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(const MCSubtargetInfo &STI, MCRegister &Reg, | 
|  | StringRef Name) { | 
|  | Reg = MatchRegisterName(Name); | 
|  |  | 
|  | if (Reg == CSKY::NoRegister) | 
|  | Reg = MatchRegisterAltName(Name); | 
|  |  | 
|  | return Reg == CSKY::NoRegister; | 
|  | } | 
|  |  | 
|  | bool CSKYAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc, | 
|  | SMLoc &EndLoc) { | 
|  | const AsmToken &Tok = getParser().getTok(); | 
|  | StartLoc = Tok.getLoc(); | 
|  | EndLoc = Tok.getEndLoc(); | 
|  | StringRef Name = getLexer().getTok().getIdentifier(); | 
|  |  | 
|  | if (!matchRegisterNameHelper(getSTI(), Reg, Name)) { | 
|  | getParser().Lex(); // Eat identifier token. | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | ParseStatus CSKYAsmParser::parseRegister(OperandVector &Operands) { | 
|  | SMLoc S = getLoc(); | 
|  | SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); | 
|  |  | 
|  | switch (getLexer().getKind()) { | 
|  | default: | 
|  | return ParseStatus::NoMatch; | 
|  | case AsmToken::Identifier: { | 
|  | StringRef Name = getLexer().getTok().getIdentifier(); | 
|  | MCRegister Reg; | 
|  |  | 
|  | if (matchRegisterNameHelper(getSTI(), Reg, Name)) | 
|  | return ParseStatus::NoMatch; | 
|  |  | 
|  | getLexer().Lex(); | 
|  | Operands.push_back(CSKYOperand::createReg(Reg, S, E)); | 
|  |  | 
|  | return ParseStatus::Success; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | ParseStatus CSKYAsmParser::parseBaseRegImm(OperandVector &Operands) { | 
|  | assert(getLexer().is(AsmToken::LParen)); | 
|  |  | 
|  | Operands.push_back(CSKYOperand::createToken("(", getLoc())); | 
|  |  | 
|  | auto Tok = getParser().Lex(); // Eat '(' | 
|  |  | 
|  | if (!parseRegister(Operands).isSuccess()) { | 
|  | getLexer().UnLex(Tok); | 
|  | Operands.pop_back(); | 
|  | return ParseStatus::NoMatch; | 
|  | } | 
|  |  | 
|  | if (getLexer().is(AsmToken::RParen)) { | 
|  | Operands.push_back(CSKYOperand::createToken(")", getLoc())); | 
|  | getParser().Lex(); // Eat ')' | 
|  | return ParseStatus::Success; | 
|  | } | 
|  |  | 
|  | if (getLexer().isNot(AsmToken::Comma)) | 
|  | return Error(getLoc(), "expected ','"); | 
|  |  | 
|  | getParser().Lex(); // Eat ',' | 
|  |  | 
|  | if (parseRegister(Operands).isSuccess()) { | 
|  | if (getLexer().isNot(AsmToken::LessLess)) | 
|  | return Error(getLoc(), "expected '<<'"); | 
|  |  | 
|  | Operands.push_back(CSKYOperand::createToken("<<", getLoc())); | 
|  |  | 
|  | getParser().Lex(); // Eat '<<' | 
|  |  | 
|  | if (!parseImmediate(Operands).isSuccess()) | 
|  | return Error(getLoc(), "expected imm"); | 
|  |  | 
|  | } else if (!parseImmediate(Operands).isSuccess()) { | 
|  | return Error(getLoc(), "expected imm"); | 
|  | } | 
|  |  | 
|  | if (getLexer().isNot(AsmToken::RParen)) | 
|  | return Error(getLoc(), "expected ')'"); | 
|  |  | 
|  | Operands.push_back(CSKYOperand::createToken(")", getLoc())); | 
|  |  | 
|  | getParser().Lex(); // Eat ')' | 
|  |  | 
|  | return ParseStatus::Success; | 
|  | } | 
|  |  | 
|  | ParseStatus CSKYAsmParser::parseImmediate(OperandVector &Operands) { | 
|  | switch (getLexer().getKind()) { | 
|  | default: | 
|  | return ParseStatus::NoMatch; | 
|  | case AsmToken::LParen: | 
|  | case AsmToken::Minus: | 
|  | case AsmToken::Plus: | 
|  | case AsmToken::Integer: | 
|  | case AsmToken::String: | 
|  | break; | 
|  | } | 
|  |  | 
|  | const MCExpr *IdVal; | 
|  | SMLoc S = getLoc(); | 
|  | if (getParser().parseExpression(IdVal)) | 
|  | return Error(getLoc(), "unknown expression"); | 
|  |  | 
|  | SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); | 
|  | Operands.push_back(CSKYOperand::createImm(IdVal, S, E)); | 
|  | return ParseStatus::Success; | 
|  | } | 
|  |  | 
|  | /// Looks at a token type and creates the relevant operand from this | 
|  | /// information, adding to Operands. If operand was parsed, returns false, else | 
|  | /// true. | 
|  | bool CSKYAsmParser::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. | 
|  | ParseStatus Result = | 
|  | MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/true); | 
|  | if (Result.isSuccess()) | 
|  | return false; | 
|  | if (Result.isFailure()) | 
|  | return true; | 
|  |  | 
|  | // Attempt to parse token as register | 
|  | auto Res = parseRegister(Operands); | 
|  | if (Res.isSuccess()) | 
|  | return false; | 
|  | if (Res.isFailure()) | 
|  | return true; | 
|  |  | 
|  | // Attempt to parse token as (register, imm) | 
|  | if (getLexer().is(AsmToken::LParen)) { | 
|  | Res = parseBaseRegImm(Operands); | 
|  | if (Res.isSuccess()) | 
|  | return false; | 
|  | if (Res.isFailure()) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Res = parseImmediate(Operands); | 
|  | if (Res.isSuccess()) | 
|  | return false; | 
|  | if (Res.isFailure()) | 
|  | return true; | 
|  |  | 
|  | // Finally we have exhausted all options and must declare defeat. | 
|  | Error(getLoc(), "unknown operand"); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | ParseStatus CSKYAsmParser::parseCSKYSymbol(OperandVector &Operands) { | 
|  | SMLoc S = getLoc(); | 
|  | SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); | 
|  | const MCExpr *Res; | 
|  |  | 
|  | if (getLexer().getKind() != AsmToken::Identifier) | 
|  | return ParseStatus::NoMatch; | 
|  |  | 
|  | StringRef Identifier; | 
|  | AsmToken Tok = getLexer().getTok(); | 
|  |  | 
|  | if (getParser().parseIdentifier(Identifier)) | 
|  | return Error(getLoc(), "unknown identifier"); | 
|  |  | 
|  | CSKY::Specifier Kind = CSKY::S_None; | 
|  | if (Identifier.consume_back("@GOT")) | 
|  | Kind = CSKY::S_GOT; | 
|  | else if (Identifier.consume_back("@GOTOFF")) | 
|  | Kind = CSKY::S_GOTOFF; | 
|  | else if (Identifier.consume_back("@PLT")) | 
|  | Kind = CSKY::S_PLT; | 
|  | else if (Identifier.consume_back("@GOTPC")) | 
|  | Kind = CSKY::S_GOTPC; | 
|  | else if (Identifier.consume_back("@TLSGD32")) | 
|  | Kind = CSKY::S_TLSGD; | 
|  | else if (Identifier.consume_back("@GOTTPOFF")) | 
|  | Kind = CSKY::S_TLSIE; | 
|  | else if (Identifier.consume_back("@TPOFF")) | 
|  | Kind = CSKY::S_TLSLE; | 
|  | else if (Identifier.consume_back("@TLSLDM32")) | 
|  | Kind = CSKY::S_TLSLDM; | 
|  | else if (Identifier.consume_back("@TLSLDO32")) | 
|  | Kind = CSKY::S_TLSLDO; | 
|  |  | 
|  | MCSymbol *Sym = getContext().getInlineAsmLabel(Identifier); | 
|  |  | 
|  | if (!Sym) | 
|  | Sym = getContext().getOrCreateSymbol(Identifier); | 
|  |  | 
|  | if (Sym->isVariable()) { | 
|  | const MCExpr *V = Sym->getVariableValue(); | 
|  | if (!isa<MCSymbolRefExpr>(V)) { | 
|  | getLexer().UnLex(Tok); // Put back if it's not a bare symbol. | 
|  | return Error(getLoc(), "unknown symbol"); | 
|  | } | 
|  | Res = V; | 
|  | } else | 
|  | Res = MCSymbolRefExpr::create(Sym, getContext()); | 
|  |  | 
|  | MCBinaryExpr::Opcode Opcode; | 
|  | switch (getLexer().getKind()) { | 
|  | default: | 
|  | if (Kind != CSKY::S_None) | 
|  | Res = MCSpecifierExpr::create(Res, Kind, getContext()); | 
|  |  | 
|  | Operands.push_back(CSKYOperand::createImm(Res, S, E)); | 
|  | return ParseStatus::Success; | 
|  | case AsmToken::Plus: | 
|  | Opcode = MCBinaryExpr::Add; | 
|  | break; | 
|  | case AsmToken::Minus: | 
|  | Opcode = MCBinaryExpr::Sub; | 
|  | break; | 
|  | } | 
|  |  | 
|  | getLexer().Lex(); // eat + or - | 
|  |  | 
|  | const MCExpr *Expr; | 
|  | if (getParser().parseExpression(Expr)) | 
|  | return Error(getLoc(), "unknown expression"); | 
|  | Res = MCBinaryExpr::create(Opcode, Res, Expr, getContext()); | 
|  | Operands.push_back(CSKYOperand::createImm(Res, S, E)); | 
|  | return ParseStatus::Success; | 
|  | } | 
|  |  | 
|  | ParseStatus CSKYAsmParser::parseDataSymbol(OperandVector &Operands) { | 
|  | SMLoc S = getLoc(); | 
|  | SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); | 
|  | const MCExpr *Res; | 
|  |  | 
|  | if (!parseOptionalToken(AsmToken::LBrac)) | 
|  | return ParseStatus::NoMatch; | 
|  | if (getLexer().getKind() != AsmToken::Identifier) { | 
|  | const MCExpr *Expr; | 
|  | if (getParser().parseExpression(Expr)) | 
|  | return Error(getLoc(), "unknown expression"); | 
|  |  | 
|  | if (parseToken(AsmToken::RBrac, "expected ']'")) | 
|  | return ParseStatus::Failure; | 
|  |  | 
|  | Operands.push_back(CSKYOperand::createConstpoolOp(Expr, S, E)); | 
|  | return ParseStatus::Success; | 
|  | } | 
|  |  | 
|  | AsmToken Tok = getLexer().getTok(); | 
|  | StringRef Identifier; | 
|  |  | 
|  | if (getParser().parseIdentifier(Identifier)) | 
|  | return Error(getLoc(), "unknown identifier " + Identifier); | 
|  |  | 
|  | CSKY::Specifier Kind = CSKY::S_None; | 
|  | if (Identifier.consume_back("@GOT")) | 
|  | Kind = CSKY::S_GOT_IMM18_BY4; | 
|  | else if (Identifier.consume_back("@PLT")) | 
|  | Kind = CSKY::S_PLT_IMM18_BY4; | 
|  |  | 
|  | MCSymbol *Sym = getContext().getInlineAsmLabel(Identifier); | 
|  |  | 
|  | if (!Sym) | 
|  | Sym = getContext().getOrCreateSymbol(Identifier); | 
|  |  | 
|  | if (Sym->isVariable()) { | 
|  | const MCExpr *V = Sym->getVariableValue(); | 
|  | if (!isa<MCSymbolRefExpr>(V)) { | 
|  | getLexer().UnLex(Tok); // Put back if it's not a bare symbol. | 
|  | return Error(getLoc(), "unknown symbol"); | 
|  | } | 
|  | Res = V; | 
|  | } else { | 
|  | Res = MCSymbolRefExpr::create(Sym, getContext()); | 
|  | } | 
|  |  | 
|  | MCBinaryExpr::Opcode Opcode; | 
|  | switch (getLexer().getKind()) { | 
|  | default: | 
|  | return Error(getLoc(), "unknown symbol"); | 
|  | case AsmToken::RBrac: | 
|  |  | 
|  | getLexer().Lex(); // Eat ']'. | 
|  |  | 
|  | if (Kind != CSKY::S_None) | 
|  | Res = MCSpecifierExpr::create(Res, Kind, getContext()); | 
|  |  | 
|  | Operands.push_back(CSKYOperand::createConstpoolOp(Res, S, E)); | 
|  | return ParseStatus::Success; | 
|  | case AsmToken::Plus: | 
|  | Opcode = MCBinaryExpr::Add; | 
|  | break; | 
|  | case AsmToken::Minus: | 
|  | Opcode = MCBinaryExpr::Sub; | 
|  | break; | 
|  | } | 
|  |  | 
|  | getLexer().Lex(); // eat + or - | 
|  |  | 
|  | const MCExpr *Expr; | 
|  | if (getParser().parseExpression(Expr)) | 
|  | return Error(getLoc(), "unknown expression"); | 
|  | if (parseToken(AsmToken::RBrac, "expected ']'")) | 
|  | return ParseStatus::Failure; | 
|  |  | 
|  | Res = MCBinaryExpr::create(Opcode, Res, Expr, getContext()); | 
|  | Operands.push_back(CSKYOperand::createConstpoolOp(Res, S, E)); | 
|  | return ParseStatus::Success; | 
|  | } | 
|  |  | 
|  | ParseStatus CSKYAsmParser::parseConstpoolSymbol(OperandVector &Operands) { | 
|  | SMLoc S = getLoc(); | 
|  | SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); | 
|  | const MCExpr *Res; | 
|  |  | 
|  | if (!parseOptionalToken(AsmToken::LBrac)) | 
|  | return ParseStatus::NoMatch; | 
|  |  | 
|  | if (getLexer().getKind() != AsmToken::Identifier) { | 
|  | const MCExpr *Expr; | 
|  | if (getParser().parseExpression(Expr)) | 
|  | return Error(getLoc(), "unknown expression"); | 
|  | if (parseToken(AsmToken::RBrac)) | 
|  | return ParseStatus::Failure; | 
|  |  | 
|  | Operands.push_back(CSKYOperand::createConstpoolOp(Expr, S, E)); | 
|  | return ParseStatus::Success; | 
|  | } | 
|  |  | 
|  | AsmToken Tok = getLexer().getTok(); | 
|  | StringRef Identifier; | 
|  |  | 
|  | if (getParser().parseIdentifier(Identifier)) | 
|  | return Error(getLoc(), "unknown identifier"); | 
|  |  | 
|  | MCSymbol *Sym = getContext().getInlineAsmLabel(Identifier); | 
|  |  | 
|  | if (!Sym) | 
|  | Sym = getContext().getOrCreateSymbol(Identifier); | 
|  |  | 
|  | if (Sym->isVariable()) { | 
|  | const MCExpr *V = Sym->getVariableValue(); | 
|  | if (!isa<MCSymbolRefExpr>(V)) { | 
|  | getLexer().UnLex(Tok); // Put back if it's not a bare symbol. | 
|  | return Error(getLoc(), "unknown symbol"); | 
|  | } | 
|  | Res = V; | 
|  | } else { | 
|  | Res = MCSymbolRefExpr::create(Sym, getContext()); | 
|  | } | 
|  |  | 
|  | MCBinaryExpr::Opcode Opcode; | 
|  | switch (getLexer().getKind()) { | 
|  | default: | 
|  | return Error(getLoc(), "unknown symbol"); | 
|  | case AsmToken::RBrac: | 
|  |  | 
|  | getLexer().Lex(); // Eat ']'. | 
|  |  | 
|  | Operands.push_back(CSKYOperand::createConstpoolOp(Res, S, E)); | 
|  | return ParseStatus::Success; | 
|  | case AsmToken::Plus: | 
|  | Opcode = MCBinaryExpr::Add; | 
|  | break; | 
|  | case AsmToken::Minus: | 
|  | Opcode = MCBinaryExpr::Sub; | 
|  | break; | 
|  | } | 
|  |  | 
|  | getLexer().Lex(); // eat + or - | 
|  |  | 
|  | const MCExpr *Expr; | 
|  | if (getParser().parseExpression(Expr)) | 
|  | return Error(getLoc(), "unknown expression"); | 
|  | if (parseToken(AsmToken::RBrac, "expected ']'")) | 
|  | return ParseStatus::Failure; | 
|  |  | 
|  | Res = MCBinaryExpr::create(Opcode, Res, Expr, getContext()); | 
|  | Operands.push_back(CSKYOperand::createConstpoolOp(Res, S, E)); | 
|  | return ParseStatus::Success; | 
|  | } | 
|  |  | 
|  | ParseStatus CSKYAsmParser::parsePSRFlag(OperandVector &Operands) { | 
|  | SMLoc S = getLoc(); | 
|  | SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); | 
|  |  | 
|  | unsigned Flag = 0; | 
|  |  | 
|  | while (getLexer().isNot(AsmToken::EndOfStatement)) { | 
|  | StringRef Identifier; | 
|  | if (getParser().parseIdentifier(Identifier)) | 
|  | return Error(getLoc(), "unknown identifier " + Identifier); | 
|  |  | 
|  | if (Identifier == "sie") | 
|  | Flag = (1 << 4) | Flag; | 
|  | else if (Identifier == "ee") | 
|  | Flag = (1 << 3) | Flag; | 
|  | else if (Identifier == "ie") | 
|  | Flag = (1 << 2) | Flag; | 
|  | else if (Identifier == "fe") | 
|  | Flag = (1 << 1) | Flag; | 
|  | else if (Identifier == "af") | 
|  | Flag = (1 << 0) | Flag; | 
|  | else | 
|  | return Error(getLoc(), "expected " + Identifier); | 
|  |  | 
|  | if (getLexer().is(AsmToken::EndOfStatement)) | 
|  | break; | 
|  |  | 
|  | if (parseToken(AsmToken::Comma, "expected ','")) | 
|  | return ParseStatus::Failure; | 
|  | } | 
|  |  | 
|  | Operands.push_back( | 
|  | CSKYOperand::createImm(MCConstantExpr::create(Flag, getContext()), S, E)); | 
|  | return ParseStatus::Success; | 
|  | } | 
|  |  | 
|  | ParseStatus CSKYAsmParser::parseRegSeq(OperandVector &Operands) { | 
|  | SMLoc S = getLoc(); | 
|  |  | 
|  | if (!parseRegister(Operands).isSuccess()) | 
|  | return ParseStatus::NoMatch; | 
|  |  | 
|  | auto Ry = Operands.back()->getReg(); | 
|  | Operands.pop_back(); | 
|  |  | 
|  | if (parseToken(AsmToken::Minus, "expected '-'")) | 
|  | return ParseStatus::Failure; | 
|  | if (!parseRegister(Operands).isSuccess()) | 
|  | return Error(getLoc(), "invalid register"); | 
|  |  | 
|  | auto Rz = Operands.back()->getReg(); | 
|  | Operands.pop_back(); | 
|  |  | 
|  | Operands.push_back(CSKYOperand::createRegSeq(Ry, Rz, S)); | 
|  | return ParseStatus::Success; | 
|  | } | 
|  |  | 
|  | ParseStatus CSKYAsmParser::parseRegList(OperandVector &Operands) { | 
|  | SMLoc S = getLoc(); | 
|  | SmallVector<MCRegister, 4> reglist; | 
|  | while (true) { | 
|  |  | 
|  | if (!parseRegister(Operands).isSuccess()) | 
|  | return Error(getLoc(), "invalid register"); | 
|  |  | 
|  | auto Ry = Operands.back()->getReg(); | 
|  | Operands.pop_back(); | 
|  |  | 
|  | if (parseOptionalToken(AsmToken::Minus)) { | 
|  | if (!parseRegister(Operands).isSuccess()) | 
|  | return Error(getLoc(), "invalid register"); | 
|  |  | 
|  | auto Rz = Operands.back()->getReg(); | 
|  | Operands.pop_back(); | 
|  |  | 
|  | reglist.push_back(Ry); | 
|  | reglist.push_back(Rz); | 
|  |  | 
|  | if (getLexer().is(AsmToken::EndOfStatement)) | 
|  | break; | 
|  | (void)parseOptionalToken(AsmToken::Comma); | 
|  | } else if (parseOptionalToken(AsmToken::Comma)) { | 
|  | reglist.push_back(Ry); | 
|  | reglist.push_back(Ry); | 
|  | } else if (getLexer().is(AsmToken::EndOfStatement)) { | 
|  | reglist.push_back(Ry); | 
|  | reglist.push_back(Ry); | 
|  | break; | 
|  | } else { | 
|  | return Error(getLoc(), "invalid register list"); | 
|  | } | 
|  | } | 
|  |  | 
|  | Operands.push_back(CSKYOperand::createRegList(reglist, S)); | 
|  | return ParseStatus::Success; | 
|  | } | 
|  |  | 
|  | bool CSKYAsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name, | 
|  | SMLoc NameLoc, OperandVector &Operands) { | 
|  | // First operand is token for instruction. | 
|  | Operands.push_back(CSKYOperand::createToken(Name, NameLoc)); | 
|  |  | 
|  | // If there are no more operands, then finish. | 
|  | if (getLexer().is(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; | 
|  |  | 
|  | if (getLexer().isNot(AsmToken::EndOfStatement)) { | 
|  | SMLoc Loc = getLexer().getLoc(); | 
|  | getParser().eatToEndOfStatement(); | 
|  | return Error(Loc, "unexpected token"); | 
|  | } | 
|  |  | 
|  | getParser().Lex(); // Consume the EndOfStatement. | 
|  | return false; | 
|  | } | 
|  |  | 
|  | ParseStatus CSKYAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc, | 
|  | SMLoc &EndLoc) { | 
|  | const AsmToken &Tok = getParser().getTok(); | 
|  | StartLoc = Tok.getLoc(); | 
|  | EndLoc = Tok.getEndLoc(); | 
|  |  | 
|  | StringRef Name = getLexer().getTok().getIdentifier(); | 
|  |  | 
|  | if (matchRegisterNameHelper(getSTI(), Reg, Name)) | 
|  | return ParseStatus::NoMatch; | 
|  |  | 
|  | getParser().Lex(); // Eat identifier token. | 
|  | return ParseStatus::Success; | 
|  | } | 
|  |  | 
|  | ParseStatus CSKYAsmParser::parseDirective(AsmToken DirectiveID) { | 
|  | StringRef IDVal = DirectiveID.getString(); | 
|  |  | 
|  | if (IDVal == ".csky_attribute") | 
|  | return parseDirectiveAttribute(); | 
|  |  | 
|  | return ParseStatus::NoMatch; | 
|  | } | 
|  |  | 
|  | /// parseDirectiveAttribute | 
|  | ///  ::= .attribute expression ',' ( expression | "string" ) | 
|  | bool CSKYAsmParser::parseDirectiveAttribute() { | 
|  | MCAsmParser &Parser = getParser(); | 
|  | int64_t Tag; | 
|  | SMLoc TagLoc; | 
|  | TagLoc = Parser.getTok().getLoc(); | 
|  | if (Parser.getTok().is(AsmToken::Identifier)) { | 
|  | StringRef Name = Parser.getTok().getIdentifier(); | 
|  | std::optional<unsigned> Ret = | 
|  | ELFAttrs::attrTypeFromString(Name, CSKYAttrs::getCSKYAttributeTags()); | 
|  | if (!Ret) | 
|  | return Error(TagLoc, "attribute name not recognised: " + Name); | 
|  | Tag = *Ret; | 
|  | Parser.Lex(); | 
|  | } else { | 
|  | const MCExpr *AttrExpr; | 
|  |  | 
|  | TagLoc = Parser.getTok().getLoc(); | 
|  | if (Parser.parseExpression(AttrExpr)) | 
|  | return true; | 
|  |  | 
|  | const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(AttrExpr); | 
|  | if (!CE) | 
|  | return Error(TagLoc, "expected numeric constant"); | 
|  |  | 
|  | Tag = CE->getValue(); | 
|  | } | 
|  |  | 
|  | if (Parser.parseComma()) | 
|  | return true; | 
|  |  | 
|  | StringRef StringValue; | 
|  | int64_t IntegerValue = 0; | 
|  | bool IsIntegerValue = ((Tag != CSKYAttrs::CSKY_ARCH_NAME) && | 
|  | (Tag != CSKYAttrs::CSKY_CPU_NAME) && | 
|  | (Tag != CSKYAttrs::CSKY_FPU_NUMBER_MODULE)); | 
|  |  | 
|  | SMLoc ValueExprLoc = Parser.getTok().getLoc(); | 
|  | if (IsIntegerValue) { | 
|  | const MCExpr *ValueExpr; | 
|  | if (Parser.parseExpression(ValueExpr)) | 
|  | return true; | 
|  |  | 
|  | const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ValueExpr); | 
|  | if (!CE) | 
|  | return Error(ValueExprLoc, "expected numeric constant"); | 
|  | IntegerValue = CE->getValue(); | 
|  | } else { | 
|  | if (Parser.getTok().isNot(AsmToken::String)) | 
|  | return Error(Parser.getTok().getLoc(), "expected string constant"); | 
|  |  | 
|  | StringValue = Parser.getTok().getStringContents(); | 
|  | Parser.Lex(); | 
|  | } | 
|  |  | 
|  | if (Parser.parseEOL()) | 
|  | return true; | 
|  |  | 
|  | if (IsIntegerValue) | 
|  | getTargetStreamer().emitAttribute(Tag, IntegerValue); | 
|  | else if (Tag != CSKYAttrs::CSKY_ARCH_NAME && Tag != CSKYAttrs::CSKY_CPU_NAME) | 
|  | getTargetStreamer().emitTextAttribute(Tag, StringValue); | 
|  | else { | 
|  | CSKY::ArchKind ID = (Tag == CSKYAttrs::CSKY_ARCH_NAME) | 
|  | ? CSKY::parseArch(StringValue) | 
|  | : CSKY::parseCPUArch(StringValue); | 
|  | if (ID == CSKY::ArchKind::INVALID) | 
|  | return Error(ValueExprLoc, (Tag == CSKYAttrs::CSKY_ARCH_NAME) | 
|  | ? "unknown arch name" | 
|  | : "unknown cpu name"); | 
|  |  | 
|  | getTargetStreamer().emitTextAttribute(Tag, StringValue); | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | unsigned CSKYAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, | 
|  | unsigned Kind) { | 
|  | CSKYOperand &Op = static_cast<CSKYOperand &>(AsmOp); | 
|  |  | 
|  | if (!Op.isReg()) | 
|  | return Match_InvalidOperand; | 
|  |  | 
|  | MCRegister Reg = Op.getReg(); | 
|  |  | 
|  | if (CSKYMCRegisterClasses[CSKY::FPR32RegClassID].contains(Reg)) { | 
|  | // As the parser couldn't differentiate an FPR64 from an FPR32, coerce the | 
|  | // register from FPR32 to FPR64 if necessary. | 
|  | if (Kind == MCK_FPR64 || Kind == MCK_sFPR64) { | 
|  | Op.Reg.RegNum = convertFPR32ToFPR64(Reg); | 
|  | if (Kind == MCK_sFPR64 && | 
|  | (Op.Reg.RegNum < CSKY::F0_64 || Op.Reg.RegNum > CSKY::F15_64)) | 
|  | return Match_InvalidRegOutOfRange; | 
|  | if (Kind == MCK_FPR64 && | 
|  | (Op.Reg.RegNum < CSKY::F0_64 || Op.Reg.RegNum > CSKY::F31_64)) | 
|  | return Match_InvalidRegOutOfRange; | 
|  | return Match_Success; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (CSKYMCRegisterClasses[CSKY::GPRRegClassID].contains(Reg)) { | 
|  | if (Kind == MCK_GPRPair) { | 
|  | Op.Reg.RegNum = MRI->getEncodingValue(Reg) + CSKY::R0_R1; | 
|  | return Match_Success; | 
|  | } | 
|  | } | 
|  |  | 
|  | return Match_InvalidOperand; | 
|  | } | 
|  |  | 
|  | void CSKYAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) { | 
|  | MCInst CInst; | 
|  | bool Res = false; | 
|  | if (EnableCompressedInst) | 
|  | Res = compressInst(CInst, Inst, getSTI()); | 
|  | if (Res) | 
|  | ++CSKYNumInstrsCompressed; | 
|  | S.emitInstruction((Res ? CInst : Inst), getSTI()); | 
|  | } | 
|  |  | 
|  | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmParser() { | 
|  | RegisterMCAsmParser<CSKYAsmParser> X(getTheCSKYTarget()); | 
|  | } |