Index: lib/Target/NDS32/AsmParser/CMakeLists.txt =================================================================== --- /dev/null +++ lib/Target/NDS32/AsmParser/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMNDS32AsmParser + NDS32AsmParser.cpp + ) Index: lib/Target/NDS32/AsmParser/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/Target/NDS32/AsmParser/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./lib/Target/NDS32/AsmParser/LLVMBuild.txt --------------*- Conf -*---===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = NDS32AsmParser +parent = NDS32 +required_libraries = MC MCParser NDS32Desc NDS32Info Support +add_to_library_groups = NDS32 Index: lib/Target/NDS32/AsmParser/NDS32AsmParser.cpp =================================================================== --- /dev/null +++ lib/Target/NDS32/AsmParser/NDS32AsmParser.cpp @@ -0,0 +1,1474 @@ +//===-- NDS32AsmParser.cpp - Parse NDS32 assembly to MCInst instructions --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/NDS32MCExpr.h" +#include "MCTargetDesc/NDS32MCTargetDesc.h" +#include "NDS32RegisterInfo.h" +#include "NDS32TargetStreamer.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstBuilder.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm; + +#define DEBUG_TYPE "nds32-asm-parser" + +namespace llvm { +class MCInstrInfo; +} + +namespace { +class NDS32AssemblerOptions { +public: + NDS32AssemblerOptions(const FeatureBitset &Features_) : + Features(Features_) {} + + NDS32AssemblerOptions(const NDS32AssemblerOptions *Opts) { + Features = Opts->getFeatures(); + } + + const FeatureBitset &getFeatures() const { return Features; } + void setFeatures(const FeatureBitset &Features_) { Features = Features_; } + + static const FeatureBitset AllArchRelatedMask; + +private: + FeatureBitset Features; +}; +} + +const FeatureBitset NDS32AssemblerOptions::AllArchRelatedMask = { + NDS32::FeatureNo16Bit +}; + +namespace { +class NDS32AsmParser : public MCTargetAsmParser { + NDS32TargetStreamer &getTargetStreamer() { + MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); + return static_cast(TS); + } + + SmallVector, 2> AssemblerOptions; + MCSymbol *CurrentFn; + bool IsLittleEndian; + bool IsPicEnabled; + + // Print a warning along with its fix-it message at the given range. + void printWarningWithFixIt(const Twine &Msg, const Twine &FixMsg, + SMRange Range, bool ShowColors = true); + +#define GET_ASSEMBLER_HEADER +#include "NDS32GenAsmMatcher.inc" + + unsigned checkTargetMatchPredicate(MCInst &Inst) override; + + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) override; + + /// Parse a register as used in CFI directives + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; + + bool parseParenSuffix(StringRef Name, OperandVector &Operands); + + bool parseBracketSuffix(StringRef Name, OperandVector &Operands); + + bool processInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, + const MCSubtargetInfo *STI); + + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; + + bool ParseDirective(AsmToken DirectiveID) override; + bool parseMemory(OperandVector &); + bool parseRegisterList(OperandVector &); + bool parseRelocOperand(OperandVector &); + + OperandMatchResultTy + matchAnyRegisterNameWithoutDollar(OperandVector &Operands, + StringRef Identifier, SMLoc S); + OperandMatchResultTy matchAnyRegisterWithoutDollar(OperandVector &Operands, + SMLoc S); + OperandMatchResultTy parseAnyRegister(OperandVector &Operands); + OperandMatchResultTy parseImm(OperandVector &Operands); + OperandMatchResultTy parseJumpTarget(OperandVector &Operands); + + bool parseOperand(OperandVector &, StringRef Mnemonic); + + bool isMultipleLoadStore(StringRef Mnemonic); + + bool searchSymbolAlias(OperandVector &Operands); + + int matchCPURegisterName(StringRef Symbol); + + int tryParseRegister(); + +public: + enum NDS32MatchResultTy { + Match_RequiresDifferentSrcAndDst = FIRST_TARGET_MATCH_RESULT_TY, + Match_RequiresDifferentOperands, + Match_RequiresNoZeroRegister, +#define GET_OPERAND_DIAGNOSTIC_TYPES +#include "NDS32GenAsmMatcher.inc" +#undef GET_OPERAND_DIAGNOSTIC_TYPES + }; + + NDS32AsmParser(const MCSubtargetInfo &sti, MCAsmParser &parser, + const MCInstrInfo &MII, const MCTargetOptions &Options) + : MCTargetAsmParser(Options, sti) { + MCAsmParserExtension::Initialize(parser); + + parser.addAliasForDirective(".asciiz", ".asciz"); + + // Initialize the set of available features. + setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits())); + + // Remember the initial assembler options. The user can not modify these. + AssemblerOptions.push_back( + llvm::make_unique(getSTI().getFeatureBits())); + + // Create an assembler options environment for the user to modify. + AssemblerOptions.push_back( + llvm::make_unique(getSTI().getFeatureBits())); + + CurrentFn = nullptr; + + IsLittleEndian = true; + } + + bool has16Bit() const { + return !getSTI().getFeatureBits()[NDS32::FeatureNo16Bit]; + } + + bool isLittle() const { return IsLittleEndian; } +}; +} + +namespace { + +/// NDS32Operand - Instances of this class represent a parsed NDS32 machine +/// instruction. +class NDS32Operand : public MCParsedAsmOperand { +public: + /// Broad categories of register classes + /// The exact class is finalized by the render method. + enum RegKind { + RegKind_GPR = 1, + RegKind_Numeric = RegKind_GPR + }; + +private: + enum KindTy { + k_Immediate, /// An immediate (possibly involving symbol references) + k_Memory, /// Memory Address + k_RegisterIndex, /// A register index in one or more RegKind. + k_Token, /// A simple token + k_RegList, /// A physical register list + } Kind; + +public: + NDS32Operand(KindTy K, NDS32AsmParser &Parser) + : MCParsedAsmOperand(), Kind(K), AsmParser(Parser) {} + +private: + /// For diagnostics, and checking the assembler temporary + NDS32AsmParser &AsmParser; + + struct Token { + const char *Data; + unsigned Length; + }; + + struct RegIdxOp { + unsigned Index; /// Index into the register class + RegKind Kind; /// Bitfield of the kinds it could possibly be + const MCRegisterInfo *RegInfo; + }; + + struct ImmOp { + const MCExpr *Val; + }; + + struct MemoryOp { + unsigned BaseRegNum; + // Offset is in OffsetReg or OffsetImm. If both are zero, no offset + // was specified. + const MCConstantExpr *OffsetImm; // Offset immediate value + unsigned OffsetRegNum; // Offset register num, when OffsetImm == NULL + unsigned ShiftImm; // shift for OffsetReg. + bool isMinusOffset; // Offset prefix is Minus + }; + + struct RegListOp { + SmallVector *List; + }; + + union { + struct Token Tok; + struct RegIdxOp RegIdx; + struct ImmOp Imm; + struct MemoryOp Memory; + struct RegListOp RegList; + }; + + SMLoc StartLoc, EndLoc; + + /// Internal constructor for register kinds + static std::unique_ptr CreateReg(unsigned Index, + RegKind RegKind, + const MCRegisterInfo *RegInfo, + SMLoc S, SMLoc E, + NDS32AsmParser &Parser) { + auto Op = make_unique(k_RegisterIndex, Parser); + Op->RegIdx.Index = Index; + Op->RegIdx.RegInfo = RegInfo; + Op->RegIdx.Kind = RegKind; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + +public: + /// Coerce the register to GPR and return the real register for the current + /// target. + unsigned getGPRReg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_GPR) && "Invalid access!"); + unsigned ClassID = NDS32::GPRRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + +public: + unsigned getGPR32Reg() const { + assert(isRegIdx() && (RegIdx.Kind & RegKind_GPR) && "Invalid access!"); + unsigned ClassID = NDS32::GPRRegClassID; + return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); + } + + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + // Add as immediate when possible. Null MCExpr = 0. + if (!Expr) + Inst.addOperand(MCOperand::createImm(0)); + else if (const MCConstantExpr *CE = dyn_cast(Expr)) + Inst.addOperand(MCOperand::createImm(CE->getValue())); + else + Inst.addOperand(MCOperand::createExpr(Expr)); + } + + void addRegOperands(MCInst &Inst, unsigned N) const { + Inst.addOperand(MCOperand::createReg(getReg())); + } + + /// Render the operand to an MCInst as a GPR + /// Asserts if the wrong number of operands are requested, or the operand + /// is not a k_RegisterIndex compatible with RegKind_GPR + void addGPRAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getGPRReg())); + } + + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCExpr *Expr = getImm(); + addExpr(Inst, Expr); + } + + void addMemRegOffsetOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + addRegOperands (Inst, N); + } + + void addAddrRegShiftOperands(MCInst &Inst, unsigned N) const { + assert(N == 3 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::createReg(Memory.OffsetRegNum)); + Inst.addOperand(MCOperand::createImm(Memory.ShiftImm)); + } + + void addAddrImm15sWordOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::createImm(Val)); + } + + void addAddrImm15sHalfOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::createImm(Val)); + } + + void addAddrImm15sByteOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::createImm(Val)); + } + + void addAddrImm3uWordOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::createImm(Val)); + } + + void addAddrImm3uHalfOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::createImm(Val)); + } + + void addAddrImm3uByteOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::createImm(Val)); + } + + void addAddrFPImm7uWordOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::createImm(Val)); + } + + void addAddrSPImm7uWordOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + int32_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::createReg(NDS32::SP)); + Inst.addOperand(MCOperand::createImm(Val)); + } + + void addRegListOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + for (auto RegNo : getRegList()) + Inst.addOperand(MCOperand::createReg(RegNo)); + } + + bool isReg() const override { + return isGPRAsmReg(); + } + bool isRegIdx() const { return Kind == k_RegisterIndex; } + bool isImm() const override { return Kind == k_Immediate; } + bool isConstantImm() const { + return isImm() && isa(getImm()); + } + bool isToken() const override { + // Note: It's not possible to pretend that other operand kinds are tokens. + // The matcher emitter checks tokens first. + return Kind == k_Token; + } + bool isMem() const override { return Kind == k_Memory; } + bool isRegList() const { return Kind == k_RegList; } + bool isImm5s() const { + return isConstantImm() && isIntN(5, getConstantImm()); + } + bool isImm11s() const { + return isConstantImm() && isIntN(11, getConstantImm()); + } + bool isImm15s() const { + return isConstantImm() && isIntN(15, getConstantImm()); + } + bool isImm20s() const { + return isConstantImm() && isIntN(20, getConstantImm()); + } + bool isImm3u() const { + return isConstantImm() && isUIntN(3, getConstantImm()); + } + bool isImm5u() const { + return isConstantImm() && isUIntN(5, getConstantImm()); + } + bool isImm15u() const { + return isConstantImm() ? isUIntN(15, getConstantImm()) : isImm(); + } + bool isImm20u() const { + return isConstantImm() ? isUIntN(20, getConstantImm()) : isImm(); + } + bool isMemNoOffset() const { + if (!isMem()) return false; + // No offset of any kind. + return Memory.OffsetRegNum == 0 && Memory.OffsetImm == nullptr; + } + // [Reg + Reg << sv], sv could be 0, 1, 2, 3 + bool isAddrRegShift() const { + if (!isMem()) return false; + if (Memory.OffsetImm != nullptr) return false; + if (Memory.ShiftImm > 3) return false; + return true; + } + // [Reg + imm15s << 2] + bool isAddrImm15sWord() const { + if (!isMem()) return false; + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + if (Memory.isMinusOffset) Val = -Val; + return isIntN(15 + 2, Val) && (Val % 4 == 0); + } + // [Reg + imm15s << 1] + bool isAddrImm15sHalf() const { + if (!isMem()) return false; + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + if (Memory.isMinusOffset) Val = -Val; + return isIntN(15 + 1, Val) && (Val % 2 == 0); + } + // [Reg + imm15s] + bool isAddrImm15sByte() const { + if (!isMem()) return false; + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + if (Memory.isMinusOffset) Val = -Val; + return isIntN(15, Val); + } + // [Reg + imm3u << 2] + bool isAddrImm3uWord() const { + if (!isMem()) return false; + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + if (Memory.isMinusOffset) Val = -Val; + return isUIntN(3 + 2, Val) && (Val % 4 == 0); + } + // [Reg + imm3u << 1] + bool isAddrImm3uHalf() const { + if (!isMem()) return false; + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + if (Memory.isMinusOffset) Val = -Val; + return isUIntN(3 + 1, Val) && (Val % 2 == 0); + } + // [Reg + imm3u] + bool isAddrImm3uByte() const { + if (!isMem()) return false; + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + if (Memory.isMinusOffset) Val = -Val; + return isUIntN(3, Val); + } + // [FP + imm7u << 2] + bool isAddrFPImm7uWord() const { + if (!isMem()) return false; + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return isUIntN(7 + 2, Val) && (Val % 4 == 0); + } + // [SP + imm7u << 2] + bool isAddrSPImm7uWord() const { + if (!isMem()) return false; + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + return isUIntN(7 + 2, Val) && (Val % 4 == 0); + } + // imm15s << 2 + bool isOffsetImm15sWord() const { + return isConstantImm() && isIntN(15 + 2, getConstantImm()) && + (getConstantImm() % 4 == 0); + } + // imm15s << 1 + bool isOffsetImm15sHalf() const { + return isConstantImm() && isIntN(15 + 1, getConstantImm()) && + (getConstantImm() % 2 == 0); + } + // imm15s + bool isOffsetImm15sByte() const { + return isConstantImm() && isIntN(15, getConstantImm()); + } + bool isMemRegOffset() const { + return isReg(); + } + void addMemNoOffsetOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); + } + + void addOffsetImm15sWordOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createImm(getConstantImm())); + } + + void addOffsetImm15sHalfOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createImm(getConstantImm())); + } + + void addOffsetImm15sByteOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createImm(getConstantImm())); + } + + StringRef getToken() const { + assert(Kind == k_Token && "Invalid access!"); + return StringRef(Tok.Data, Tok.Length); + } + + unsigned getReg() const override { + if (Kind == k_RegisterIndex && + RegIdx.Kind & RegKind_GPR) + return getGPRReg(); + + llvm_unreachable("Invalid access!"); + return 0; + } + + const MCExpr *getImm() const { + assert((Kind == k_Immediate) && "Invalid access!"); + return Imm.Val; + } + + int64_t getConstantImm() const { + const MCExpr *Val = getImm(); + return static_cast(Val)->getValue(); + } + + const SmallVectorImpl &getRegList() const { + assert((Kind == k_RegList) && "Invalid access!"); + return *(RegList.List); + } + + static std::unique_ptr CreateToken(StringRef Str, SMLoc S, + NDS32AsmParser &Parser) { + auto Op = make_unique(k_Token, Parser); + Op->Tok.Data = Str.data(); + Op->Tok.Length = Str.size(); + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + /// Create a numeric register (e.g. $1). The exact register remains + /// unresolved until an instruction successfully matches + static std::unique_ptr + createNumericReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, + SMLoc E, NDS32AsmParser &Parser) { + DEBUG(dbgs() << "createNumericReg(" << Index << ", ...)\n"); + return CreateReg(Index, RegKind_Numeric, RegInfo, S, E, Parser); + } + + /// Create a register that is definitely a GPR. + /// This is typically only used for named registers such as $gp. + static std::unique_ptr + createGPRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, + NDS32AsmParser &Parser) { + return CreateReg(Index, RegKind_GPR, RegInfo, S, E, Parser); + } + + + static std::unique_ptr + CreateImm(const MCExpr *Val, SMLoc S, SMLoc E, NDS32AsmParser &Parser) { + auto Op = make_unique(k_Immediate, Parser); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static std::unique_ptr + CreateMem(unsigned BaseRegNum, const MCConstantExpr *OffsetImm, + unsigned OffsetRegNum, unsigned ShiftImm, bool isMinusOffset, + SMLoc S, SMLoc E, NDS32AsmParser &Parser) { + auto Op = make_unique(k_Memory, Parser); + Op->Memory.BaseRegNum = BaseRegNum; + Op->Memory.OffsetImm = OffsetImm; + Op->Memory.OffsetRegNum = OffsetRegNum; + Op->Memory.ShiftImm = ShiftImm; + Op->Memory.isMinusOffset = isMinusOffset; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static std::unique_ptr + CreateRegList(SmallVectorImpl &Regs, SMLoc StartLoc, SMLoc EndLoc, + NDS32AsmParser &Parser) { + assert (Regs.size() > 0 && "Empty list not allowed"); + + auto Op = make_unique(k_RegList, Parser); + Op->RegList.List = new SmallVector(Regs.begin(), Regs.end()); + Op->StartLoc = StartLoc; + Op->EndLoc = EndLoc; + return Op; + } + + bool isGPRAsmReg() const { + return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index <= 31; + } + + /// getStartLoc - Get the location of the first token of this operand. + SMLoc getStartLoc() const override { return StartLoc; } + /// getEndLoc - Get the location of the last token of this operand. + SMLoc getEndLoc() const override { return EndLoc; } + + virtual ~NDS32Operand() { + switch (Kind) { + case k_Immediate: + break; + case k_Memory: + break; + case k_RegList: + delete RegList.List; + case k_RegisterIndex: + case k_Token: + break; + } + } + + void print(raw_ostream &OS) const override { + switch (Kind) { + case k_Immediate: + OS << "Imm<"; + OS << *Imm.Val; + OS << ">"; + break; + case k_Memory: + OS << ""; + break; + case k_RegisterIndex: + OS << "RegIdx<" << RegIdx.Index << ":" << RegIdx.Kind << ">"; + break; + case k_Token: + OS << Tok.Data; + break; + case k_RegList: + OS << "RegList< "; + for (auto Reg : (*RegList.List)) + OS << Reg << " "; + OS << ">"; + break; + } + } +}; // class NDS32Operand +} // namespace + +namespace llvm { +extern const MCInstrDesc NDS32Insts[]; +} + +bool NDS32AsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) { + SmallVector, 1> Operands; + OperandMatchResultTy ResTy = parseAnyRegister(Operands); + if (ResTy == MatchOperand_Success) { + assert(Operands.size() == 1); + NDS32Operand &Operand = static_cast(*Operands.front()); + StartLoc = Operand.getStartLoc(); + EndLoc = Operand.getEndLoc(); + + if (Operand.isGPRAsmReg()) { + RegNo = Operand.getGPR32Reg(); + } + + return (RegNo == (unsigned)-1); + } + + assert(Operands.size() == 0); + return (RegNo == (unsigned)-1); +} + +OperandMatchResultTy +NDS32AsmParser::parseImm(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + case AsmToken::LParen: + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Integer: + case AsmToken::Tilde: + case AsmToken::String: + break; + } + + const MCExpr *IdVal; + SMLoc S = Parser.getTok().getLoc(); + if (getParser().parseExpression(IdVal)) + return MatchOperand_ParseFail; + + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(NDS32Operand::CreateImm(IdVal, S, E, *this)); + return MatchOperand_Success; +} + +int NDS32AsmParser::matchCPURegisterName(StringRef Name) { + int CC; + + CC = StringSwitch(Name) + .Case("r0", 0) + .Case("r1", 1) + .Case("r2", 2) + .Case("r3", 3) + .Case("r4", 4) + .Case("r5", 5) + .Case("r6", 6) + .Case("r7", 7) + .Case("r8", 8) + .Case("r9", 9) + .Case("r10",10) + .Case("r11",11) + .Case("r12",12) + .Case("r13",13) + .Case("r14",14) + .Case("r15",15) + .Case("r16",16) + .Case("r17",17) + .Case("r18",18) + .Case("r19",19) + .Case("r20",20) + .Case("r21",21) + .Case("r22",22) + .Case("r23",23) + .Case("r24",24) + .Case("r25",25) + .Case("r26",26) + .Case("r27",27) + .Case("fp", 28) + .Case("gp", 29) + .Case("lp", 30) + .Case("sp", 31) + .Default(-1); + + return CC; +} + +/// @name Auto-generated Match Functions +/// { + +static unsigned MatchRegisterName(StringRef Name); + +/// } + +/// Try to parse a register name. The token must be an Identifier when called, +/// and if it is a register name the token is eaten and the register number is +/// returned. Otherwise return -1. +/// +int NDS32AsmParser::tryParseRegister() { + MCAsmParser &Parser = getParser(); + const AsmToken &Tok = Parser.getTok(); + if (Tok.isNot(AsmToken::Identifier)) return -1; + std::string lowerCase = Tok.getString().lower(); + int RegNum = MatchRegisterName(lowerCase); + + Parser.Lex(); // Eat identifier token. + return RegNum; +} + +OperandMatchResultTy +NDS32AsmParser::matchAnyRegisterNameWithoutDollar(OperandVector &Operands, + StringRef Identifier, + SMLoc S) { + int Index = matchCPURegisterName(Identifier); + if (Index != -1) { + Operands.push_back(NDS32Operand::createGPRReg( + Index, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + return MatchOperand_Success; + } + + return MatchOperand_NoMatch; +} + +OperandMatchResultTy NDS32AsmParser:: +matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) { + MCAsmParser &Parser = getParser(); + auto Token = Parser.getLexer().peekTok(false); + + if (Token.is(AsmToken::Identifier)) { + DEBUG(dbgs() << ".. identifier\n"); + StringRef Identifier = Token.getIdentifier(); + OperandMatchResultTy ResTy = + matchAnyRegisterNameWithoutDollar(Operands, Identifier, S); + return ResTy; + } else if (Token.is(AsmToken::Integer)) { + DEBUG(dbgs() << ".. integer\n"); + Operands.push_back(NDS32Operand::createNumericReg( + Token.getIntVal(), getContext().getRegisterInfo(), S, Token.getLoc(), + *this)); + return MatchOperand_Success; + } + + DEBUG(dbgs() << Parser.getTok().getKind() << "\n"); + + return MatchOperand_NoMatch; +} + +bool NDS32AsmParser::searchSymbolAlias(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + MCSymbol *Sym = getContext().lookupSymbol(Parser.getTok().getIdentifier()); + if (Sym) { + SMLoc S = Parser.getTok().getLoc(); + const MCExpr *Expr; + if (Sym->isVariable()) + Expr = Sym->getVariableValue(); + else + return false; + if (Expr->getKind() == MCExpr::SymbolRef) { + const MCSymbolRefExpr *Ref = static_cast(Expr); + StringRef DefSymbol = Ref->getSymbol().getName(); + if (DefSymbol.startswith("$")) { + OperandMatchResultTy ResTy = + matchAnyRegisterNameWithoutDollar(Operands, DefSymbol.substr(1), S); + if (ResTy == MatchOperand_Success) { + Parser.Lex(); + return true; + } else if (ResTy == MatchOperand_ParseFail) + llvm_unreachable("Should never ParseFail"); + return false; + } + } + } + return false; +} + +OperandMatchResultTy +NDS32AsmParser::parseAnyRegister(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + DEBUG(dbgs() << "parseAnyRegister\n"); + + auto Token = Parser.getTok(); + + SMLoc S = Token.getLoc(); + + if (Token.isNot(AsmToken::Dollar)) { + DEBUG(dbgs() << ".. !$ -> try sym aliasing\n"); + if (Token.is(AsmToken::Identifier)) { + if (searchSymbolAlias(Operands)) + return MatchOperand_Success; + } + DEBUG(dbgs() << ".. !symalias -> NoMatch\n"); + return MatchOperand_NoMatch; + } + DEBUG(dbgs() << ".. $\n"); + + OperandMatchResultTy ResTy = matchAnyRegisterWithoutDollar(Operands, S); + if (ResTy == MatchOperand_Success) { + Parser.Lex(); // $ + Parser.Lex(); // identifier + } + return ResTy; +} + +OperandMatchResultTy +NDS32AsmParser::parseJumpTarget(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + DEBUG(dbgs() << "parseJumpTarget\n"); + + SMLoc S = getLexer().getLoc(); + + // Integers and expressions are acceptable + OperandMatchResultTy ResTy = parseImm(Operands); + if (ResTy != MatchOperand_NoMatch) + return ResTy; + + // Registers are a valid target and have priority over symbols. + ResTy = parseAnyRegister(Operands); + if (ResTy != MatchOperand_NoMatch) + return ResTy; + + const MCExpr *Expr = nullptr; + if (Parser.parseExpression(Expr)) { + // We have no way of knowing if a symbol was consumed so we must ParseFail + return MatchOperand_ParseFail; + } + Operands.push_back( + NDS32Operand::CreateImm(Expr, S, getLexer().getLoc(), *this)); + return MatchOperand_Success; +} + +/// Sometimes (i.e. load/stores) the operand may be followed immediately by +/// either this. +/// ::= '(', register, ')' +/// handle it before we iterate so we don't get tripped up by the lack of +/// a comma. +bool NDS32AsmParser::parseParenSuffix(StringRef Name, OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + if (getLexer().is(AsmToken::LParen)) { + Operands.push_back( + NDS32Operand::CreateToken("(", getLexer().getLoc(), *this)); + Parser.Lex(); + if (parseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + if (Parser.getTok().isNot(AsmToken::RParen)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token, expected ')'"); + } + Operands.push_back( + NDS32Operand::CreateToken(")", getLexer().getLoc(), *this)); + Parser.Lex(); + } + return false; +} + +bool NDS32AsmParser::parseBracketSuffix(StringRef Name, + OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + if (getLexer().is(AsmToken::LBrac)) { + Operands.push_back( + NDS32Operand::CreateToken("[", getLexer().getLoc(), *this)); + Parser.Lex(); + if (parseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + if (Parser.getTok().isNot(AsmToken::RBrac)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token, expected ']'"); + } + Operands.push_back( + NDS32Operand::CreateToken("]", getLexer().getLoc(), *this)); + Parser.Lex(); + } + return false; +} + +bool NDS32AsmParser:: +ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + DEBUG(dbgs() << "ParseInstruction\n"); + + // Check if we have valid mnemonic + if (!mnemonicIsValid(Name, 0)) { + Parser.eatToEndOfStatement(); + return Error(NameLoc, "unknown instruction"); + } + // First operand in MCInst is instruction mnemonic. + Operands.push_back(NDS32Operand::CreateToken(Name, NameLoc, *this)); + + // Read the remaining operands. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + // Read the first operand. + if (parseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + if (getLexer().is(AsmToken::LBrac) && parseBracketSuffix(Name, Operands)) + return true; + // AFAIK, parenthesis suffixes are never on the first operand + + while (getLexer().is(AsmToken::Comma)) { + Parser.Lex(); // Eat the comma. + // Parse and remember the operand. + if (parseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + // Parse bracket and parenthesis suffixes before we iterate + if (getLexer().is(AsmToken::LBrac)) { + if (parseBracketSuffix(Name, Operands)) + return true; + } else if (getLexer().is(AsmToken::LParen) && + parseParenSuffix(Name, Operands)) + return true; + } + } + if (getLexer().isNot(AsmToken::EndOfStatement)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool NDS32AsmParser::ParseDirective(AsmToken DirectiveID) { + return true; +} + +/// Parse a register list. +bool NDS32AsmParser::parseRegisterList(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + SMLoc S, E; + int BaseRegNum = -1; + int RegListBeginRegNum = -1; + int RegListEndRegNum = -1; + int64_t Enable4Encode = 0; + int Reg = 0; + SmallVector Registers; + + DEBUG(dbgs() << "ParseRegisterList\n"); + + if (Parser.getTok().is(AsmToken::Dollar)) { + Parser.Lex(); // Eat the Dollar. + DEBUG(dbgs() << "Eat $ \n"); + S = Parser.getTok().getLoc(); + + const AsmToken &BeginRegTok = Parser.getTok(); + RegListBeginRegNum = tryParseRegister(); + if (RegListBeginRegNum == -1) + return Error(BeginRegTok.getLoc(), "register expected"); + + DEBUG(dbgs() << "RegListBeginRegNum = " << RegListBeginRegNum << "\n"); + } else + return Error(S, "Expact $"); + + // The next token must be a Comma + if (!Parser.getTok().is(AsmToken::Comma)) + return Error(Parser.getTok().getLoc(), "Expact ,"); + else + Parser.Lex(); // Eat the Comma. + + // The next token must be a LBrac + if (!Parser.getTok().is(AsmToken::LBrac)) + return Error(Parser.getTok().getLoc(), "Expact ["); + else + Parser.Lex(); // Eat the LBrac. + + if (Parser.getTok().is(AsmToken::Dollar)) { + Parser.Lex(); // Eat the Dollar. + DEBUG(dbgs() << "Eat $ \n"); + + const AsmToken &BaseRegTok = Parser.getTok(); + BaseRegNum = tryParseRegister(); + if (BaseRegNum == -1) + return Error(BaseRegTok.getLoc(), "register expected"); + + DEBUG(dbgs() << "BaseRegNum = " << BaseRegNum << "\n"); + + // insert BaseRegNum to register list first + Registers.push_back(BaseRegNum); + } else + return Error(Parser.getTok().getLoc(), "Expact $"); + + // The next token must a RBrac + if (!Parser.getTok().is(AsmToken::RBrac)) + return Error(Parser.getTok().getLoc(), "Expact ]"); + else + Parser.Lex(); // Eat the RBrac. + + // The next token must a comma + if (!Parser.getTok().is(AsmToken::Comma)) + return Error(Parser.getTok().getLoc(), "Expact ,"); + else + Parser.Lex(); // Eat the Comma. + + if (Parser.getTok().is(AsmToken::Dollar)) { + Parser.Lex(); // Eat the Dollar. + DEBUG(dbgs() << "Eat $ \n"); + + const AsmToken &EndRegTok = Parser.getTok(); + RegListEndRegNum = tryParseRegister(); + if (RegListEndRegNum == -1) + return Error(EndRegTok.getLoc(), "register expected"); + + DEBUG(dbgs() << "RegListEndRegNum = " << RegListEndRegNum << "\n"); + } else + return Error(Parser.getTok().getLoc(), "Expact $"); + + // The next token must a comma + if (!Parser.getTok().is(AsmToken::Comma)) + return Error(Parser.getTok().getLoc(), "Expact ,"); + else + Parser.Lex(); // Eat the Comma. + + // parsing Enable4 + if (Parser.getTok().is(AsmToken::Integer)) { + E = Parser.getTok().getLoc(); + + const MCExpr *Enable4; + if (getParser().parseExpression(Enable4)) + return true; + + const MCConstantExpr *CE = dyn_cast(Enable4); + if (!CE) + return Error (E, "constant expression expected"); + + Enable4Encode = CE->getValue(); + DEBUG(dbgs() << "Enable4 = " << Enable4Encode << "\n"); + } + + // Add all the registers in the range to the register list. + // There is no R0~R27 register in register if Rb == SP. + if (RegListBeginRegNum != NDS32::SP) + for (Reg = RegListBeginRegNum; Reg <= RegListEndRegNum; Reg++) + Registers.push_back(Reg); + + if (Enable4Encode & 1) + Registers.push_back(NDS32::SP); + if (Enable4Encode & 2) + Registers.push_back(NDS32::LP); + if (Enable4Encode & 4) + Registers.push_back(NDS32::GP); + if (Enable4Encode & 8) + Registers.push_back(NDS32::FP); + + // Push the register list operand. + Operands.push_back(NDS32Operand::CreateRegList(Registers, S, E, *this)); + + return false; +} + +// Parse an NDS32 memory expression, return false if successful else return +// true or an error. The first token must be a '[' when called. +bool NDS32AsmParser::parseMemory(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + SMLoc S, E; + bool isMinusOffset = false; + int BaseRegNum = -1; + + DEBUG(dbgs() << "ParseMemory\n"); + + assert(Parser.getTok().is(AsmToken::LBrac) && + "Token is not a Left Bracket"); + S = Parser.getTok().getLoc(); + Parser.Lex(); // Eat left bracket token. + + if (Parser.getTok().is(AsmToken::Dollar)) { + Parser.Lex(); // Eat the Dollar. + DEBUG(dbgs() << "Eat $ \n"); + + const AsmToken &BaseRegTok = Parser.getTok(); + BaseRegNum = tryParseRegister(); + if (BaseRegNum == -1) + return Error(BaseRegTok.getLoc(), "register expected"); + + DEBUG(dbgs() << "BaseRegNum = " << BaseRegNum << "\n"); + } + + // The next token must either be a plus or a closing bracket. + const AsmToken &Tok = Parser.getTok(); + if (!Tok.is(AsmToken::Plus) && + !Tok.is(AsmToken::RBrac)) + return Error(Tok.getLoc(), "malformed memory operand"); + + // parsing [Reg] + if (Tok.is(AsmToken::RBrac)) { + E = Tok.getEndLoc(); + Parser.Lex(); // Eat right bracket token. + + Operands.push_back(NDS32Operand::CreateMem(BaseRegNum, nullptr, 0, 0, + isMinusOffset, S, E, *this)); + return false; + } + + assert(Tok.is(AsmToken::Plus) && "Lost Plus in memory operand?!"); + + if (Tok.is(AsmToken::Plus)) { + DEBUG(dbgs() << "Eat + \n"); + Parser.Lex(); // Eat the Plus. + } + + if (Tok.is(AsmToken::LParen)) { + DEBUG(dbgs() << "Eat ( \n"); + Parser.Lex(); // Eat the LParen. + } + + if (Tok.is(AsmToken::Minus)) { + DEBUG(dbgs() << "Eat - \n"); + Parser.Lex(); // Eat the Minus. + isMinusOffset = true; + } + + // parsing [Reg + Imm] + if (Parser.getTok().is(AsmToken::Integer)) { + E = Parser.getTok().getLoc(); + + const MCExpr *Offset; + if (getParser().parseExpression(Offset)) + return true; + + // The expression has to be a constant. Memory references with relocations + // don't come through here, as they use the