| //===---- 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/CSKYMCExpr.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/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/MCAsmLexer.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/CSKYTargetParser.h" | |
| #include "llvm/Support/Casting.h" | |
| #include "llvm/Support/CommandLine.h" | |
| #include "llvm/Support/Debug.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, 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 &RegNo, SMLoc &StartLoc, | |
| SMLoc &EndLoc) override; | |
| bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, | |
| SMLoc NameLoc, OperandVector &Operands) override; | |
| bool 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); | |
| OperandMatchResultTy tryParseRegister(MCRegister &RegNo, 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" | |
| OperandMatchResultTy parseImmediate(OperandVector &Operands); | |
| OperandMatchResultTy parseRegister(OperandVector &Operands); | |
| OperandMatchResultTy parseBaseRegImm(OperandVector &Operands); | |
| OperandMatchResultTy parseCSKYSymbol(OperandVector &Operands); | |
| OperandMatchResultTy parseConstpoolSymbol(OperandVector &Operands); | |
| OperandMatchResultTy parseDataSymbol(OperandVector &Operands); | |
| OperandMatchResultTy parsePSRFlag(OperandVector &Operands); | |
| OperandMatchResultTy parseRegSeq(OperandVector &Operands); | |
| OperandMatchResultTy 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 { | |
| unsigned RegNum; | |
| }; | |
| struct ImmOp { | |
| const MCExpr *Val; | |
| }; | |
| struct ConstpoolOp { | |
| const MCExpr *Val; | |
| }; | |
| struct RegSeqOp { | |
| unsigned RegNumFrom; | |
| unsigned RegNumTo; | |
| }; | |
| struct RegListOp { | |
| unsigned List1From = 0; | |
| unsigned List1To = 0; | |
| unsigned List2From = 0; | |
| unsigned List2To = 0; | |
| unsigned List3From = 0; | |
| unsigned List3To = 0; | |
| unsigned List4From = 0; | |
| unsigned List4To = 0; | |
| }; | |
| 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; } | |
| unsigned getReg() const override { | |
| assert(Kind == Register && "Invalid type access!"); | |
| return Reg.RegNum; | |
| } | |
| std::pair<unsigned, unsigned> getRegSeq() const { | |
| assert(Kind == RegisterSeq && "Invalid type access!"); | |
| return std::pair<unsigned, unsigned>(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 override { | |
| auto RegName = [](MCRegister Reg) { | |
| if (Reg) | |
| return CSKYInstPrinter::getRegisterName(Reg); | |
| else | |
| return "noreg"; | |
| }; | |
| switch (Kind) { | |
| case CPOP: | |
| OS << *getConstpoolOp(); | |
| break; | |
| case Immediate: | |
| 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(unsigned 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(unsigned RegNoFrom, | |
| unsigned 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(SmallVector<unsigned, 4> reglist, 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, | |
| 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().getFeatureBits()[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 CSKYMCExpr *CSKYExpr = | |
| dyn_cast<CSKYMCExpr>(Inst.getOperand(1).getExpr())) { | |
| if (CSKYExpr->getKind() == CSKYMCExpr::VK_CSKY_TLSGD || | |
| CSKYExpr->getKind() == CSKYMCExpr::VK_CSKY_TLSIE || | |
| CSKYExpr->getKind() == CSKYMCExpr::VK_CSKY_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 &RegNo, StringRef Name) { | |
| RegNo = MatchRegisterName(Name); | |
| if (RegNo == CSKY::NoRegister) | |
| RegNo = MatchRegisterAltName(Name); | |
| return RegNo == CSKY::NoRegister; | |
| } | |
| bool CSKYAsmParser::parseRegister(MCRegister &RegNo, SMLoc &StartLoc, | |
| SMLoc &EndLoc) { | |
| const AsmToken &Tok = getParser().getTok(); | |
| StartLoc = Tok.getLoc(); | |
| EndLoc = Tok.getEndLoc(); | |
| StringRef Name = getLexer().getTok().getIdentifier(); | |
| if (!matchRegisterNameHelper(getSTI(), (MCRegister &)RegNo, Name)) { | |
| getParser().Lex(); // Eat identifier token. | |
| return false; | |
| } | |
| return MatchOperand_NoMatch; | |
| } | |
| OperandMatchResultTy CSKYAsmParser::parseRegister(OperandVector &Operands) { | |
| SMLoc S = getLoc(); | |
| SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); | |
| switch (getLexer().getKind()) { | |
| default: | |
| return MatchOperand_NoMatch; | |
| case AsmToken::Identifier: { | |
| StringRef Name = getLexer().getTok().getIdentifier(); | |
| MCRegister RegNo; | |
| if (matchRegisterNameHelper(getSTI(), (MCRegister &)RegNo, Name)) | |
| return MatchOperand_NoMatch; | |
| getLexer().Lex(); | |
| Operands.push_back(CSKYOperand::createReg(RegNo, S, E)); | |
| return MatchOperand_Success; | |
| } | |
| } | |
| } | |
| OperandMatchResultTy CSKYAsmParser::parseBaseRegImm(OperandVector &Operands) { | |
| assert(getLexer().is(AsmToken::LParen)); | |
| Operands.push_back(CSKYOperand::createToken("(", getLoc())); | |
| auto Tok = getParser().Lex(); // Eat '(' | |
| if (parseRegister(Operands) != MatchOperand_Success) { | |
| getLexer().UnLex(Tok); | |
| Operands.pop_back(); | |
| return MatchOperand_NoMatch; | |
| } | |
| if (getLexer().is(AsmToken::RParen)) { | |
| Operands.push_back(CSKYOperand::createToken(")", getLoc())); | |
| getParser().Lex(); // Eat ')' | |
| return MatchOperand_Success; | |
| } | |
| if (getLexer().isNot(AsmToken::Comma)) { | |
| Error(getLoc(), "expected ','"); | |
| return MatchOperand_ParseFail; | |
| } | |
| getParser().Lex(); // Eat ',' | |
| if (parseRegister(Operands) == MatchOperand_Success) { | |
| if (getLexer().isNot(AsmToken::LessLess)) { | |
| Error(getLoc(), "expected '<<'"); | |
| return MatchOperand_ParseFail; | |
| } | |
| Operands.push_back(CSKYOperand::createToken("<<", getLoc())); | |
| getParser().Lex(); // Eat '<<' | |
| if (parseImmediate(Operands) != MatchOperand_Success) { | |
| Error(getLoc(), "expected imm"); | |
| return MatchOperand_ParseFail; | |
| } | |
| } else if (parseImmediate(Operands) != MatchOperand_Success) { | |
| Error(getLoc(), "expected imm"); | |
| return MatchOperand_ParseFail; | |
| } | |
| if (getLexer().isNot(AsmToken::RParen)) { | |
| Error(getLoc(), "expected ')'"); | |
| return MatchOperand_ParseFail; | |
| } | |
| Operands.push_back(CSKYOperand::createToken(")", getLoc())); | |
| getParser().Lex(); // Eat ')' | |
| return MatchOperand_Success; | |
| } | |
| OperandMatchResultTy CSKYAsmParser::parseImmediate(OperandVector &Operands) { | |
| switch (getLexer().getKind()) { | |
| default: | |
| return MatchOperand_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)) { | |
| Error(getLoc(), "unknown expression"); | |
| return MatchOperand_ParseFail; | |
| } | |
| SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); | |
| Operands.push_back(CSKYOperand::createImm(IdVal, S, E)); | |
| return MatchOperand_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. | |
| OperandMatchResultTy Result = | |
| MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/true); | |
| if (Result == MatchOperand_Success) | |
| return false; | |
| if (Result == MatchOperand_ParseFail) | |
| return true; | |
| // Attempt to parse token as register | |
| auto Res = parseRegister(Operands); | |
| if (Res == MatchOperand_Success) | |
| return false; | |
| else if (Res == MatchOperand_ParseFail) | |
| return true; | |
| // Attempt to parse token as (register, imm) | |
| if (getLexer().is(AsmToken::LParen)) { | |
| Res = parseBaseRegImm(Operands); | |
| if (Res == MatchOperand_Success) | |
| return false; | |
| else if (Res == MatchOperand_ParseFail) | |
| return true; | |
| } | |
| Res = parseImmediate(Operands); | |
| if (Res == MatchOperand_Success) | |
| return false; | |
| else if (Res == MatchOperand_ParseFail) | |
| return true; | |
| // Finally we have exhausted all options and must declare defeat. | |
| Error(getLoc(), "unknown operand"); | |
| return true; | |
| } | |
| OperandMatchResultTy CSKYAsmParser::parseCSKYSymbol(OperandVector &Operands) { | |
| SMLoc S = getLoc(); | |
| SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); | |
| const MCExpr *Res; | |
| if (getLexer().getKind() != AsmToken::Identifier) | |
| return MatchOperand_NoMatch; | |
| StringRef Identifier; | |
| AsmToken Tok = getLexer().getTok(); | |
| if (getParser().parseIdentifier(Identifier)) { | |
| Error(getLoc(), "unknown identifier"); | |
| return MatchOperand_ParseFail; | |
| } | |
| CSKYMCExpr::VariantKind Kind = CSKYMCExpr::VK_CSKY_None; | |
| if (Identifier.consume_back("@GOT")) | |
| Kind = CSKYMCExpr::VK_CSKY_GOT; | |
| else if (Identifier.consume_back("@GOTOFF")) | |
| Kind = CSKYMCExpr::VK_CSKY_GOTOFF; | |
| else if (Identifier.consume_back("@PLT")) | |
| Kind = CSKYMCExpr::VK_CSKY_PLT; | |
| else if (Identifier.consume_back("@GOTPC")) | |
| Kind = CSKYMCExpr::VK_CSKY_GOTPC; | |
| else if (Identifier.consume_back("@TLSGD32")) | |
| Kind = CSKYMCExpr::VK_CSKY_TLSGD; | |
| else if (Identifier.consume_back("@GOTTPOFF")) | |
| Kind = CSKYMCExpr::VK_CSKY_TLSIE; | |
| else if (Identifier.consume_back("@TPOFF")) | |
| Kind = CSKYMCExpr::VK_CSKY_TLSLE; | |
| else if (Identifier.consume_back("@TLSLDM32")) | |
| Kind = CSKYMCExpr::VK_CSKY_TLSLDM; | |
| else if (Identifier.consume_back("@TLSLDO32")) | |
| Kind = CSKYMCExpr::VK_CSKY_TLSLDO; | |
| MCSymbol *Sym = getContext().getInlineAsmLabel(Identifier); | |
| if (!Sym) | |
| Sym = getContext().getOrCreateSymbol(Identifier); | |
| if (Sym->isVariable()) { | |
| const MCExpr *V = Sym->getVariableValue(/*SetUsed=*/false); | |
| if (!isa<MCSymbolRefExpr>(V)) { | |
| getLexer().UnLex(Tok); // Put back if it's not a bare symbol. | |
| Error(getLoc(), "unknown symbol"); | |
| return MatchOperand_ParseFail; | |
| } | |
| Res = V; | |
| } else | |
| Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); | |
| MCBinaryExpr::Opcode Opcode; | |
| switch (getLexer().getKind()) { | |
| default: | |
| if (Kind != CSKYMCExpr::VK_CSKY_None) | |
| Res = CSKYMCExpr::create(Res, Kind, getContext()); | |
| Operands.push_back(CSKYOperand::createImm(Res, S, E)); | |
| return MatchOperand_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)) { | |
| Error(getLoc(), "unknown expression"); | |
| return MatchOperand_ParseFail; | |
| } | |
| Res = MCBinaryExpr::create(Opcode, Res, Expr, getContext()); | |
| Operands.push_back(CSKYOperand::createImm(Res, S, E)); | |
| return MatchOperand_Success; | |
| } | |
| OperandMatchResultTy CSKYAsmParser::parseDataSymbol(OperandVector &Operands) { | |
| SMLoc S = getLoc(); | |
| SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); | |
| const MCExpr *Res; | |
| if (getLexer().getKind() != AsmToken::LBrac) | |
| return MatchOperand_NoMatch; | |
| getLexer().Lex(); // Eat '['. | |
| if (getLexer().getKind() != AsmToken::Identifier) { | |
| const MCExpr *Expr; | |
| if (getParser().parseExpression(Expr)) { | |
| Error(getLoc(), "unknown expression"); | |
| return MatchOperand_ParseFail; | |
| } | |
| if (getLexer().getKind() != AsmToken::RBrac) { | |
| Error(getLoc(), "expected ]"); | |
| return MatchOperand_ParseFail; | |
| } | |
| getLexer().Lex(); // Eat ']'. | |
| Operands.push_back(CSKYOperand::createConstpoolOp(Expr, S, E)); | |
| return MatchOperand_Success; | |
| } | |
| AsmToken Tok = getLexer().getTok(); | |
| StringRef Identifier; | |
| if (getParser().parseIdentifier(Identifier)) { | |
| Error(getLoc(), "unknown identifier " + Identifier); | |
| return MatchOperand_ParseFail; | |
| } | |
| CSKYMCExpr::VariantKind Kind = CSKYMCExpr::VK_CSKY_None; | |
| if (Identifier.consume_back("@GOT")) | |
| Kind = CSKYMCExpr::VK_CSKY_GOT_IMM18_BY4; | |
| else if (Identifier.consume_back("@PLT")) | |
| Kind = CSKYMCExpr::VK_CSKY_PLT_IMM18_BY4; | |
| MCSymbol *Sym = getContext().getInlineAsmLabel(Identifier); | |
| if (!Sym) | |
| Sym = getContext().getOrCreateSymbol(Identifier); | |
| if (Sym->isVariable()) { | |
| const MCExpr *V = Sym->getVariableValue(/*SetUsed=*/false); | |
| if (!isa<MCSymbolRefExpr>(V)) { | |
| getLexer().UnLex(Tok); // Put back if it's not a bare symbol. | |
| Error(getLoc(), "unknown symbol"); | |
| return MatchOperand_ParseFail; | |
| } | |
| Res = V; | |
| } else { | |
| Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); | |
| } | |
| MCBinaryExpr::Opcode Opcode; | |
| switch (getLexer().getKind()) { | |
| default: | |
| Error(getLoc(), "unknown symbol"); | |
| return MatchOperand_ParseFail; | |
| case AsmToken::RBrac: | |
| getLexer().Lex(); // Eat ']'. | |
| if (Kind != CSKYMCExpr::VK_CSKY_None) | |
| Res = CSKYMCExpr::create(Res, Kind, getContext()); | |
| Operands.push_back(CSKYOperand::createConstpoolOp(Res, S, E)); | |
| return MatchOperand_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)) { | |
| Error(getLoc(), "unknown expression"); | |
| return MatchOperand_ParseFail; | |
| } | |
| if (getLexer().getKind() != AsmToken::RBrac) { | |
| Error(getLoc(), "expected ']'"); | |
| return MatchOperand_ParseFail; | |
| } | |
| getLexer().Lex(); // Eat ']'. | |
| Res = MCBinaryExpr::create(Opcode, Res, Expr, getContext()); | |
| Operands.push_back(CSKYOperand::createConstpoolOp(Res, S, E)); | |
| return MatchOperand_Success; | |
| } | |
| OperandMatchResultTy | |
| CSKYAsmParser::parseConstpoolSymbol(OperandVector &Operands) { | |
| SMLoc S = getLoc(); | |
| SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); | |
| const MCExpr *Res; | |
| if (getLexer().getKind() != AsmToken::LBrac) | |
| return MatchOperand_NoMatch; | |
| getLexer().Lex(); // Eat '['. | |
| if (getLexer().getKind() != AsmToken::Identifier) { | |
| const MCExpr *Expr; | |
| if (getParser().parseExpression(Expr)) { | |
| Error(getLoc(), "unknown expression"); | |
| return MatchOperand_ParseFail; | |
| } | |
| if (getLexer().getKind() != AsmToken::RBrac) { | |
| Error(getLoc(), "expected ']'"); | |
| return MatchOperand_ParseFail; | |
| } | |
| getLexer().Lex(); // Eat ']'. | |
| Operands.push_back(CSKYOperand::createConstpoolOp(Expr, S, E)); | |
| return MatchOperand_Success; | |
| } | |
| AsmToken Tok = getLexer().getTok(); | |
| StringRef Identifier; | |
| if (getParser().parseIdentifier(Identifier)) { | |
| Error(getLoc(), "unknown identifier"); | |
| return MatchOperand_ParseFail; | |
| } | |
| MCSymbol *Sym = getContext().getInlineAsmLabel(Identifier); | |
| if (!Sym) | |
| Sym = getContext().getOrCreateSymbol(Identifier); | |
| if (Sym->isVariable()) { | |
| const MCExpr *V = Sym->getVariableValue(/*SetUsed=*/false); | |
| if (!isa<MCSymbolRefExpr>(V)) { | |
| getLexer().UnLex(Tok); // Put back if it's not a bare symbol. | |
| Error(getLoc(), "unknown symbol"); | |
| return MatchOperand_ParseFail; | |
| } | |
| Res = V; | |
| } else { | |
| Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); | |
| } | |
| MCBinaryExpr::Opcode Opcode; | |
| switch (getLexer().getKind()) { | |
| default: | |
| Error(getLoc(), "unknown symbol"); | |
| return MatchOperand_ParseFail; | |
| case AsmToken::RBrac: | |
| getLexer().Lex(); // Eat ']'. | |
| Operands.push_back(CSKYOperand::createConstpoolOp(Res, S, E)); | |
| return MatchOperand_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)) { | |
| Error(getLoc(), "unknown expression"); | |
| return MatchOperand_ParseFail; | |
| } | |
| if (getLexer().getKind() != AsmToken::RBrac) { | |
| Error(getLoc(), "expected ']'"); | |
| return MatchOperand_ParseFail; | |
| } | |
| getLexer().Lex(); // Eat ']'. | |
| Res = MCBinaryExpr::create(Opcode, Res, Expr, getContext()); | |
| Operands.push_back(CSKYOperand::createConstpoolOp(Res, S, E)); | |
| return MatchOperand_Success; | |
| } | |
| OperandMatchResultTy 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)) { | |
| Error(getLoc(), "unknown identifier " + Identifier); | |
| return MatchOperand_ParseFail; | |
| } | |
| 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 { | |
| Error(getLoc(), "expected " + Identifier); | |
| return MatchOperand_ParseFail; | |
| } | |
| if (getLexer().is(AsmToken::EndOfStatement)) | |
| break; | |
| if (getLexer().is(AsmToken::Comma)) { | |
| getLexer().Lex(); // eat ',' | |
| } else { | |
| Error(getLoc(), "expected ,"); | |
| return MatchOperand_ParseFail; | |
| } | |
| } | |
| Operands.push_back( | |
| CSKYOperand::createImm(MCConstantExpr::create(Flag, getContext()), S, E)); | |
| return MatchOperand_Success; | |
| } | |
| OperandMatchResultTy CSKYAsmParser::parseRegSeq(OperandVector &Operands) { | |
| SMLoc S = getLoc(); | |
| if (parseRegister(Operands) != MatchOperand_Success) | |
| return MatchOperand_NoMatch; | |
| auto Ry = Operands.back()->getReg(); | |
| Operands.pop_back(); | |
| if (getLexer().isNot(AsmToken::Minus)) { | |
| Error(getLoc(), "expected '-'"); | |
| return MatchOperand_ParseFail; | |
| } | |
| getLexer().Lex(); // eat '-' | |
| if (parseRegister(Operands) != MatchOperand_Success) { | |
| Error(getLoc(), "invalid register"); | |
| return MatchOperand_ParseFail; | |
| } | |
| auto Rz = Operands.back()->getReg(); | |
| Operands.pop_back(); | |
| Operands.push_back(CSKYOperand::createRegSeq(Ry, Rz, S)); | |
| return MatchOperand_Success; | |
| } | |
| OperandMatchResultTy CSKYAsmParser::parseRegList(OperandVector &Operands) { | |
| SMLoc S = getLoc(); | |
| SmallVector<unsigned, 4> reglist; | |
| while (true) { | |
| if (parseRegister(Operands) != MatchOperand_Success) { | |
| Error(getLoc(), "invalid register"); | |
| return MatchOperand_ParseFail; | |
| } | |
| auto Ry = Operands.back()->getReg(); | |
| Operands.pop_back(); | |
| if (getLexer().is(AsmToken::Minus)) { | |
| getLexer().Lex(); // eat '-' | |
| if (parseRegister(Operands) != MatchOperand_Success) { | |
| Error(getLoc(), "invalid register"); | |
| return MatchOperand_ParseFail; | |
| } | |
| auto Rz = Operands.back()->getReg(); | |
| Operands.pop_back(); | |
| reglist.push_back(Ry); | |
| reglist.push_back(Rz); | |
| if (getLexer().is(AsmToken::Comma)) | |
| getLexer().Lex(); // eat ',' | |
| else if (getLexer().is(AsmToken::EndOfStatement)) | |
| break; | |
| } else if (getLexer().is(AsmToken::Comma)) { | |
| reglist.push_back(Ry); | |
| reglist.push_back(Ry); | |
| getLexer().Lex(); // eat ',' | |
| } else if (getLexer().is(AsmToken::EndOfStatement)) { | |
| reglist.push_back(Ry); | |
| reglist.push_back(Ry); | |
| break; | |
| } else { | |
| Error(getLoc(), "invalid register list"); | |
| return MatchOperand_ParseFail; | |
| } | |
| } | |
| Operands.push_back(CSKYOperand::createRegList(reglist, S)); | |
| return MatchOperand_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 (getLexer().is(AsmToken::Comma)) { | |
| // Consume comma token. | |
| getLexer().Lex(); | |
| // Parse next operand. | |
| 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; | |
| } | |
| OperandMatchResultTy CSKYAsmParser::tryParseRegister(MCRegister &RegNo, | |
| SMLoc &StartLoc, | |
| SMLoc &EndLoc) { | |
| const AsmToken &Tok = getParser().getTok(); | |
| StartLoc = Tok.getLoc(); | |
| EndLoc = Tok.getEndLoc(); | |
| StringRef Name = getLexer().getTok().getIdentifier(); | |
| if (matchRegisterNameHelper(getSTI(), (MCRegister &)RegNo, Name)) | |
| return MatchOperand_NoMatch; | |
| getParser().Lex(); // Eat identifier token. | |
| return MatchOperand_Success; | |
| } | |
| bool CSKYAsmParser::ParseDirective(AsmToken DirectiveID) { | |
| // This returns false if this function recognizes the directive | |
| // regardless of whether it is successfully handles or reports an | |
| // error. Otherwise it returns true to give the generic parser a | |
| // chance at recognizing it. | |
| StringRef IDVal = DirectiveID.getString(); | |
| if (IDVal == ".csky_attribute") | |
| return parseDirectiveAttribute(); | |
| return true; | |
| } | |
| /// 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) { | |
| Error(TagLoc, "attribute name not recognised: " + Name); | |
| return false; | |
| } | |
| 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 (check(!CE, TagLoc, "expected numeric constant")) | |
| return true; | |
| Tag = CE->getValue(); | |
| } | |
| if (Parser.parseToken(AsmToken::Comma, "comma expected")) | |
| 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()); | |
| } |