diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -311,6 +311,7 @@ EM_RISCV = 243, // RISC-V EM_LANAI = 244, // Lanai 32-bit processor EM_BPF = 247, // Linux kernel bpf virtual machine + EM_VE = 251, // NEC SX-Aurora VE }; // Object file classes. @@ -764,6 +765,11 @@ #include "ELFRelocs/MSP430.def" }; +// ELF Relocation type for VE. +enum { +#include "ELFRelocs/VE.def" +}; + #undef ELF_RELOC // Section header. diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/VE.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/VE.def new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/VE.def @@ -0,0 +1,6 @@ + +#ifndef ELF_RELOC +#error "ELF_RELOC must be defined" +#endif + +ELF_RELOC(R_VE_NONE, 0) diff --git a/llvm/lib/Target/VE/AsmParser/CMakeLists.txt b/llvm/lib/Target/VE/AsmParser/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/VE/AsmParser/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_component_library(LLVMVEAsmParser + VEAsmParser.cpp + ) diff --git a/llvm/lib/Target/VE/LLVMBuild.txt b/llvm/lib/Target/VE/AsmParser/LLVMBuild.txt copy from llvm/lib/Target/VE/LLVMBuild.txt copy to llvm/lib/Target/VE/AsmParser/LLVMBuild.txt --- a/llvm/lib/Target/VE/LLVMBuild.txt +++ b/llvm/lib/Target/VE/AsmParser/LLVMBuild.txt @@ -1,4 +1,4 @@ -;===- ./lib/Target/VE/LLVMBuild.txt ----------------------------*- Conf -*--===; +;===- ./lib/Target/VE/AsmParser/LLVMBuild.txt ------------------*- Conf -*--===; ; ; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. ; See https://llvm.org/LICENSE.txt for license information. @@ -14,20 +14,9 @@ ; ;===------------------------------------------------------------------------===; -[common] -subdirectories = MCTargetDesc TargetInfo - [component_0] -type = TargetGroup -name = VE -parent = Target -has_asmparser = 0 -has_asmprinter = 1 - -[component_1] type = Library -name = VECodeGen +name = VEAsmParser parent = VE -required_libraries = Analysis AsmPrinter CodeGen Core - MC SelectionDAG VEDesc VEInfo Support Target +required_libraries = MC MCParser VEDesc VEInfo Support add_to_library_groups = VE diff --git a/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp b/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp @@ -0,0 +1,846 @@ +//===-- VEAsmParser.cpp - Parse VE 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/VEMCExpr.h" +#include "MCTargetDesc/VEMCTargetDesc.h" +#include "TargetInfo/VETargetInfo.h" +#include "VE.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include +#include + +using namespace llvm; + +#define DEBUG_TYPE "ve-asmparser" + +namespace { + +class VEOperand; + +class VEAsmParser : public MCTargetAsmParser { + MCAsmParser &Parser; + + /// @name Auto-generated Match Functions + /// { + +#define GET_ASSEMBLER_HEADER +#include "VEGenAsmMatcher.inc" + + /// } + + // public interface of the MCTargetAsmParser. + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) override; + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; + int parseRegisterName(unsigned (*matchFn)(StringRef)); + OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) override; + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; + bool ParseDirective(AsmToken DirectiveID) override; + + // Custom parse functions for VE specific operands. + OperandMatchResultTy parseMEMOperand(OperandVector &Operands); + OperandMatchResultTy parseMEMAsOperand(OperandVector &Operands); + OperandMatchResultTy parseOperand(OperandVector &Operands, StringRef Name); + OperandMatchResultTy parseVEAsmOperand(std::unique_ptr &Operand); + +public: + VEAsmParser(const MCSubtargetInfo &sti, MCAsmParser &parser, + const MCInstrInfo &MII, const MCTargetOptions &Options) + : MCTargetAsmParser(Options, sti, MII), Parser(parser) { + // Initialize the set of available features. + setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits())); + } +}; + +} // end anonymous namespace + +namespace { + +/// VEOperand - Instances of this class represent a parsed VE machine +/// instruction. +class VEOperand : public MCParsedAsmOperand { +private: + enum KindTy { + k_Token, + k_Register, + k_Immediate, + // SX-Aurora ASX form is disp(index, base). + k_MemoryRegRegImm, // base=reg, index=reg, disp=imm + k_MemoryRegImmImm, // base=reg, index=imm, disp=imm + k_MemoryZeroRegImm, // base=0, index=reg, disp=imm + k_MemoryZeroImmImm, // base=0, index=imm, disp=imm + // SX-Aurora AS form is disp(base). + k_MemoryRegImm, // base=reg, disp=imm + } Kind; + + SMLoc StartLoc, EndLoc; + + struct Token { + const char *Data; + unsigned Length; + }; + + struct RegOp { + unsigned RegNum; + }; + + struct ImmOp { + const MCExpr *Val; + }; + + struct MemOp { + unsigned Base; + unsigned IndexReg; + const MCExpr *Index; + const MCExpr *Offset; + }; + + union { + struct Token Tok; + struct RegOp Reg; + struct ImmOp Imm; + struct MemOp Mem; + }; + +public: + VEOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} + + bool isToken() const override { return Kind == k_Token; } + bool isReg() const override { return Kind == k_Register; } + bool isImm() const override { return Kind == k_Immediate; } + bool isMem() const override { + return isMEMrri() || isMEMrii() || isMEMzri() || isMEMzii() || isMEMri(); + } + bool isMEMrri() const { return Kind == k_MemoryRegRegImm; } + bool isMEMrii() const { return Kind == k_MemoryRegImmImm; } + bool isMEMzri() const { return Kind == k_MemoryZeroRegImm; } + bool isMEMzii() const { return Kind == k_MemoryZeroImmImm; } + bool isMEMri() const { return Kind == k_MemoryRegImm; } + bool isSImm7() { + if (!isImm()) + return false; + + // Constant case + if (const MCConstantExpr *ConstExpr = dyn_cast(Imm.Val)) { + int64_t Value = ConstExpr->getValue(); + return isInt<7>(Value); + } + return false; + } + + StringRef getToken() const { + assert(Kind == k_Token && "Invalid access!"); + return StringRef(Tok.Data, Tok.Length); + } + + unsigned getReg() const override { + assert((Kind == k_Register) && "Invalid access!"); + return Reg.RegNum; + } + + const MCExpr *getImm() const { + assert((Kind == k_Immediate) && "Invalid access!"); + return Imm.Val; + } + + unsigned getMemBase() const { + assert((Kind == k_MemoryRegRegImm || Kind == k_MemoryRegImmImm || + Kind == k_MemoryRegImm) && + "Invalid access!"); + return Mem.Base; + } + + unsigned getMemIndexReg() const { + assert((Kind == k_MemoryRegRegImm || Kind == k_MemoryZeroRegImm) && + "Invalid access!"); + return Mem.IndexReg; + } + + const MCExpr *getMemIndex() const { + assert((Kind == k_MemoryRegImmImm || Kind == k_MemoryZeroImmImm) && + "Invalid access!"); + return Mem.Index; + } + + const MCExpr *getMemOffset() const { + assert((Kind == k_MemoryRegRegImm || Kind == k_MemoryRegImmImm || + Kind == k_MemoryZeroImmImm || Kind == k_MemoryZeroRegImm || + Kind == k_MemoryRegImm) && + "Invalid access!"); + return Mem.Offset; + } + + void setMemOffset(const MCExpr *off) { + assert((Kind == k_MemoryRegRegImm || Kind == k_MemoryRegImmImm || + Kind == k_MemoryZeroImmImm || Kind == k_MemoryZeroRegImm || + Kind == k_MemoryRegImm) && + "Invalid access!"); + Mem.Offset = off; + } + + /// 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; } + + void print(raw_ostream &OS) const override { + switch (Kind) { + case k_Token: + OS << "Token: " << getToken() << "\n"; + break; + case k_Register: + OS << "Reg: #" << getReg() << "\n"; + break; + case k_Immediate: + OS << "Imm: " << getImm() << "\n"; + break; + case k_MemoryRegRegImm: + assert(getMemOffset() != nullptr); + OS << "Mem: #" << getMemBase() << "+#" << getMemIndexReg() << "+" + << *getMemOffset() << "\n"; + break; + case k_MemoryRegImmImm: + assert(getMemIndex() != nullptr && getMemOffset() != nullptr); + OS << "Mem: #" << getMemBase() << "+" << *getMemIndex() << "+" + << *getMemOffset() << "\n"; + break; + case k_MemoryZeroRegImm: + assert(getMemOffset() != nullptr); + OS << "Mem: 0+#" << getMemIndexReg() << "+" << *getMemOffset() << "\n"; + break; + case k_MemoryZeroImmImm: + assert(getMemIndex() != nullptr && getMemOffset() != nullptr); + OS << "Mem: 0+" << *getMemIndex() << "+" << *getMemOffset() << "\n"; + break; + case k_MemoryRegImm: + assert(getMemOffset() != nullptr); + OS << "Mem: #" << getMemBase() << "+" << *getMemOffset() << "\n"; + break; + } + } + + 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!"); + const MCExpr *Expr = getImm(); + addExpr(Inst, Expr); + } + + void addSImm7Operands(MCInst &Inst, unsigned N) const { + addImmOperands(Inst, N); + } + + 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 addMEMrriOperands(MCInst &Inst, unsigned N) const { + assert(N == 3 && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::createReg(getMemBase())); + Inst.addOperand(MCOperand::createReg(getMemIndexReg())); + addExpr(Inst, getMemOffset()); + } + + void addMEMriiOperands(MCInst &Inst, unsigned N) const { + assert(N == 3 && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::createReg(getMemBase())); + addExpr(Inst, getMemIndex()); + addExpr(Inst, getMemOffset()); + } + + void addMEMzriOperands(MCInst &Inst, unsigned N) const { + assert(N == 3 && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::createImm(0)); + Inst.addOperand(MCOperand::createReg(getMemIndexReg())); + addExpr(Inst, getMemOffset()); + } + + void addMEMziiOperands(MCInst &Inst, unsigned N) const { + assert(N == 3 && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::createImm(0)); + addExpr(Inst, getMemIndex()); + addExpr(Inst, getMemOffset()); + } + + void addMEMriOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::createReg(getMemBase())); + addExpr(Inst, getMemOffset()); + } + + static std::unique_ptr CreateToken(StringRef Str, SMLoc S) { + auto Op = std::make_unique(k_Token); + Op->Tok.Data = Str.data(); + Op->Tok.Length = Str.size(); + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static std::unique_ptr CreateReg(unsigned RegNum, SMLoc S, + SMLoc E) { + auto Op = std::make_unique(k_Register); + Op->Reg.RegNum = RegNum; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static std::unique_ptr CreateImm(const MCExpr *Val, SMLoc S, + SMLoc E) { + auto Op = std::make_unique(k_Immediate); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static std::unique_ptr + MorphToMEMri(unsigned Base, std::unique_ptr Op) { + const MCExpr *Imm = Op->getImm(); + Op->Kind = k_MemoryRegImm; + Op->Mem.Base = Base; + Op->Mem.IndexReg = 0; + Op->Mem.Index = nullptr; + Op->Mem.Offset = Imm; + return Op; + } + + static std::unique_ptr + MorphToMEMrri(unsigned Base, unsigned Index, std::unique_ptr Op) { + const MCExpr *Imm = Op->getImm(); + Op->Kind = k_MemoryRegRegImm; + Op->Mem.Base = Base; + Op->Mem.IndexReg = Index; + Op->Mem.Index = nullptr; + Op->Mem.Offset = Imm; + return Op; + } + + static std::unique_ptr + MorphToMEMrii(unsigned Base, const MCExpr *Index, + std::unique_ptr Op) { + const MCExpr *Imm = Op->getImm(); + Op->Kind = k_MemoryRegImmImm; + Op->Mem.Base = Base; + Op->Mem.IndexReg = 0; + Op->Mem.Index = Index; + Op->Mem.Offset = Imm; + return Op; + } + + static std::unique_ptr + MorphToMEMzri(unsigned Index, std::unique_ptr Op) { + const MCExpr *Imm = Op->getImm(); + Op->Kind = k_MemoryZeroRegImm; + Op->Mem.Base = 0; + Op->Mem.IndexReg = Index; + Op->Mem.Index = nullptr; + Op->Mem.Offset = Imm; + return Op; + } + + static std::unique_ptr + MorphToMEMzii(const MCExpr *Index, std::unique_ptr Op) { + const MCExpr *Imm = Op->getImm(); + Op->Kind = k_MemoryZeroImmImm; + Op->Mem.Base = 0; + Op->Mem.IndexReg = 0; + Op->Mem.Index = Index; + Op->Mem.Offset = Imm; + return Op; + } +}; + +} // end anonymous namespace + +bool VEAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, + MCStreamer &Out, uint64_t &ErrorInfo, + bool MatchingInlineAsm) { + MCInst Inst; + unsigned MatchResult = + MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); + switch (MatchResult) { + case Match_Success: + Inst.setLoc(IDLoc); + Out.emitInstruction(Inst, getSTI()); + return false; + + case Match_MissingFeature: + return Error(IDLoc, + "instruction requires a CPU feature not currently enabled"); + + case Match_InvalidOperand: { + SMLoc ErrorLoc = IDLoc; + if (ErrorInfo != ~0ULL) { + if (ErrorInfo >= Operands.size()) + return Error(IDLoc, "too few operands for instruction"); + + ErrorLoc = ((VEOperand &)*Operands[ErrorInfo]).getStartLoc(); + if (ErrorLoc == SMLoc()) + ErrorLoc = IDLoc; + } + + return Error(ErrorLoc, "invalid operand for instruction"); + } + case Match_MnemonicFail: + return Error(IDLoc, "invalid instruction mnemonic"); + } + llvm_unreachable("Implement any new match types added!"); +} + +bool VEAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) { + if (tryParseRegister(RegNo, StartLoc, EndLoc) != MatchOperand_Success) + return Error(StartLoc, "invalid register name"); + return false; +} + +/// Parses a register name using a given matching function. +/// Checks for lowercase or uppercase if necessary. +int VEAsmParser::parseRegisterName(unsigned (*matchFn)(StringRef)) { + StringRef Name = Parser.getTok().getString(); + + int RegNum = matchFn(Name); + + // GCC supports case insensitive register names. Some of the AVR registers + // are all lower case, some are all upper case but non are mixed. We prefer + // to use the original names in the register definitions. That is why we + // have to test both upper and lower case here. + if (RegNum == VE::NoRegister) { + RegNum = matchFn(Name.lower()); + } + if (RegNum == VE::NoRegister) { + RegNum = matchFn(Name.upper()); + } + + return RegNum; +} + +/// Maps from the set of all register names to a register number. +/// \note Generated by TableGen. +static unsigned MatchRegisterName(StringRef Name); + +/// Maps from the set of all alternative registernames to a register number. +/// \note Generated by TableGen. +static unsigned MatchRegisterAltName(StringRef Name); + +OperandMatchResultTy +VEAsmParser::tryParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { + const AsmToken Tok = Parser.getTok(); + StartLoc = Tok.getLoc(); + EndLoc = Tok.getEndLoc(); + RegNo = 0; + if (getLexer().getKind() != AsmToken::Percent) + return MatchOperand_NoMatch; + Parser.Lex(); + + RegNo = parseRegisterName(&MatchRegisterName); + if (RegNo == VE::NoRegister) + RegNo = parseRegisterName(&MatchRegisterAltName); + + if (RegNo != VE::NoRegister) { + Parser.Lex(); + return MatchOperand_Success; + } + + getLexer().UnLex(Tok); + return MatchOperand_NoMatch; +} + +bool VEAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) { + + // First operand in MCInst is instruction mnemonic. + Operands.push_back(VEOperand::CreateToken(Name, NameLoc)); + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + // Read the first operand. + if (parseOperand(Operands, Name) != MatchOperand_Success) { + SMLoc Loc = getLexer().getLoc(); + return Error(Loc, "unexpected token"); + } + + while (getLexer().is(AsmToken::Comma)) { + Parser.Lex(); // Eat the comma. + // Parse and remember the operand. + if (parseOperand(Operands, Name) != MatchOperand_Success) { + SMLoc Loc = getLexer().getLoc(); + return Error(Loc, "unexpected token"); + } + } + } + if (getLexer().isNot(AsmToken::EndOfStatement)) { + SMLoc Loc = getLexer().getLoc(); + return Error(Loc, "unexpected token"); + } + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool VEAsmParser::ParseDirective(AsmToken DirectiveID) { + // Let the MC layer to handle other directives. + return true; +} + +OperandMatchResultTy VEAsmParser::parseMEMOperand(OperandVector &Operands) { + LLVM_DEBUG(dbgs() << "parseMEMOpeand\n"); + const AsmToken &Tok = Parser.getTok(); + SMLoc S = Tok.getLoc(); + SMLoc E = Tok.getEndLoc(); + // Parse ASX format + // disp + // disp(, base) + // disp(index) + // disp(index, base) + // (, base) + // (index) + // (index, base) + + std::unique_ptr Offset; + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + + case AsmToken::Minus: + case AsmToken::Integer: + case AsmToken::Dot: { + const MCExpr *EVal; + if (!getParser().parseExpression(EVal, E)) + Offset = VEOperand::CreateImm(EVal, S, E); + else + return MatchOperand_NoMatch; + break; + } + case AsmToken::LParen: + // empty disp (= 0) + Offset = + VEOperand::CreateImm(MCConstantExpr::create(0, getContext()), S, E); + break; + } + + switch (getLexer().getKind()) { + default: + return MatchOperand_ParseFail; + + case AsmToken::EndOfStatement: + Operands.push_back(VEOperand::MorphToMEMzii( + MCConstantExpr::create(0, getContext()), std::move(Offset))); + return MatchOperand_Success; + + case AsmToken::LParen: + Parser.Lex(); // Eat the ( + break; + } + + const MCExpr *IndexValue = nullptr; + unsigned IndexReg = 0; + ; + + switch (getLexer().getKind()) { + default: + if (ParseRegister(IndexReg, S, E)) + return MatchOperand_ParseFail; + break; + + case AsmToken::Minus: + case AsmToken::Integer: + case AsmToken::Dot: + if (getParser().parseExpression(IndexValue, E)) + return MatchOperand_ParseFail; + break; + + case AsmToken::Comma: + // empty index + IndexValue = MCConstantExpr::create(0, getContext()); + break; + } + + switch (getLexer().getKind()) { + default: + return MatchOperand_ParseFail; + + case AsmToken::RParen: + Parser.Lex(); // Eat the ) + Operands.push_back( + IndexValue ? VEOperand::MorphToMEMzii(IndexValue, std::move(Offset)) + : VEOperand::MorphToMEMzri(IndexReg, std::move(Offset))); + return MatchOperand_Success; + + case AsmToken::Comma: + Parser.Lex(); // Eat the , + break; + } + + unsigned BaseReg = 0; + if (ParseRegister(BaseReg, S, E)) + return MatchOperand_ParseFail; + + if (!Parser.getTok().is(AsmToken::RParen)) + return MatchOperand_ParseFail; + + Parser.Lex(); // Eat the ) + Operands.push_back( + IndexValue + ? VEOperand::MorphToMEMrii(BaseReg, IndexValue, std::move(Offset)) + : VEOperand::MorphToMEMrri(BaseReg, IndexReg, std::move(Offset))); + + return MatchOperand_Success; +} + +OperandMatchResultTy VEAsmParser::parseMEMAsOperand(OperandVector &Operands) { + LLVM_DEBUG(dbgs() << "parseMEMAsOpeand\n"); + const AsmToken &Tok = Parser.getTok(); + SMLoc S = Tok.getLoc(); + SMLoc E = Tok.getEndLoc(); + // Parse AS format + // disp + // disp(, base) + // disp(base) + // disp() + // (, base) + // (base) + // base + + unsigned BaseReg = VE::NoRegister; + std::unique_ptr Offset; + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + + case AsmToken::Minus: + case AsmToken::Integer: + case AsmToken::Dot: { + const MCExpr *EVal; + if (!getParser().parseExpression(EVal, E)) + Offset = VEOperand::CreateImm(EVal, S, E); + else + return MatchOperand_NoMatch; + break; + } + case AsmToken::Percent: + if (ParseRegister(BaseReg, S, E)) + return MatchOperand_NoMatch; + Offset = + VEOperand::CreateImm(MCConstantExpr::create(0, getContext()), S, E); + break; + + case AsmToken::LParen: + // empty disp (= 0) + Offset = + VEOperand::CreateImm(MCConstantExpr::create(0, getContext()), S, E); + break; + } + + switch (getLexer().getKind()) { + default: + return MatchOperand_ParseFail; + + case AsmToken::EndOfStatement: + case AsmToken::Comma: + Operands.push_back(VEOperand::MorphToMEMri(BaseReg, std::move(Offset))); + return MatchOperand_Success; + + case AsmToken::LParen: + if (BaseReg != VE::NoRegister) + return MatchOperand_ParseFail; + Parser.Lex(); // Eat the ( + break; + } + + switch (getLexer().getKind()) { + default: + if (ParseRegister(BaseReg, S, E)) + return MatchOperand_ParseFail; + break; + + case AsmToken::Comma: + Parser.Lex(); // Eat the , + if (ParseRegister(BaseReg, S, E)) + return MatchOperand_ParseFail; + break; + + case AsmToken::RParen: + break; + } + + if (!Parser.getTok().is(AsmToken::RParen)) + return MatchOperand_ParseFail; + + Parser.Lex(); // Eat the ) + Operands.push_back(VEOperand::MorphToMEMri(BaseReg, std::move(Offset))); + + return MatchOperand_Success; +} + +OperandMatchResultTy VEAsmParser::parseOperand(OperandVector &Operands, + StringRef Mnemonic) { + LLVM_DEBUG(dbgs() << "parseOpeand\n"); + OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic); + + // If there wasn't a custom match, try the generic matcher below. Otherwise, + // there was a match, but an error occurred, in which case, just return that + // the operand parsing failed. + if (ResTy == MatchOperand_Success || ResTy == MatchOperand_ParseFail) + return ResTy; + + switch (getLexer().getKind()) { + case AsmToken::LParen: { + // Parsing "(" + %vreg + ", " + %vreg + ")" + const AsmToken Tok1 = Parser.getTok(); + Parser.Lex(); // Eat the '('. + + unsigned RegNo1; + SMLoc S1, E1; + if (tryParseRegister(RegNo1, S1, E1) != MatchOperand_Success) { + getLexer().UnLex(Tok1); + return MatchOperand_NoMatch; + } + + if (!Parser.getTok().is(AsmToken::Comma)) + return MatchOperand_ParseFail; + Parser.Lex(); // Eat the ','. + + unsigned RegNo2; + SMLoc S2, E2; + if (tryParseRegister(RegNo2, S2, E2) != MatchOperand_Success) + return MatchOperand_ParseFail; + + if (!Parser.getTok().is(AsmToken::RParen)) + return MatchOperand_ParseFail; + + Operands.push_back(VEOperand::CreateToken(Tok1.getString(), Tok1.getLoc())); + Operands.push_back(VEOperand::CreateReg(RegNo1, S1, E1)); + Operands.push_back(VEOperand::CreateReg(RegNo2, S2, E2)); + Operands.push_back(VEOperand::CreateToken(Parser.getTok().getString(), + Parser.getTok().getLoc())); + Parser.Lex(); // Eat the ')'. + break; + } + default: { + std::unique_ptr Op; + ResTy = parseVEAsmOperand(Op); + if (ResTy != MatchOperand_Success || !Op) + return MatchOperand_ParseFail; + + // Push the parsed operand into the list of operands + Operands.push_back(std::move(Op)); + + if (!Parser.getTok().is(AsmToken::LParen)) + break; + + // Parsing %vec-reg + "(" + %sclar-reg/number + ")" + std::unique_ptr Op1 = VEOperand::CreateToken( + Parser.getTok().getString(), Parser.getTok().getLoc()); + Parser.Lex(); // Eat the '('. + + std::unique_ptr Op2; + ResTy = parseVEAsmOperand(Op2); + if (ResTy != MatchOperand_Success || !Op2) + return MatchOperand_ParseFail; + + if (!Parser.getTok().is(AsmToken::RParen)) + return MatchOperand_ParseFail; + + Operands.push_back(std::move(Op1)); + Operands.push_back(std::move(Op2)); + Operands.push_back(VEOperand::CreateToken(Parser.getTok().getString(), + Parser.getTok().getLoc())); + Parser.Lex(); // Eat the ')'. + break; + } + } + + return MatchOperand_Success; +} + +OperandMatchResultTy +VEAsmParser::parseVEAsmOperand(std::unique_ptr &Op) { + LLVM_DEBUG(dbgs() << "parseVEAsmOpeand\n"); + SMLoc S = Parser.getTok().getLoc(); + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + const MCExpr *EVal; + + Op = nullptr; + switch (getLexer().getKind()) { + default: + break; + + case AsmToken::Percent: + unsigned RegNo; + if (tryParseRegister(RegNo, S, E) == MatchOperand_Success) + Op = VEOperand::CreateReg(RegNo, S, E); + break; + + case AsmToken::Minus: + case AsmToken::Integer: + case AsmToken::Dot: + if (!getParser().parseExpression(EVal, E)) + Op = VEOperand::CreateImm(EVal, S, E); + break; + + case AsmToken::Identifier: { + StringRef Identifier; + if (!getParser().parseIdentifier(Identifier)) { + E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); + + const MCExpr *Res = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + Op = VEOperand::CreateImm(Res, S, E); + } + break; + } + } + return (Op) ? MatchOperand_Success : MatchOperand_ParseFail; +} + +// Force static initialization. +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeVEAsmParser() { + RegisterMCAsmParser A(getTheVETarget()); +} + +#define GET_REGISTER_MATCHER +#define GET_MATCHER_IMPLEMENTATION +#include "VEGenAsmMatcher.inc" diff --git a/llvm/lib/Target/VE/CMakeLists.txt b/llvm/lib/Target/VE/CMakeLists.txt --- a/llvm/lib/Target/VE/CMakeLists.txt +++ b/llvm/lib/Target/VE/CMakeLists.txt @@ -2,7 +2,9 @@ tablegen(LLVM VEGenRegisterInfo.inc -gen-register-info) tablegen(LLVM VEGenInstrInfo.inc -gen-instr-info) +tablegen(LLVM VEGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM VEGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM VEGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM VEGenDAGISel.inc -gen-dag-isel) tablegen(LLVM VEGenSubtargetInfo.inc -gen-subtarget) tablegen(LLVM VEGenCallingConv.inc -gen-callingconv) @@ -21,5 +23,6 @@ VETargetMachine.cpp ) +add_subdirectory(AsmParser) add_subdirectory(TargetInfo) add_subdirectory(MCTargetDesc) diff --git a/llvm/lib/Target/VE/LLVMBuild.txt b/llvm/lib/Target/VE/LLVMBuild.txt --- a/llvm/lib/Target/VE/LLVMBuild.txt +++ b/llvm/lib/Target/VE/LLVMBuild.txt @@ -15,13 +15,13 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = MCTargetDesc TargetInfo +subdirectories = AsmParser MCTargetDesc TargetInfo [component_0] type = TargetGroup name = VE parent = Target -has_asmparser = 0 +has_asmparser = 1 has_asmprinter = 1 [component_1] diff --git a/llvm/lib/Target/VE/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/VE/MCTargetDesc/CMakeLists.txt --- a/llvm/lib/Target/VE/MCTargetDesc/CMakeLists.txt +++ b/llvm/lib/Target/VE/MCTargetDesc/CMakeLists.txt @@ -1,6 +1,9 @@ add_llvm_component_library(LLVMVEDesc + VEAsmBackend.cpp + VEELFObjectWriter.cpp VEInstPrinter.cpp VEMCAsmInfo.cpp + VEMCCodeEmitter.cpp VEMCExpr.cpp VEMCTargetDesc.cpp VETargetStreamer.cpp diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEAsmBackend.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEAsmBackend.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/VE/MCTargetDesc/VEAsmBackend.cpp @@ -0,0 +1,188 @@ +//===-- VEAsmBackend.cpp - VE Assembler Backend ---------------------------===// +// +// 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/VEFixupKinds.h" +#include "MCTargetDesc/VEMCTargetDesc.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) { + switch (Kind) { + default: + llvm_unreachable("Unknown fixup kind!"); + + case VE::fixup_ve_hi32: + case VE::fixup_ve_pc_hi32: + case VE::fixup_ve_got_hi32: + case VE::fixup_ve_gotoff_hi32: + case VE::fixup_ve_plt_hi32: + case VE::fixup_ve_tls_gd_hi32: + case VE::fixup_ve_tpoff_hi32: + return (Value >> 32) & 0xffffffff; + + case VE::fixup_ve_lo32: + case VE::fixup_ve_pc_lo32: + case VE::fixup_ve_got_lo32: + case VE::fixup_ve_gotoff_lo32: + case VE::fixup_ve_plt_lo32: + case VE::fixup_ve_tls_gd_lo32: + case VE::fixup_ve_tpoff_lo32: + return Value & 0xffffffff; + } +} + +/// getFixupKindNumBytes - The number of bytes the fixup may change. +static unsigned getFixupKindNumBytes(unsigned Kind) { + switch (Kind) { + default: + return 8; + } +} + +namespace { +class VEAsmBackend : public MCAsmBackend { +protected: + const Target &TheTarget; + bool Is64Bit; + +public: + VEAsmBackend(const Target &T) + : MCAsmBackend(support::little), TheTarget(T), Is64Bit(true) {} + + unsigned getNumFixupKinds() const override { return VE::NumTargetFixupKinds; } + + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { + const static MCFixupKindInfo InfosLE[VE::NumTargetFixupKinds] = { + // name offset bits flags + {"fixup_ve_hi32", 0, 32, 0}, + {"fixup_ve_lo32", 0, 32, 0}, + {"fixup_ve_pc_hi32", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_ve_pc_lo32", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_ve_got_hi32", 0, 32, 0}, + {"fixup_ve_got_lo32", 0, 32, 0}, + {"fixup_ve_gotoff_hi32", 0, 32, 0}, + {"fixup_ve_gotoff_lo32", 0, 32, 0}, + {"fixup_ve_plt_hi32", 0, 32, 0}, + {"fixup_ve_plt_lo32", 0, 32, 0}, + {"fixup_ve_tls_gd_hi32", 0, 32, 0}, + {"fixup_ve_tls_gd_lo32", 0, 32, 0}, + {"fixup_ve_tpoff_hi32", 0, 32, 0}, + {"fixup_ve_tpoff_lo32", 0, 32, 0}, + }; + + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return InfosLE[Kind - FirstTargetFixupKind]; + } + + bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target) override { + switch ((VE::Fixups)Fixup.getKind()) { + default: + return false; + case VE::fixup_ve_tls_gd_hi32: + case VE::fixup_ve_tls_gd_lo32: + case VE::fixup_ve_tpoff_hi32: + case VE::fixup_ve_tpoff_lo32: + return true; + } + } + + bool mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const override { + // FIXME. + return false; + } + + /// fixupNeedsRelaxation - Target specific predicate for whether a given + /// fixup requires the associated instruction to be relaxed. + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const override { + // FIXME. + llvm_unreachable("fixupNeedsRelaxation() unimplemented"); + return false; + } + void relaxInstruction(MCInst &Inst, + const MCSubtargetInfo &STI) const override { + // FIXME. + llvm_unreachable("relaxInstruction() unimplemented"); + } + + bool writeNopData(raw_ostream &OS, uint64_t Count) const override { + if ((Count % 8) != 0) + return false; + + for (uint64_t i = 0; i < Count; i += 8) + support::endian::write(OS, 0x7900000000000000ULL, + support::little); + + return true; + } +}; + +class ELFVEAsmBackend : public VEAsmBackend { + Triple::OSType OSType; + +public: + ELFVEAsmBackend(const Target &T, Triple::OSType OSType) + : VEAsmBackend(T), OSType(OSType) {} + + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsResolved, + const MCSubtargetInfo *STI) const override { + + Value = adjustFixupValue(Fixup.getKind(), Value); + if (!Value) + return; // Doesn't change encoding. + + MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); + + // Shift the value into position. + Value <<= Info.TargetOffset; + + unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind()); + unsigned Offset = Fixup.getOffset(); + assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); + // For each byte of the fragment that the fixup touches, mask in the bits + // from the fixup value. The Value has been "split up" into the + // appropriate bitfields above. + for (unsigned i = 0; i != NumBytes; ++i) { + unsigned Idx = Endian == support::little ? i : (NumBytes - 1) - i; + Data[Offset + Idx] |= static_cast((Value >> (i * 8)) & 0xff); + } + } + + std::unique_ptr + createObjectTargetWriter() const override { + uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(OSType); + return createVEELFObjectWriter(Is64Bit, OSABI); + } +}; + +} // end anonymous namespace + +MCAsmBackend *llvm::createVEAsmBackend(const Target &T, + const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options) { + return new ELFVEAsmBackend(T, STI.getTargetTriple().getOS()); +} diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/VE/MCTargetDesc/VEELFObjectWriter.cpp @@ -0,0 +1,55 @@ +//===-- VEELFObjectWriter.cpp - VE ELF Writer -----------------------------===// +// +// 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 "VEFixupKinds.h" +#include "VEMCTargetDesc.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +namespace { +class VEELFObjectWriter : public MCELFObjectTargetWriter { +public: + VEELFObjectWriter(bool Is64Bit, uint8_t OSABI) + : MCELFObjectTargetWriter(Is64Bit, OSABI, ELF::EM_VE, + /*HasRelocationAddend*/ true) {} + + ~VEELFObjectWriter() override {} + +protected: + unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const override; + + bool needsRelocateWithSymbol(const MCSymbol &Sym, + unsigned Type) const override; +}; +} // namespace + +unsigned VEELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + + return ELF::R_VE_NONE; +} + +bool VEELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym, + unsigned Type) const { + switch (Type) { + default: + return false; + } +} + +std::unique_ptr +llvm::createVEELFObjectWriter(bool Is64Bit, uint8_t OSABI) { + return std::make_unique(Is64Bit, OSABI); +} diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEMCCodeEmitter.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEMCCodeEmitter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/VE/MCTargetDesc/VEMCCodeEmitter.cpp @@ -0,0 +1,122 @@ +//===-- VEMCCodeEmitter.cpp - Convert VE code to machine code -------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements the VEMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/VEFixupKinds.h" +#include "VE.h" +#include "VEMCExpr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include +#include + +using namespace llvm; + +#define DEBUG_TYPE "mccodeemitter" + +STATISTIC(MCNumEmitted, "Number of MC instructions emitted"); + +namespace { + +class VEMCCodeEmitter : public MCCodeEmitter { + const MCInstrInfo &MCII; + MCContext &Ctx; + +public: + VEMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx) + : MCII(mcii), Ctx(ctx) {} + VEMCCodeEmitter(const VEMCCodeEmitter &) = delete; + VEMCCodeEmitter &operator=(const VEMCCodeEmitter &) = delete; + ~VEMCCodeEmitter() override = default; + + void encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const override; + + // getBinaryCodeForInstr - TableGen'erated function for getting the + // binary encoding for an instruction. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + /// getMachineOpValue - Return binary encoding of operand. If the machine + /// operand requires relocation, record the relocation and return zero. + unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + +private: + FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const; + void + verifyInstructionPredicates(const MCInst &MI, + const FeatureBitset &AvailableFeatures) const; +}; + +} // end anonymous namespace + +void VEMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + verifyInstructionPredicates(MI, + computeAvailableFeatures(STI.getFeatureBits())); + + uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); + support::endian::write(OS, Bits, support::little); + + ++MCNumEmitted; // Keep track of the # of mi's emitted. +} + +unsigned VEMCCodeEmitter::getMachineOpValue(const MCInst &MI, + const MCOperand &MO, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + if (MO.isReg()) + return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); + + if (MO.isImm()) + return MO.getImm(); + + assert(MO.isExpr()); + const MCExpr *Expr = MO.getExpr(); + if (const VEMCExpr *SExpr = dyn_cast(Expr)) { + MCFixupKind Kind = (MCFixupKind)SExpr->getFixupKind(); + Fixups.push_back(MCFixup::create(0, Expr, Kind)); + return 0; + } + + int64_t Res; + if (Expr->evaluateAsAbsolute(Res)) + return Res; + + llvm_unreachable("Unhandled expression!"); + return 0; +} + +#define ENABLE_INSTR_PREDICATE_VERIFIER +#include "VEGenMCCodeEmitter.inc" + +MCCodeEmitter *llvm::createVEMCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + MCContext &Ctx) { + return new VEMCCodeEmitter(MCII, Ctx); +} diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEMCTargetDesc.h b/llvm/lib/Target/VE/MCTargetDesc/VEMCTargetDesc.h --- a/llvm/lib/Target/VE/MCTargetDesc/VEMCTargetDesc.h +++ b/llvm/lib/Target/VE/MCTargetDesc/VEMCTargetDesc.h @@ -22,7 +22,7 @@ class MCCodeEmitter; class MCContext; class MCInstrInfo; -class MCObjectWriter; +class MCObjectTargetWriter; class MCRegisterInfo; class MCSubtargetInfo; class MCTargetOptions; @@ -31,6 +31,14 @@ class StringRef; class raw_pwrite_stream; class raw_ostream; + +MCCodeEmitter *createVEMCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, MCContext &Ctx); +MCAsmBackend *createVEAsmBackend(const Target &T, const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options); +std::unique_ptr createVEELFObjectWriter(bool Is64Bit, + uint8_t OSABI); } // namespace llvm // Defines symbolic names for VE registers. This defines a mapping from diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEMCTargetDesc.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEMCTargetDesc.cpp --- a/llvm/lib/Target/VE/MCTargetDesc/VEMCTargetDesc.cpp +++ b/llvm/lib/Target/VE/MCTargetDesc/VEMCTargetDesc.cpp @@ -94,6 +94,12 @@ // Register the MC subtarget info. TargetRegistry::RegisterMCSubtargetInfo(*T, createVEMCSubtargetInfo); + // Register the MC Code Emitter. + TargetRegistry::RegisterMCCodeEmitter(*T, createVEMCCodeEmitter); + + // Register the asm backend. + TargetRegistry::RegisterMCAsmBackend(*T, createVEAsmBackend); + // Register the object target streamer. TargetRegistry::RegisterObjectTargetStreamer(*T, createObjectTargetStreamer); diff --git a/llvm/lib/Target/VE/VE.td b/llvm/lib/Target/VE/VE.td --- a/llvm/lib/Target/VE/VE.td +++ b/llvm/lib/Target/VE/VE.td @@ -29,6 +29,13 @@ def VEInstrInfo : InstrInfo; +def VEAsmParser : AsmParser { + // Use both VE register name matcher to accept "S0~S63" register names + // and default register matcher to accept other registeres. + let AllowDuplicateRegisterNames = 1; + let ShouldEmitMatchRegisterAltName = 1; +} + //===----------------------------------------------------------------------===// // VE processors supported. //===----------------------------------------------------------------------===// @@ -51,6 +58,7 @@ def VE : Target { // Pull in Instruction Info: let InstructionSet = VEInstrInfo; + let AssemblyParsers = [VEAsmParser]; let AssemblyWriters = [VEAsmWriter]; let AllowRegisterRenaming = 1; } diff --git a/llvm/lib/Target/VE/VEInstrFormats.td b/llvm/lib/Target/VE/VEInstrFormats.td --- a/llvm/lib/Target/VE/VEInstrFormats.td +++ b/llvm/lib/Target/VE/VEInstrFormats.td @@ -6,6 +6,20 @@ // //===----------------------------------------------------------------------===// +// SX-Aurora uses little bit endian in 64 bits data. However, x86 uses +// little endian in each 8 bits data. Therefore, we need to tranlate +// the address of each bitfield described in ISA documentation like below. +// +// ISA | InstrFormats.td +// --------------------------- +// 0-7 => 63-56 +// 8 => 55 +// 32-63 => 31-0 + +//===----------------------------------------------------------------------===// +// Instruction Format +//===----------------------------------------------------------------------===// + class InstVE pattern> : Instruction { field bits<64> Inst; @@ -14,7 +28,7 @@ let Size = 8; bits<8> op; - let Inst{0-7} = op; + let Inst{63-56} = op; dag OutOperandList = outs; dag InOperandList = ins; @@ -25,50 +39,114 @@ field bits<64> SoftFail = 0; } -class RMopVal, dag outs, dag ins, string asmstr, list pattern=[]> +//----------------------------------------------------------------------------- +// Section 5.1 RM Type +// +// RM type has sx, sy, sz, and imm32. +// The effective address is generated by sz + sy + imm32. +//----------------------------------------------------------------------------- + +class RMopVal, dag outs, dag ins, string asmstr, list pattern = []> : InstVE { bits<1> cx = 0; bits<7> sx; - bits<1> cy = 0; + bits<1> cy = 1; + bits<7> sz; // defines sz prior to sy to assign from sz + bits<7> sy; + bits<1> cz = 1; + bits<32> imm32; + let op = opVal; + let Inst{55} = cx; + let Inst{54-48} = sx; + let Inst{47} = cy; + let Inst{46-40} = sy; + let Inst{39} = cz; + let Inst{38-32} = sz; + let Inst{31-0} = imm32; +} + +//----------------------------------------------------------------------------- +// Section 5.2 RRM Type +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Section 5.3 CF Type +// +// CF type is used for control flow. +//----------------------------------------------------------------------------- + +class CFopVal, dag outs, dag ins, string asmstr, list pattern = []> + : InstVE { + bits<1> cx = 0; + bits<1> cx2 = 0; + bits<2> bpf = 0; + bits<4> cf; + bits<1> cy = 1; bits<7> sy; - bits<1> cz = 0; + bits<1> cz = 1; bits<7> sz; - bits<32> imm32 = 0; + bits<32> imm32; let op = opVal; - let Inst{15} = cx; - let Inst{14-8} = sx; - let Inst{23} = cy; - let Inst{22-16} = sy; - let Inst{31} = cz; - let Inst{30-24} = sz; - let Inst{63-32} = imm32; + let Inst{55} = cx; + let Inst{54} = cx2; + let Inst{53-52} = bpf; + let Inst{51-48} = cf; + let Inst{47} = cy; + let Inst{46-40} = sy; + let Inst{39} = cz; + let Inst{38-32} = sz; + let Inst{31-0} = imm32; } -class RRopVal, dag outs, dag ins, string asmstr, list pattern=[]> - : RM { +//----------------------------------------------------------------------------- +// Section 5.4 RR Type +// +// RR type is for generic arithmetic instructions. +//----------------------------------------------------------------------------- + +class RRopVal, dag outs, dag ins, string asmstr, list pattern = []> + : InstVE { + bits<1> cx = 0; + bits<7> sx; + bits<1> cy = 1; + bits<7> sy; + bits<1> cz = 1; + bits<7> sz; // m field places at the top sz field + bits<8> vx = 0; + bits<8> vz = 0; bits<1> cw = 0; bits<1> cw2 = 0; bits<4> cfw = 0; - let imm32{0-23} = 0; - let imm32{24} = cw; - let imm32{25} = cw2; - let imm32{26-27} = 0; - let imm32{28-31} = cfw; + let op = opVal; + let Inst{55} = cx; + let Inst{54-48} = sx; + let Inst{47} = cy; + let Inst{46-40} = sy; + let Inst{39} = cz; + let Inst{38-32} = sz; + let Inst{31-24} = vx; + let Inst{23-16} = 0; + let Inst{15-8} = vz; + let Inst{7} = cw; + let Inst{6} = cw2; + let Inst{5-4} = 0; + let Inst{3-0} = cfw; } -class CFopVal, dag outs, dag ins, string asmstr, list pattern=[]> - : RM { - bits<1> cx2; - bits<2> bpf; - bits<4> cf; - let cx = 0; - let sx{6} = cx2; - let sx{5-4} = bpf; - let sx{3-0} = cf; -} +//----------------------------------------------------------------------------- +// Section 5.5 RW Type +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Section 5.6 RVM Type +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Section 5.7 RV Type +//----------------------------------------------------------------------------- // Pseudo instructions. -class Pseudo pattern=[]> +class Pseudo pattern = []> : InstVE { let isCodeGenOnly = 1; let isPseudo = 1; diff --git a/llvm/lib/Target/VE/VEInstrInfo.td b/llvm/lib/Target/VE/VEInstrInfo.td --- a/llvm/lib/Target/VE/VEInstrInfo.td +++ b/llvm/lib/Target/VE/VEInstrInfo.td @@ -175,20 +175,6 @@ }]>; // Addressing modes. -def ADDRri : ComplexPattern; - -def MEMri : Operand { - let PrintMethod = "printMemASOperandASX"; - let MIOperandInfo = (ops ptr_rc, i64imm); -} - -// AS format of memory address -def MEMASri : Operand { - let PrintMethod = "printMemASOperand"; - let MIOperandInfo = (ops ptr_rc, i64imm); -} - -// Addressing modes. // SX-Aurora has following fields. // sz: register or 0 // sy: register or immediate (-64 to 63) @@ -217,6 +203,8 @@ def ADDRrii : ComplexPattern; def ADDRzri : ComplexPattern; def ADDRzii : ComplexPattern; +// AS format: +def ADDRri : ComplexPattern; // // ASX assembly instrcution format: def VEMEMrriAsmOperand : AsmOperandClass { @@ -255,14 +243,28 @@ let MIOperandInfo = (ops i32imm /* = 0 */, i32imm, i32imm); let ParserMatchClass = VEMEMziiAsmOperand; } +// AS assembly instrcution format: +def VEMEMriAsmOperand : AsmOperandClass { + let Name = "MEMri"; + let ParserMethod = "parseMEMAsOperand"; +} +// AS generic assembly instruction format: +def MEMri : Operand { + let PrintMethod = "printMemASOperandASX"; + let MIOperandInfo = (ops ptr_rc, i32imm); + let ParserMatchClass = VEMEMriAsmOperand; +} +def MEMASri : Operand { + let PrintMethod = "printMemASOperand"; + let MIOperandInfo = (ops ptr_rc, i32imm); + let ParserMatchClass = VEMEMriAsmOperand; +} // Branch targets have OtherVT type. def brtarget32 : Operand { - let EncoderMethod = "getBranchTarget32OpValue"; } def calltarget : Operand { - let EncoderMethod = "getCallTargetOpValue"; let DecoderMethod = "DecodeCall"; } diff --git a/llvm/test/MC/VE/LEA.s b/llvm/test/MC/VE/LEA.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/VE/LEA.s @@ -0,0 +1,29 @@ +# RUN: llvm-mc -triple ve-unknown-unknown --show-encoding %s | FileCheck %s + +# CHECK: lea %s11, 23 +# CHECK: encoding: [0x17,0x00,0x00,0x00,0x00,0x00,0x0b,0x06] +lea %s11, 23 + +# CHECK: lea %s63, 324(, %s11) +# CHECK: encoding: [0x44,0x01,0x00,0x00,0x8b,0x00,0x3f,0x06] +lea %s63, 324(,%s11) + +# CHECK: lea %s11, 324(%s10) +# CHECK: encoding: [0x44,0x01,0x00,0x00,0x00,0x8a,0x0b,0x06] +lea %s11, 324(%s10 ) + +# CHECK: lea %s11, 324(%s13, %s11) +# CHECK: encoding: [0x44,0x01,0x00,0x00,0x8b,0x8d,0x0b,0x06] +lea %s11, 324 (%s13,%s11) + +# CHECK: lea %s11, (%s10) +# CHECK: encoding: [0x00,0x00,0x00,0x00,0x00,0x8a,0x0b,0x06] +lea %s11, (%s10) + +# CHECK: lea %s11, (, %s12) +# CHECK: encoding: [0x00,0x00,0x00,0x00,0x8c,0x00,0x0b,0x06] +lea %s11, (,%s12) + +# CHECK: lea.sl %s11, -1(%s13, %s11) +# CHECK: encoding: [0xff,0xff,0xff,0xff,0x8b,0x8d,0x8b,0x06] +lea.sl %s11, -1(%s13, %s11) diff --git a/llvm/test/MC/VE/lit.local.cfg b/llvm/test/MC/VE/lit.local.cfg new file mode 100644 --- /dev/null +++ b/llvm/test/MC/VE/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'VE' in config.root.targets: + config.unsupported = True