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,562 @@ +//===-- 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; + +#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 ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; + + bool ParseDirective(AsmToken DirectiveID) override; + + OperandMatchResultTy parseImm(OperandVector &Operands); + + OperandMatchResultTy parseAnyRegister(OperandVector &Operands); + + bool parseOperand(OperandVector &Operands, StringRef Mnemonic); + + int tryParseRegister(); + +public: + enum NDS32MatchResultTy { + Match_RequiresNotInRegisterList = FIRST_TARGET_MATCH_RESULT_TY, +#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); + + // 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); + } + + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + } + + void addRegOperands(MCInst &Inst, unsigned N) const { + } + + /// 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 { + } + + void addImmOperands(MCInst &Inst, unsigned N) const { + } + + void addMemRegOffsetOperands(MCInst &Inst, unsigned N) const { + } + + void addAddrRegShiftOperands(MCInst &Inst, unsigned N) const { + } + + void addAddrImm15sWordOperands(MCInst &Inst, unsigned N) const { + } + + void addAddrImm15sHalfOperands(MCInst &Inst, unsigned N) const { + } + + void addAddrImm15sByteOperands(MCInst &Inst, unsigned N) const { + } + + void addAddrImm3uWordOperands(MCInst &Inst, unsigned N) const { + } + + void addAddrImm3uHalfOperands(MCInst &Inst, unsigned N) const { + } + + void addAddrImm3uByteOperands(MCInst &Inst, unsigned N) const { + } + + void addAddrFPImm7uWordOperands(MCInst &Inst, unsigned N) const { + } + + void addAddrSPImm7uWordOperands(MCInst &Inst, unsigned N) const { + } + + void addRegListOperands(MCInst &Inst, unsigned N) const { + } + + 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 false; + } + bool isImm11s() const { + return false; + } + bool isImm15s() const { + return false; + } + bool isImm20s() const { + return false; + } + bool isImm3u() const { + return false; + } + bool isImm5u() const { + return false; + } + bool isImm15u() const { + return false; + } + bool isImm20u() const { + return false; + } + bool isMemNoOffset() const { + return false; + } + // [Reg + Reg << sv], sv could be 0, 1, 2, 3 + bool isAddrRegShift() const { + return false; + } + // [Reg + imm15s << 2] + bool isAddrImm15sWord() const { + return false; + } + // [Reg + imm15s << 1] + bool isAddrImm15sHalf() const { + return false; + } + // [Reg + imm15s] + bool isAddrImm15sByte() const { + return false; + } + // [Reg + imm3u << 2] + bool isAddrImm3uWord() const { + return false; + } + // [Reg + imm3u << 1] + bool isAddrImm3uHalf() const { + return false; + } + // [Reg + imm3u] + bool isAddrImm3uByte() const { + return false; + } + // [FP + imm7u << 2] + bool isAddrFPImm7uWord() const { + return false; + } + // [SP + imm7u << 2] + bool isAddrSPImm7uWord() const { + return false; + } + // imm15s << 2 + bool isOffsetImm15sWord() const { + return false; + } + // imm15s << 1 + bool isOffsetImm15sHalf() const { + return false; + } + // imm15s + bool isOffsetImm15sByte() const { + return false; + } + bool isMemRegOffset() const { + return false; + } + void addMemNoOffsetOperands(MCInst &Inst, unsigned N) const { + } + + void addOffsetImm15sWordOperands(MCInst &Inst, unsigned N) const { + } + + void addOffsetImm15sHalfOperands(MCInst &Inst, unsigned N) const { + } + + void addOffsetImm15sByteOperands(MCInst &Inst, unsigned N) const { + } + + 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 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) { + } + + + static std::unique_ptr + CreateImm(const MCExpr *Val, SMLoc S, SMLoc E, NDS32AsmParser &Parser) { + } + + static std::unique_ptr + CreateMem(unsigned BaseRegNum, const MCConstantExpr *OffsetImm, + unsigned OffsetRegNum, unsigned ShiftImm, bool isMinusOffset, + SMLoc S, SMLoc E, NDS32AsmParser &Parser) { + } + + static std::unique_ptr + CreateRegList(SmallVectorImpl &Regs, SMLoc StartLoc, SMLoc EndLoc, + NDS32AsmParser &Parser) { + } + + 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) { + return false; +} + +OperandMatchResultTy +NDS32AsmParser::parseImm(OperandVector &Operands) { + return MatchOperand_Success; +} + +OperandMatchResultTy +NDS32AsmParser::parseAnyRegister(OperandVector &Operands) { + return MatchOperand_Success; +} + +/// 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() { +} + +bool NDS32AsmParser:: +ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) { + return true; +} + +bool NDS32AsmParser::ParseDirective(AsmToken DirectiveID) { + return true; +} + +bool NDS32AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, + MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) { + return true; +} + +unsigned NDS32AsmParser::checkTargetMatchPredicate(MCInst &Inst) { + switch (Inst.getOpcode()) { + default: + return Match_Success; + } +} + +bool NDS32AsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { + return true; +} + +extern "C" void LLVMInitializeNDS32AsmParser() { + RegisterMCAsmParser X(getTheNDS32Target()); +} + +#define GET_REGISTER_MATCHER +#define GET_MATCHER_IMPLEMENTATION +#include "NDS32GenAsmMatcher.inc" Index: lib/Target/NDS32/CMakeLists.txt =================================================================== --- lib/Target/NDS32/CMakeLists.txt +++ lib/Target/NDS32/CMakeLists.txt @@ -6,6 +6,7 @@ tablegen(LLVM NDS32GenDAGISel.inc -gen-dag-isel) tablegen(LLVM NDS32GenCallingConv.inc -gen-callingconv) tablegen(LLVM NDS32GenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM NDS32GenAsmMatcher.inc -gen-asm-matcher) add_public_tablegen_target(NDS32CommonTableGen) @@ -27,3 +28,4 @@ add_subdirectory(TargetInfo) add_subdirectory(MCTargetDesc) add_subdirectory(InstPrinter) +add_subdirectory(AsmParser) Index: lib/Target/NDS32/LLVMBuild.txt =================================================================== --- lib/Target/NDS32/LLVMBuild.txt +++ lib/Target/NDS32/LLVMBuild.txt @@ -16,13 +16,14 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = TargetInfo MCTargetDesc InstPrinter +subdirectories = TargetInfo MCTargetDesc InstPrinter AsmParser [component_0] type = TargetGroup name = NDS32 parent = Target has_asmprinter = 1 +has_asmparser = 1 [component_1] type = Library Index: lib/Target/NDS32/NDS32Predicate.td =================================================================== --- lib/Target/NDS32/NDS32Predicate.td +++ lib/Target/NDS32/NDS32Predicate.td @@ -232,6 +232,7 @@ def reglist : Operand { let MIOperandInfo = (ops GPR:$base, variable_ops); let PrintMethod = "printRegisterList"; + let ParserMatchClass = RegListAsmOperand; } @@ -239,10 +240,6 @@ // Branch/Jump target Operands Predicates // -def NDS32JumpTarget : AsmOperandClass { - let Name = "NDS32JumpTarget"; -} - def nds32_jump_target : Operand { let OperandType = "OPERAND_PCREL"; } Index: lib/Target/NDS32/NDS32TargetStreamer.h =================================================================== --- /dev/null +++ lib/Target/NDS32/NDS32TargetStreamer.h @@ -0,0 +1,33 @@ +//===- NDS32TargetStreamer.h - NDS32TargetStreamer class --*- C++ -*-------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the NDS32TargetStreamer class. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIB_TARGET_NDS32_NDS32TARGETSTREAMER_H +#define LLVM_LIB_TARGET_NDS32_NDS32TARGETSTREAMER_H + +#include "llvm/ADT/MapVector.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCStreamer.h" + +using namespace llvm; +// +// NDS32TargetStreamer Implemenation +// +class NDS32TargetStreamer : public MCTargetStreamer { +public: + NDS32TargetStreamer(MCStreamer &S); +}; + +NDS32TargetStreamer::NDS32TargetStreamer(MCStreamer &S) + : MCTargetStreamer(S) {} + +#endif