diff options
Diffstat (limited to 'contrib/llvm/lib/Target/MBlaze')
55 files changed, 9965 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/MBlaze/AsmParser/MBlazeAsmLexer.cpp b/contrib/llvm/lib/Target/MBlaze/AsmParser/MBlazeAsmLexer.cpp new file mode 100644 index 0000000..59a1ed9 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/AsmParser/MBlazeAsmLexer.cpp @@ -0,0 +1,115 @@ +//===-- MBlazeAsmLexer.cpp - Tokenize MBlaze assembly to AsmTokens --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MBlazeBaseInfo.h" + +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCTargetAsmLexer.h" + +#include "llvm/Support/TargetRegistry.h" + +#include <string> +#include <map> + +using namespace llvm; + +namespace { + + class MBlazeBaseAsmLexer : public MCTargetAsmLexer { + const MCAsmInfo &AsmInfo; + + const AsmToken &lexDefinite() { + return getLexer()->Lex(); + } + + AsmToken LexTokenUAL(); + protected: + typedef std::map <std::string, unsigned> rmap_ty; + + rmap_ty RegisterMap; + + void InitRegisterMap(const MCRegisterInfo *info) { + unsigned numRegs = info->getNumRegs(); + + for (unsigned i = 0; i < numRegs; ++i) { + const char *regName = info->getName(i); + if (regName) + RegisterMap[regName] = i; + } + } + + unsigned MatchRegisterName(StringRef Name) { + rmap_ty::iterator iter = RegisterMap.find(Name.str()); + if (iter != RegisterMap.end()) + return iter->second; + else + return 0; + } + + AsmToken LexToken() { + if (!Lexer) { + SetError(SMLoc(), "No MCAsmLexer installed"); + return AsmToken(AsmToken::Error, "", 0); + } + + switch (AsmInfo.getAssemblerDialect()) { + default: + SetError(SMLoc(), "Unhandled dialect"); + return AsmToken(AsmToken::Error, "", 0); + case 0: + return LexTokenUAL(); + } + } + public: + MBlazeBaseAsmLexer(const Target &T, const MCAsmInfo &MAI) + : MCTargetAsmLexer(T), AsmInfo(MAI) { + } + }; + + class MBlazeAsmLexer : public MBlazeBaseAsmLexer { + public: + MBlazeAsmLexer(const Target &T, const MCRegisterInfo &MRI, + const MCAsmInfo &MAI) + : MBlazeBaseAsmLexer(T, MAI) { + InitRegisterMap(&MRI); + } + }; +} + +AsmToken MBlazeBaseAsmLexer::LexTokenUAL() { + const AsmToken &lexedToken = lexDefinite(); + + switch (lexedToken.getKind()) { + default: + return AsmToken(lexedToken); + case AsmToken::Error: + SetError(Lexer->getErrLoc(), Lexer->getErr()); + return AsmToken(lexedToken); + case AsmToken::Identifier: + { + unsigned regID = MatchRegisterName(lexedToken.getString().lower()); + + if (regID) { + return AsmToken(AsmToken::Register, + lexedToken.getString(), + static_cast<int64_t>(regID)); + } else { + return AsmToken(lexedToken); + } + } + } +} + +extern "C" void LLVMInitializeMBlazeAsmLexer() { + RegisterMCAsmLexer<MBlazeAsmLexer> X(TheMBlazeTarget); +} + diff --git a/contrib/llvm/lib/Target/MBlaze/AsmParser/MBlazeAsmParser.cpp b/contrib/llvm/lib/Target/MBlaze/AsmParser/MBlazeAsmParser.cpp new file mode 100644 index 0000000..38fb0e8 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/AsmParser/MBlazeAsmParser.cpp @@ -0,0 +1,562 @@ +//===-- MBlazeAsmParser.cpp - Parse MBlaze asm 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/MBlazeBaseInfo.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Twine.h" +using namespace llvm; + +namespace { +struct MBlazeOperand; + +class MBlazeAsmParser : public MCTargetAsmParser { + MCAsmParser &Parser; + + MCAsmParser &getParser() const { return Parser; } + MCAsmLexer &getLexer() const { return Parser.getLexer(); } + + void Warning(SMLoc L, const Twine &Msg) { Parser.Warning(L, Msg); } + bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); } + + MBlazeOperand *ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands); + MBlazeOperand *ParseRegister(unsigned &RegNo); + MBlazeOperand *ParseImmediate(); + MBlazeOperand *ParseFsl(); + MBlazeOperand* ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands); + + virtual bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc); + + bool ParseDirectiveWord(unsigned Size, SMLoc L); + + bool MatchAndEmitInstruction(SMLoc IDLoc, + SmallVectorImpl<MCParsedAsmOperand*> &Operands, + MCStreamer &Out); + + /// @name Auto-generated Match Functions + /// { + +#define GET_ASSEMBLER_HEADER +#include "MBlazeGenAsmMatcher.inc" + + /// } + + +public: + MBlazeAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser) + : MCTargetAsmParser(), Parser(_Parser) {} + + virtual bool ParseInstruction(StringRef Name, SMLoc NameLoc, + SmallVectorImpl<MCParsedAsmOperand*> &Operands); + + virtual bool ParseDirective(AsmToken DirectiveID); +}; + +/// MBlazeOperand - Instances of this class represent a parsed MBlaze machine +/// instruction. +struct MBlazeOperand : public MCParsedAsmOperand { + enum KindTy { + Token, + Immediate, + Register, + Memory, + Fsl + } Kind; + + SMLoc StartLoc, EndLoc; + + union { + struct { + const char *Data; + unsigned Length; + } Tok; + + struct { + unsigned RegNum; + } Reg; + + struct { + const MCExpr *Val; + } Imm; + + struct { + unsigned Base; + unsigned OffReg; + const MCExpr *Off; + } Mem; + + struct { + const MCExpr *Val; + } FslImm; + }; + + MBlazeOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} +public: + MBlazeOperand(const MBlazeOperand &o) : MCParsedAsmOperand() { + Kind = o.Kind; + StartLoc = o.StartLoc; + EndLoc = o.EndLoc; + switch (Kind) { + case Register: + Reg = o.Reg; + break; + case Immediate: + Imm = o.Imm; + break; + case Token: + Tok = o.Tok; + break; + case Memory: + Mem = o.Mem; + break; + case Fsl: + FslImm = o.FslImm; + break; + } + } + + /// getStartLoc - Get the location of the first token of this operand. + SMLoc getStartLoc() const { return StartLoc; } + + /// getEndLoc - Get the location of the last token of this operand. + SMLoc getEndLoc() const { return EndLoc; } + + unsigned getReg() const { + assert(Kind == Register && "Invalid access!"); + return Reg.RegNum; + } + + const MCExpr *getImm() const { + assert(Kind == Immediate && "Invalid access!"); + return Imm.Val; + } + + const MCExpr *getFslImm() const { + assert(Kind == Fsl && "Invalid access!"); + return FslImm.Val; + } + + unsigned getMemBase() const { + assert(Kind == Memory && "Invalid access!"); + return Mem.Base; + } + + const MCExpr* getMemOff() const { + assert(Kind == Memory && "Invalid access!"); + return Mem.Off; + } + + unsigned getMemOffReg() const { + assert(Kind == Memory && "Invalid access!"); + return Mem.OffReg; + } + + bool isToken() const { return Kind == Token; } + bool isImm() const { return Kind == Immediate; } + bool isMem() const { return Kind == Memory; } + bool isFsl() const { return Kind == Fsl; } + bool isReg() const { return Kind == Register; } + + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + // Add as immediates when possible. Null MCExpr = 0. + if (Expr == 0) + Inst.addOperand(MCOperand::CreateImm(0)); + else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr)) + Inst.addOperand(MCOperand::CreateImm(CE->getValue())); + else + Inst.addOperand(MCOperand::CreateExpr(Expr)); + } + + void addRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getReg())); + } + + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + + void addFslOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getFslImm()); + } + + void addMemOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::CreateReg(getMemBase())); + + unsigned RegOff = getMemOffReg(); + if (RegOff) + Inst.addOperand(MCOperand::CreateReg(RegOff)); + else + addExpr(Inst, getMemOff()); + } + + StringRef getToken() const { + assert(Kind == Token && "Invalid access!"); + return StringRef(Tok.Data, Tok.Length); + } + + virtual void print(raw_ostream &OS) const; + + static MBlazeOperand *CreateToken(StringRef Str, SMLoc S) { + MBlazeOperand *Op = new MBlazeOperand(Token); + Op->Tok.Data = Str.data(); + Op->Tok.Length = Str.size(); + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static MBlazeOperand *CreateReg(unsigned RegNum, SMLoc S, SMLoc E) { + MBlazeOperand *Op = new MBlazeOperand(Register); + Op->Reg.RegNum = RegNum; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static MBlazeOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) { + MBlazeOperand *Op = new MBlazeOperand(Immediate); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static MBlazeOperand *CreateFslImm(const MCExpr *Val, SMLoc S, SMLoc E) { + MBlazeOperand *Op = new MBlazeOperand(Fsl); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static MBlazeOperand *CreateMem(unsigned Base, const MCExpr *Off, SMLoc S, + SMLoc E) { + MBlazeOperand *Op = new MBlazeOperand(Memory); + Op->Mem.Base = Base; + Op->Mem.Off = Off; + Op->Mem.OffReg = 0; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static MBlazeOperand *CreateMem(unsigned Base, unsigned Off, SMLoc S, + SMLoc E) { + MBlazeOperand *Op = new MBlazeOperand(Memory); + Op->Mem.Base = Base; + Op->Mem.OffReg = Off; + Op->Mem.Off = 0; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } +}; + +} // end anonymous namespace. + +void MBlazeOperand::print(raw_ostream &OS) const { + switch (Kind) { + case Immediate: + getImm()->print(OS); + break; + case Register: + OS << "<register R"; + OS << getMBlazeRegisterNumbering(getReg()) << ">"; + break; + case Token: + OS << "'" << getToken() << "'"; + break; + case Memory: { + OS << "<memory R"; + OS << getMBlazeRegisterNumbering(getMemBase()); + OS << ", "; + + unsigned RegOff = getMemOffReg(); + if (RegOff) + OS << "R" << getMBlazeRegisterNumbering(RegOff); + else + OS << getMemOff(); + OS << ">"; + } + break; + case Fsl: + getFslImm()->print(OS); + break; + } +} + +/// @name Auto-generated Match Functions +/// { + +static unsigned MatchRegisterName(StringRef Name); + +/// } +// +bool MBlazeAsmParser:: +MatchAndEmitInstruction(SMLoc IDLoc, + SmallVectorImpl<MCParsedAsmOperand*> &Operands, + MCStreamer &Out) { + MCInst Inst; + SMLoc ErrorLoc; + unsigned ErrorInfo; + + switch (MatchInstructionImpl(Operands, Inst, ErrorInfo)) { + default: break; + case Match_Success: + Out.EmitInstruction(Inst); + return false; + case Match_MissingFeature: + return Error(IDLoc, "instruction use requires an option to be enabled"); + case Match_MnemonicFail: + return Error(IDLoc, "unrecognized instruction mnemonic"); + case Match_ConversionFail: + return Error(IDLoc, "unable to convert operands to instruction"); + case Match_InvalidOperand: + ErrorLoc = IDLoc; + if (ErrorInfo != ~0U) { + if (ErrorInfo >= Operands.size()) + return Error(IDLoc, "too few operands for instruction"); + + ErrorLoc = ((MBlazeOperand*)Operands[ErrorInfo])->getStartLoc(); + if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; + } + + return Error(ErrorLoc, "invalid operand for instruction"); + } + + llvm_unreachable("Implement any new match types added!"); +} + +MBlazeOperand *MBlazeAsmParser:: +ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + if (Operands.size() != 4) + return 0; + + MBlazeOperand &Base = *(MBlazeOperand*)Operands[2]; + MBlazeOperand &Offset = *(MBlazeOperand*)Operands[3]; + + SMLoc S = Base.getStartLoc(); + SMLoc O = Offset.getStartLoc(); + SMLoc E = Offset.getEndLoc(); + + if (!Base.isReg()) { + Error(S, "base address must be a register"); + return 0; + } + + if (!Offset.isReg() && !Offset.isImm()) { + Error(O, "offset must be a register or immediate"); + return 0; + } + + MBlazeOperand *Op; + if (Offset.isReg()) + Op = MBlazeOperand::CreateMem(Base.getReg(), Offset.getReg(), S, E); + else + Op = MBlazeOperand::CreateMem(Base.getReg(), Offset.getImm(), S, E); + + delete Operands.pop_back_val(); + delete Operands.pop_back_val(); + Operands.push_back(Op); + + return Op; +} + +bool MBlazeAsmParser::ParseRegister(unsigned &RegNo, + SMLoc &StartLoc, SMLoc &EndLoc) { + return (ParseRegister(RegNo) == 0); +} + +MBlazeOperand *MBlazeAsmParser::ParseRegister(unsigned &RegNo) { + SMLoc S = Parser.getTok().getLoc(); + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + switch (getLexer().getKind()) { + default: return 0; + case AsmToken::Identifier: + RegNo = MatchRegisterName(getLexer().getTok().getIdentifier()); + if (RegNo == 0) + return 0; + + getLexer().Lex(); + return MBlazeOperand::CreateReg(RegNo, S, E); + } +} + +static unsigned MatchFslRegister(StringRef String) { + if (!String.startswith("rfsl")) + return -1; + + unsigned regNum; + if (String.substr(4).getAsInteger(10,regNum)) + return -1; + + return regNum; +} + +MBlazeOperand *MBlazeAsmParser::ParseFsl() { + SMLoc S = Parser.getTok().getLoc(); + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + switch (getLexer().getKind()) { + default: return 0; + case AsmToken::Identifier: + unsigned reg = MatchFslRegister(getLexer().getTok().getIdentifier()); + if (reg >= 16) + return 0; + + getLexer().Lex(); + const MCExpr *EVal = MCConstantExpr::Create(reg,getContext()); + return MBlazeOperand::CreateFslImm(EVal,S,E); + } +} + +MBlazeOperand *MBlazeAsmParser::ParseImmediate() { + SMLoc S = Parser.getTok().getLoc(); + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + const MCExpr *EVal; + switch (getLexer().getKind()) { + default: return 0; + case AsmToken::LParen: + case AsmToken::Plus: + case AsmToken::Minus: + case AsmToken::Integer: + case AsmToken::Identifier: + if (getParser().ParseExpression(EVal)) + return 0; + + return MBlazeOperand::CreateImm(EVal, S, E); + } +} + +MBlazeOperand *MBlazeAsmParser:: +ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + MBlazeOperand *Op; + + // Attempt to parse the next token as a register name + unsigned RegNo; + Op = ParseRegister(RegNo); + + // Attempt to parse the next token as an FSL immediate + if (!Op) + Op = ParseFsl(); + + // Attempt to parse the next token as an immediate + if (!Op) + Op = ParseImmediate(); + + // If the token could not be parsed then fail + if (!Op) { + Error(Parser.getTok().getLoc(), "unknown operand"); + return 0; + } + + // Push the parsed operand into the list of operands + Operands.push_back(Op); + return Op; +} + +/// Parse an mblaze instruction mnemonic followed by its operands. +bool MBlazeAsmParser:: +ParseInstruction(StringRef Name, SMLoc NameLoc, + SmallVectorImpl<MCParsedAsmOperand*> &Operands) { + // The first operands is the token for the instruction name + size_t dotLoc = Name.find('.'); + Operands.push_back(MBlazeOperand::CreateToken(Name.substr(0,dotLoc),NameLoc)); + if (dotLoc < Name.size()) + Operands.push_back(MBlazeOperand::CreateToken(Name.substr(dotLoc),NameLoc)); + + // If there are no more operands then finish + if (getLexer().is(AsmToken::EndOfStatement)) + return false; + + // Parse the first operand + if (!ParseOperand(Operands)) + return true; + + while (getLexer().isNot(AsmToken::EndOfStatement) && + getLexer().is(AsmToken::Comma)) { + // Consume the comma token + getLexer().Lex(); + + // Parse the next operand + if (!ParseOperand(Operands)) + return true; + } + + // If the instruction requires a memory operand then we need to + // replace the last two operands (base+offset) with a single + // memory operand. + if (Name.startswith("lw") || Name.startswith("sw") || + Name.startswith("lh") || Name.startswith("sh") || + Name.startswith("lb") || Name.startswith("sb")) + return (ParseMemory(Operands) == NULL); + + return false; +} + +/// ParseDirective parses the MBlaze specific directives +bool MBlazeAsmParser::ParseDirective(AsmToken DirectiveID) { + StringRef IDVal = DirectiveID.getIdentifier(); + if (IDVal == ".word") + return ParseDirectiveWord(2, DirectiveID.getLoc()); + return true; +} + +/// ParseDirectiveWord +/// ::= .word [ expression (, expression)* ] +bool MBlazeAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) { + if (getLexer().isNot(AsmToken::EndOfStatement)) { + for (;;) { + const MCExpr *Value; + if (getParser().ParseExpression(Value)) + return true; + + getParser().getStreamer().EmitValue(Value, Size, 0 /*addrspace*/); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + // FIXME: Improve diagnostic. + if (getLexer().isNot(AsmToken::Comma)) + return Error(L, "unexpected token in directive"); + Parser.Lex(); + } + } + + Parser.Lex(); + return false; +} + +extern "C" void LLVMInitializeMBlazeAsmLexer(); + +/// Force static initialization. +extern "C" void LLVMInitializeMBlazeAsmParser() { + RegisterMCAsmParser<MBlazeAsmParser> X(TheMBlazeTarget); + LLVMInitializeMBlazeAsmLexer(); +} + +#define GET_REGISTER_MATCHER +#define GET_MATCHER_IMPLEMENTATION +#include "MBlazeGenAsmMatcher.inc" diff --git a/contrib/llvm/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.cpp b/contrib/llvm/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.cpp new file mode 100644 index 0000000..6b958c8 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.cpp @@ -0,0 +1,726 @@ +//===-- MBlazeDisassembler.cpp - Disassembler for MicroBlaze -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is part of the MBlaze Disassembler. It contains code to translate +// the data produced by the decoder into MCInsts. +// +//===----------------------------------------------------------------------===// + +#include "MBlaze.h" +#include "MBlazeDisassembler.h" + +#include "llvm/MC/EDInstInfo.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" + +// #include "MBlazeGenDecoderTables.inc" +// #include "MBlazeGenRegisterNames.inc" +#include "MBlazeGenEDInfo.inc" + +namespace llvm { +extern const MCInstrDesc MBlazeInsts[]; +} + +using namespace llvm; + +const uint16_t UNSUPPORTED = -1; + +static const uint16_t mblazeBinary2Opcode[] = { + MBlaze::ADD, MBlaze::RSUB, MBlaze::ADDC, MBlaze::RSUBC, //00,01,02,03 + MBlaze::ADDK, MBlaze::RSUBK, MBlaze::ADDKC, MBlaze::RSUBKC, //04,05,06,07 + MBlaze::ADDI, MBlaze::RSUBI, MBlaze::ADDIC, MBlaze::RSUBIC, //08,09,0A,0B + MBlaze::ADDIK, MBlaze::RSUBIK, MBlaze::ADDIKC, MBlaze::RSUBIKC, //0C,0D,0E,0F + + MBlaze::MUL, MBlaze::BSRL, MBlaze::IDIV, MBlaze::GETD, //10,11,12,13 + UNSUPPORTED, UNSUPPORTED, MBlaze::FADD, UNSUPPORTED, //14,15,16,17 + MBlaze::MULI, MBlaze::BSRLI, UNSUPPORTED, MBlaze::GET, //18,19,1A,1B + UNSUPPORTED, UNSUPPORTED, UNSUPPORTED, UNSUPPORTED, //1C,1D,1E,1F + + MBlaze::OR, MBlaze::AND, MBlaze::XOR, MBlaze::ANDN, //20,21,22,23 + MBlaze::SEXT8, MBlaze::MFS, MBlaze::BR, MBlaze::BEQ, //24,25,26,27 + MBlaze::ORI, MBlaze::ANDI, MBlaze::XORI, MBlaze::ANDNI, //28,29,2A,2B + MBlaze::IMM, MBlaze::RTSD, MBlaze::BRI, MBlaze::BEQI, //2C,2D,2E,2F + + MBlaze::LBU, MBlaze::LHU, MBlaze::LW, UNSUPPORTED, //30,31,32,33 + MBlaze::SB, MBlaze::SH, MBlaze::SW, UNSUPPORTED, //34,35,36,37 + MBlaze::LBUI, MBlaze::LHUI, MBlaze::LWI, UNSUPPORTED, //38,39,3A,3B + MBlaze::SBI, MBlaze::SHI, MBlaze::SWI, UNSUPPORTED, //3C,3D,3E,3F +}; + +static unsigned getRD(uint32_t insn) { + if (!isMBlazeRegister((insn>>21)&0x1F)) + return UNSUPPORTED; + return getMBlazeRegisterFromNumbering((insn>>21)&0x1F); +} + +static unsigned getRA(uint32_t insn) { + if (!getMBlazeRegisterFromNumbering((insn>>16)&0x1F)) + return UNSUPPORTED; + return getMBlazeRegisterFromNumbering((insn>>16)&0x1F); +} + +static unsigned getRB(uint32_t insn) { + if (!getMBlazeRegisterFromNumbering((insn>>11)&0x1F)) + return UNSUPPORTED; + return getMBlazeRegisterFromNumbering((insn>>11)&0x1F); +} + +static int64_t getRS(uint32_t insn) { + if (!isSpecialMBlazeRegister(insn&0x3FFF)) + return UNSUPPORTED; + return getSpecialMBlazeRegisterFromNumbering(insn&0x3FFF); +} + +static int64_t getIMM(uint32_t insn) { + int16_t val = (insn & 0xFFFF); + return val; +} + +static int64_t getSHT(uint32_t insn) { + int16_t val = (insn & 0x1F); + return val; +} + +static unsigned getFLAGS(int32_t insn) { + return (insn & 0x7FF); +} + +static int64_t getFSL(uint32_t insn) { + int16_t val = (insn & 0xF); + return val; +} + +static unsigned decodeMUL(uint32_t insn) { + switch (getFLAGS(insn)) { + default: return UNSUPPORTED; + case 0: return MBlaze::MUL; + case 1: return MBlaze::MULH; + case 2: return MBlaze::MULHSU; + case 3: return MBlaze::MULHU; + } +} + +static unsigned decodeSEXT(uint32_t insn) { + switch (insn&0x7FF) { + default: return UNSUPPORTED; + case 0x60: return MBlaze::SEXT8; + case 0x68: return MBlaze::WIC; + case 0x64: return MBlaze::WDC; + case 0x66: return MBlaze::WDCC; + case 0x74: return MBlaze::WDCF; + case 0x61: return MBlaze::SEXT16; + case 0x41: return MBlaze::SRL; + case 0x21: return MBlaze::SRC; + case 0x01: return MBlaze::SRA; + case 0xE0: return MBlaze::CLZ; + } +} + +static unsigned decodeBEQ(uint32_t insn) { + switch ((insn>>21)&0x1F) { + default: return UNSUPPORTED; + case 0x00: return MBlaze::BEQ; + case 0x10: return MBlaze::BEQD; + case 0x05: return MBlaze::BGE; + case 0x15: return MBlaze::BGED; + case 0x04: return MBlaze::BGT; + case 0x14: return MBlaze::BGTD; + case 0x03: return MBlaze::BLE; + case 0x13: return MBlaze::BLED; + case 0x02: return MBlaze::BLT; + case 0x12: return MBlaze::BLTD; + case 0x01: return MBlaze::BNE; + case 0x11: return MBlaze::BNED; + } +} + +static unsigned decodeBEQI(uint32_t insn) { + switch ((insn>>21)&0x1F) { + default: return UNSUPPORTED; + case 0x00: return MBlaze::BEQI; + case 0x10: return MBlaze::BEQID; + case 0x05: return MBlaze::BGEI; + case 0x15: return MBlaze::BGEID; + case 0x04: return MBlaze::BGTI; + case 0x14: return MBlaze::BGTID; + case 0x03: return MBlaze::BLEI; + case 0x13: return MBlaze::BLEID; + case 0x02: return MBlaze::BLTI; + case 0x12: return MBlaze::BLTID; + case 0x01: return MBlaze::BNEI; + case 0x11: return MBlaze::BNEID; + } +} + +static unsigned decodeBR(uint32_t insn) { + switch ((insn>>16)&0x1F) { + default: return UNSUPPORTED; + case 0x00: return MBlaze::BR; + case 0x08: return MBlaze::BRA; + case 0x0C: return MBlaze::BRK; + case 0x10: return MBlaze::BRD; + case 0x14: return MBlaze::BRLD; + case 0x18: return MBlaze::BRAD; + case 0x1C: return MBlaze::BRALD; + } +} + +static unsigned decodeBRI(uint32_t insn) { + switch (insn&0x3FFFFFF) { + default: break; + case 0x0020004: return MBlaze::IDMEMBAR; + case 0x0220004: return MBlaze::DMEMBAR; + case 0x0420004: return MBlaze::IMEMBAR; + } + + switch ((insn>>16)&0x1F) { + default: return UNSUPPORTED; + case 0x00: return MBlaze::BRI; + case 0x08: return MBlaze::BRAI; + case 0x0C: return MBlaze::BRKI; + case 0x10: return MBlaze::BRID; + case 0x14: return MBlaze::BRLID; + case 0x18: return MBlaze::BRAID; + case 0x1C: return MBlaze::BRALID; + } +} + +static unsigned decodeBSRL(uint32_t insn) { + switch ((insn>>9)&0x3) { + default: return UNSUPPORTED; + case 0x2: return MBlaze::BSLL; + case 0x1: return MBlaze::BSRA; + case 0x0: return MBlaze::BSRL; + } +} + +static unsigned decodeBSRLI(uint32_t insn) { + switch ((insn>>9)&0x3) { + default: return UNSUPPORTED; + case 0x2: return MBlaze::BSLLI; + case 0x1: return MBlaze::BSRAI; + case 0x0: return MBlaze::BSRLI; + } +} + +static unsigned decodeRSUBK(uint32_t insn) { + switch (getFLAGS(insn)) { + default: return UNSUPPORTED; + case 0x0: return MBlaze::RSUBK; + case 0x1: return MBlaze::CMP; + case 0x3: return MBlaze::CMPU; + } +} + +static unsigned decodeFADD(uint32_t insn) { + switch (getFLAGS(insn)) { + default: return UNSUPPORTED; + case 0x000: return MBlaze::FADD; + case 0x080: return MBlaze::FRSUB; + case 0x100: return MBlaze::FMUL; + case 0x180: return MBlaze::FDIV; + case 0x200: return MBlaze::FCMP_UN; + case 0x210: return MBlaze::FCMP_LT; + case 0x220: return MBlaze::FCMP_EQ; + case 0x230: return MBlaze::FCMP_LE; + case 0x240: return MBlaze::FCMP_GT; + case 0x250: return MBlaze::FCMP_NE; + case 0x260: return MBlaze::FCMP_GE; + case 0x280: return MBlaze::FLT; + case 0x300: return MBlaze::FINT; + case 0x380: return MBlaze::FSQRT; + } +} + +static unsigned decodeGET(uint32_t insn) { + switch ((insn>>10)&0x3F) { + default: return UNSUPPORTED; + case 0x00: return MBlaze::GET; + case 0x01: return MBlaze::EGET; + case 0x02: return MBlaze::AGET; + case 0x03: return MBlaze::EAGET; + case 0x04: return MBlaze::TGET; + case 0x05: return MBlaze::TEGET; + case 0x06: return MBlaze::TAGET; + case 0x07: return MBlaze::TEAGET; + case 0x08: return MBlaze::CGET; + case 0x09: return MBlaze::ECGET; + case 0x0A: return MBlaze::CAGET; + case 0x0B: return MBlaze::ECAGET; + case 0x0C: return MBlaze::TCGET; + case 0x0D: return MBlaze::TECGET; + case 0x0E: return MBlaze::TCAGET; + case 0x0F: return MBlaze::TECAGET; + case 0x10: return MBlaze::NGET; + case 0x11: return MBlaze::NEGET; + case 0x12: return MBlaze::NAGET; + case 0x13: return MBlaze::NEAGET; + case 0x14: return MBlaze::TNGET; + case 0x15: return MBlaze::TNEGET; + case 0x16: return MBlaze::TNAGET; + case 0x17: return MBlaze::TNEAGET; + case 0x18: return MBlaze::NCGET; + case 0x19: return MBlaze::NECGET; + case 0x1A: return MBlaze::NCAGET; + case 0x1B: return MBlaze::NECAGET; + case 0x1C: return MBlaze::TNCGET; + case 0x1D: return MBlaze::TNECGET; + case 0x1E: return MBlaze::TNCAGET; + case 0x1F: return MBlaze::TNECAGET; + case 0x20: return MBlaze::PUT; + case 0x22: return MBlaze::APUT; + case 0x24: return MBlaze::TPUT; + case 0x26: return MBlaze::TAPUT; + case 0x28: return MBlaze::CPUT; + case 0x2A: return MBlaze::CAPUT; + case 0x2C: return MBlaze::TCPUT; + case 0x2E: return MBlaze::TCAPUT; + case 0x30: return MBlaze::NPUT; + case 0x32: return MBlaze::NAPUT; + case 0x34: return MBlaze::TNPUT; + case 0x36: return MBlaze::TNAPUT; + case 0x38: return MBlaze::NCPUT; + case 0x3A: return MBlaze::NCAPUT; + case 0x3C: return MBlaze::TNCPUT; + case 0x3E: return MBlaze::TNCAPUT; + } +} + +static unsigned decodeGETD(uint32_t insn) { + switch ((insn>>5)&0x3F) { + default: return UNSUPPORTED; + case 0x00: return MBlaze::GETD; + case 0x01: return MBlaze::EGETD; + case 0x02: return MBlaze::AGETD; + case 0x03: return MBlaze::EAGETD; + case 0x04: return MBlaze::TGETD; + case 0x05: return MBlaze::TEGETD; + case 0x06: return MBlaze::TAGETD; + case 0x07: return MBlaze::TEAGETD; + case 0x08: return MBlaze::CGETD; + case 0x09: return MBlaze::ECGETD; + case 0x0A: return MBlaze::CAGETD; + case 0x0B: return MBlaze::ECAGETD; + case 0x0C: return MBlaze::TCGETD; + case 0x0D: return MBlaze::TECGETD; + case 0x0E: return MBlaze::TCAGETD; + case 0x0F: return MBlaze::TECAGETD; + case 0x10: return MBlaze::NGETD; + case 0x11: return MBlaze::NEGETD; + case 0x12: return MBlaze::NAGETD; + case 0x13: return MBlaze::NEAGETD; + case 0x14: return MBlaze::TNGETD; + case 0x15: return MBlaze::TNEGETD; + case 0x16: return MBlaze::TNAGETD; + case 0x17: return MBlaze::TNEAGETD; + case 0x18: return MBlaze::NCGETD; + case 0x19: return MBlaze::NECGETD; + case 0x1A: return MBlaze::NCAGETD; + case 0x1B: return MBlaze::NECAGETD; + case 0x1C: return MBlaze::TNCGETD; + case 0x1D: return MBlaze::TNECGETD; + case 0x1E: return MBlaze::TNCAGETD; + case 0x1F: return MBlaze::TNECAGETD; + case 0x20: return MBlaze::PUTD; + case 0x22: return MBlaze::APUTD; + case 0x24: return MBlaze::TPUTD; + case 0x26: return MBlaze::TAPUTD; + case 0x28: return MBlaze::CPUTD; + case 0x2A: return MBlaze::CAPUTD; + case 0x2C: return MBlaze::TCPUTD; + case 0x2E: return MBlaze::TCAPUTD; + case 0x30: return MBlaze::NPUTD; + case 0x32: return MBlaze::NAPUTD; + case 0x34: return MBlaze::TNPUTD; + case 0x36: return MBlaze::TNAPUTD; + case 0x38: return MBlaze::NCPUTD; + case 0x3A: return MBlaze::NCAPUTD; + case 0x3C: return MBlaze::TNCPUTD; + case 0x3E: return MBlaze::TNCAPUTD; + } +} + +static unsigned decodeIDIV(uint32_t insn) { + switch (insn&0x3) { + default: return UNSUPPORTED; + case 0x0: return MBlaze::IDIV; + case 0x2: return MBlaze::IDIVU; + } +} + +static unsigned decodeLBU(uint32_t insn) { + switch ((insn>>9)&0x1) { + default: return UNSUPPORTED; + case 0x0: return MBlaze::LBU; + case 0x1: return MBlaze::LBUR; + } +} + +static unsigned decodeLHU(uint32_t insn) { + switch ((insn>>9)&0x1) { + default: return UNSUPPORTED; + case 0x0: return MBlaze::LHU; + case 0x1: return MBlaze::LHUR; + } +} + +static unsigned decodeLW(uint32_t insn) { + switch ((insn>>9)&0x3) { + default: return UNSUPPORTED; + case 0x0: return MBlaze::LW; + case 0x1: return MBlaze::LWR; + case 0x2: return MBlaze::LWX; + } +} + +static unsigned decodeSB(uint32_t insn) { + switch ((insn>>9)&0x1) { + default: return UNSUPPORTED; + case 0x0: return MBlaze::SB; + case 0x1: return MBlaze::SBR; + } +} + +static unsigned decodeSH(uint32_t insn) { + switch ((insn>>9)&0x1) { + default: return UNSUPPORTED; + case 0x0: return MBlaze::SH; + case 0x1: return MBlaze::SHR; + } +} + +static unsigned decodeSW(uint32_t insn) { + switch ((insn>>9)&0x3) { + default: return UNSUPPORTED; + case 0x0: return MBlaze::SW; + case 0x1: return MBlaze::SWR; + case 0x2: return MBlaze::SWX; + } +} + +static unsigned decodeMFS(uint32_t insn) { + switch ((insn>>15)&0x1) { + default: return UNSUPPORTED; + case 0x0: + switch ((insn>>16)&0x1) { + default: return UNSUPPORTED; + case 0x0: return MBlaze::MSRSET; + case 0x1: return MBlaze::MSRCLR; + } + case 0x1: + switch ((insn>>14)&0x1) { + default: return UNSUPPORTED; + case 0x0: return MBlaze::MFS; + case 0x1: return MBlaze::MTS; + } + } +} + +static unsigned decodeOR(uint32_t insn) { + switch (getFLAGS(insn)) { + default: return UNSUPPORTED; + case 0x000: return MBlaze::OR; + case 0x400: return MBlaze::PCMPBF; + } +} + +static unsigned decodeXOR(uint32_t insn) { + switch (getFLAGS(insn)) { + default: return UNSUPPORTED; + case 0x000: return MBlaze::XOR; + case 0x400: return MBlaze::PCMPEQ; + } +} + +static unsigned decodeANDN(uint32_t insn) { + switch (getFLAGS(insn)) { + default: return UNSUPPORTED; + case 0x000: return MBlaze::ANDN; + case 0x400: return MBlaze::PCMPNE; + } +} + +static unsigned decodeRTSD(uint32_t insn) { + switch ((insn>>21)&0x1F) { + default: return UNSUPPORTED; + case 0x10: return MBlaze::RTSD; + case 0x11: return MBlaze::RTID; + case 0x12: return MBlaze::RTBD; + case 0x14: return MBlaze::RTED; + } +} + +static unsigned getOPCODE(uint32_t insn) { + unsigned opcode = mblazeBinary2Opcode[ (insn>>26)&0x3F ]; + switch (opcode) { + case MBlaze::MUL: return decodeMUL(insn); + case MBlaze::SEXT8: return decodeSEXT(insn); + case MBlaze::BEQ: return decodeBEQ(insn); + case MBlaze::BEQI: return decodeBEQI(insn); + case MBlaze::BR: return decodeBR(insn); + case MBlaze::BRI: return decodeBRI(insn); + case MBlaze::BSRL: return decodeBSRL(insn); + case MBlaze::BSRLI: return decodeBSRLI(insn); + case MBlaze::RSUBK: return decodeRSUBK(insn); + case MBlaze::FADD: return decodeFADD(insn); + case MBlaze::GET: return decodeGET(insn); + case MBlaze::GETD: return decodeGETD(insn); + case MBlaze::IDIV: return decodeIDIV(insn); + case MBlaze::LBU: return decodeLBU(insn); + case MBlaze::LHU: return decodeLHU(insn); + case MBlaze::LW: return decodeLW(insn); + case MBlaze::SB: return decodeSB(insn); + case MBlaze::SH: return decodeSH(insn); + case MBlaze::SW: return decodeSW(insn); + case MBlaze::MFS: return decodeMFS(insn); + case MBlaze::OR: return decodeOR(insn); + case MBlaze::XOR: return decodeXOR(insn); + case MBlaze::ANDN: return decodeANDN(insn); + case MBlaze::RTSD: return decodeRTSD(insn); + default: return opcode; + } +} + +const EDInstInfo *MBlazeDisassembler::getEDInfo() const { + return instInfoMBlaze; +} + +// +// Public interface for the disassembler +// + +MCDisassembler::DecodeStatus MBlazeDisassembler::getInstruction(MCInst &instr, + uint64_t &size, + const MemoryObject ®ion, + uint64_t address, + raw_ostream &vStream, + raw_ostream &cStream) const { + // The machine instruction. + uint32_t insn; + uint64_t read; + uint8_t bytes[4]; + + // By default we consume 1 byte on failure + size = 1; + + // We want to read exactly 4 bytes of data. + if (region.readBytes(address, 4, (uint8_t*)bytes, &read) == -1 || read < 4) + return Fail; + + // Encoded as a big-endian 32-bit word in the stream. + insn = (bytes[0]<<24) | (bytes[1]<<16) | (bytes[2]<< 8) | (bytes[3]<<0); + + // Get the MCInst opcode from the binary instruction and make sure + // that it is a valid instruction. + unsigned opcode = getOPCODE(insn); + if (opcode == UNSUPPORTED) + return Fail; + + instr.setOpcode(opcode); + + unsigned RD = getRD(insn); + unsigned RA = getRA(insn); + unsigned RB = getRB(insn); + unsigned RS = getRS(insn); + + uint64_t tsFlags = MBlazeInsts[opcode].TSFlags; + switch ((tsFlags & MBlazeII::FormMask)) { + default: + return Fail; + + case MBlazeII::FC: + break; + + case MBlazeII::FRRRR: + if (RD == UNSUPPORTED || RA == UNSUPPORTED || RB == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RD)); + instr.addOperand(MCOperand::CreateReg(RB)); + instr.addOperand(MCOperand::CreateReg(RA)); + break; + + case MBlazeII::FRRR: + if (RD == UNSUPPORTED || RA == UNSUPPORTED || RB == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RD)); + instr.addOperand(MCOperand::CreateReg(RA)); + instr.addOperand(MCOperand::CreateReg(RB)); + break; + + case MBlazeII::FRR: + if (RD == UNSUPPORTED || RA == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RD)); + instr.addOperand(MCOperand::CreateReg(RA)); + break; + + case MBlazeII::FRI: + switch (opcode) { + default: + return Fail; + case MBlaze::MFS: + if (RD == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RD)); + instr.addOperand(MCOperand::CreateImm(insn&0x3FFF)); + break; + case MBlaze::MTS: + if (RA == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateImm(insn&0x3FFF)); + instr.addOperand(MCOperand::CreateReg(RA)); + break; + case MBlaze::MSRSET: + case MBlaze::MSRCLR: + if (RD == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RD)); + instr.addOperand(MCOperand::CreateImm(insn&0x7FFF)); + break; + } + break; + + case MBlazeII::FRRI: + if (RD == UNSUPPORTED || RA == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RD)); + instr.addOperand(MCOperand::CreateReg(RA)); + switch (opcode) { + default: + instr.addOperand(MCOperand::CreateImm(getIMM(insn))); + break; + case MBlaze::BSRLI: + case MBlaze::BSRAI: + case MBlaze::BSLLI: + instr.addOperand(MCOperand::CreateImm(insn&0x1F)); + break; + } + break; + + case MBlazeII::FCRR: + if (RA == UNSUPPORTED || RB == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RA)); + instr.addOperand(MCOperand::CreateReg(RB)); + break; + + case MBlazeII::FCRI: + if (RA == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RA)); + instr.addOperand(MCOperand::CreateImm(getIMM(insn))); + break; + + case MBlazeII::FRCR: + if (RD == UNSUPPORTED || RB == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RD)); + instr.addOperand(MCOperand::CreateReg(RB)); + break; + + case MBlazeII::FRCI: + if (RD == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RD)); + instr.addOperand(MCOperand::CreateImm(getIMM(insn))); + break; + + case MBlazeII::FCCR: + if (RB == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RB)); + break; + + case MBlazeII::FCCI: + instr.addOperand(MCOperand::CreateImm(getIMM(insn))); + break; + + case MBlazeII::FRRCI: + if (RD == UNSUPPORTED || RA == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RD)); + instr.addOperand(MCOperand::CreateReg(RA)); + instr.addOperand(MCOperand::CreateImm(getSHT(insn))); + break; + + case MBlazeII::FRRC: + if (RD == UNSUPPORTED || RA == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RD)); + instr.addOperand(MCOperand::CreateReg(RA)); + break; + + case MBlazeII::FRCX: + if (RD == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RD)); + instr.addOperand(MCOperand::CreateImm(getFSL(insn))); + break; + + case MBlazeII::FRCS: + if (RD == UNSUPPORTED || RS == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RD)); + instr.addOperand(MCOperand::CreateReg(RS)); + break; + + case MBlazeII::FCRCS: + if (RS == UNSUPPORTED || RA == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RS)); + instr.addOperand(MCOperand::CreateReg(RA)); + break; + + case MBlazeII::FCRCX: + if (RA == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RA)); + instr.addOperand(MCOperand::CreateImm(getFSL(insn))); + break; + + case MBlazeII::FCX: + instr.addOperand(MCOperand::CreateImm(getFSL(insn))); + break; + + case MBlazeII::FCR: + if (RB == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RB)); + break; + + case MBlazeII::FRIR: + if (RD == UNSUPPORTED || RA == UNSUPPORTED) + return Fail; + instr.addOperand(MCOperand::CreateReg(RD)); + instr.addOperand(MCOperand::CreateImm(getIMM(insn))); + instr.addOperand(MCOperand::CreateReg(RA)); + break; + } + + // We always consume 4 bytes of data on success + size = 4; + + return Success; +} + +static MCDisassembler *createMBlazeDisassembler(const Target &T, + const MCSubtargetInfo &STI) { + return new MBlazeDisassembler(STI); +} + +extern "C" void LLVMInitializeMBlazeDisassembler() { + // Register the disassembler. + TargetRegistry::RegisterMCDisassembler(TheMBlazeTarget, + createMBlazeDisassembler); +} diff --git a/contrib/llvm/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.h b/contrib/llvm/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.h new file mode 100644 index 0000000..5c4ae3b --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.h @@ -0,0 +1,54 @@ +//===-- MBlazeDisassembler.h - Disassembler for MicroBlaze -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is part of the MBlaze Disassembler. It it the header for +// MBlazeDisassembler, a subclass of MCDisassembler. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZEDISASSEMBLER_H +#define MBLAZEDISASSEMBLER_H + +#include "llvm/MC/MCDisassembler.h" + +namespace llvm { + +class MCInst; +class MemoryObject; +class raw_ostream; + +struct EDInstInfo; + +/// MBlazeDisassembler - Disassembler for all MBlaze platforms. +class MBlazeDisassembler : public MCDisassembler { +public: + /// Constructor - Initializes the disassembler. + /// + MBlazeDisassembler(const MCSubtargetInfo &STI) : + MCDisassembler(STI) { + } + + ~MBlazeDisassembler() { + } + + /// getInstruction - See MCDisassembler. + MCDisassembler::DecodeStatus getInstruction(MCInst &instr, + uint64_t &size, + const MemoryObject ®ion, + uint64_t address, + raw_ostream &vStream, + raw_ostream &cStream) const; + + /// getEDInfo - See MCDisassembler. + const EDInstInfo *getEDInfo() const; +}; + +} // namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/InstPrinter/MBlazeInstPrinter.cpp b/contrib/llvm/lib/Target/MBlaze/InstPrinter/MBlazeInstPrinter.cpp new file mode 100644 index 0000000..a1f1dbc --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/InstPrinter/MBlazeInstPrinter.cpp @@ -0,0 +1,71 @@ +//===-- MBlazeInstPrinter.cpp - Convert MBlaze MCInst to assembly syntax --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an MBlaze MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "MBlaze.h" +#include "MBlazeInstPrinter.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +using namespace llvm; + + +// Include the auto-generated portion of the assembly writer. +#include "MBlazeGenAsmWriter.inc" + +void MBlazeInstPrinter::printInst(const MCInst *MI, raw_ostream &O, + StringRef Annot) { + printInstruction(MI, O); + printAnnotation(O, Annot); +} + +void MBlazeInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O, const char *Modifier) { + assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) { + O << getRegisterName(Op.getReg()); + } else if (Op.isImm()) { + O << (int32_t)Op.getImm(); + } else { + assert(Op.isExpr() && "unknown operand kind in printOperand"); + O << *Op.getExpr(); + } +} + +void MBlazeInstPrinter::printFSLImm(const MCInst *MI, int OpNo, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(OpNo); + if (MO.isImm()) + O << "rfsl" << MO.getImm(); + else + printOperand(MI, OpNo, O, NULL); +} + +void MBlazeInstPrinter::printUnsignedImm(const MCInst *MI, int OpNo, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(OpNo); + if (MO.isImm()) + O << (uint32_t)MO.getImm(); + else + printOperand(MI, OpNo, O, NULL); +} + +void MBlazeInstPrinter::printMemOperand(const MCInst *MI, int OpNo, + raw_ostream &O, const char *Modifier) { + printOperand(MI, OpNo, O, NULL); + O << ", "; + printOperand(MI, OpNo+1, O, NULL); +} diff --git a/contrib/llvm/lib/Target/MBlaze/InstPrinter/MBlazeInstPrinter.h b/contrib/llvm/lib/Target/MBlaze/InstPrinter/MBlazeInstPrinter.h new file mode 100644 index 0000000..51ba7c3 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/InstPrinter/MBlazeInstPrinter.h @@ -0,0 +1,43 @@ +//= MBlazeInstPrinter.h - Convert MBlaze MCInst to assembly syntax -*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints a MBlaze MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZEINSTPRINTER_H +#define MBLAZEINSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm { + class MCOperand; + + class MBlazeInstPrinter : public MCInstPrinter { + public: + MBlazeInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, + const MCRegisterInfo &MRI) + : MCInstPrinter(MAI, MII, MRI) {} + + virtual void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot); + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); + + void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, + const char *Modifier = 0); + void printFSLImm(const MCInst *MI, int OpNo, raw_ostream &O); + void printUnsignedImm(const MCInst *MI, int OpNo, raw_ostream &O); + void printMemOperand(const MCInst *MI, int OpNo,raw_ostream &O, + const char *Modifier = 0); + }; +} + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MBlaze.h b/contrib/llvm/lib/Target/MBlaze/MBlaze.h new file mode 100644 index 0000000..1399b85 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlaze.h @@ -0,0 +1,32 @@ +//===-- MBlaze.h - Top-level interface for MBlaze ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the entry points for global functions defined in +// the LLVM MBlaze back-end. +// +//===----------------------------------------------------------------------===// + +#ifndef TARGET_MBLAZE_H +#define TARGET_MBLAZE_H + +#include "MCTargetDesc/MBlazeBaseInfo.h" +#include "MCTargetDesc/MBlazeMCTargetDesc.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + class MBlazeTargetMachine; + class FunctionPass; + class MachineCodeEmitter; + + FunctionPass *createMBlazeISelDag(MBlazeTargetMachine &TM); + FunctionPass *createMBlazeDelaySlotFillerPass(MBlazeTargetMachine &TM); + +} // end namespace llvm; + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MBlaze.td b/contrib/llvm/lib/Target/MBlaze/MBlaze.td new file mode 100644 index 0000000..c288855 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlaze.td @@ -0,0 +1,73 @@ +//===-- MBlaze.td - Describe the MBlaze Target Machine -----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This is the top level entry point for the MBlaze target. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// Register File, Calling Conv, Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "MBlazeRegisterInfo.td" +include "MBlazeSchedule.td" +include "MBlazeIntrinsics.td" +include "MBlazeInstrInfo.td" +include "MBlazeCallingConv.td" + +def MBlazeInstrInfo : InstrInfo; + +//===----------------------------------------------------------------------===// +// Microblaze Subtarget features // +//===----------------------------------------------------------------------===// + +def FeatureBarrel : SubtargetFeature<"barrel", "HasBarrel", "true", + "Implements barrel shifter">; +def FeatureDiv : SubtargetFeature<"div", "HasDiv", "true", + "Implements hardware divider">; +def FeatureMul : SubtargetFeature<"mul", "HasMul", "true", + "Implements hardware multiplier">; +def FeaturePatCmp : SubtargetFeature<"patcmp", "HasPatCmp", "true", + "Implements pattern compare instruction">; +def FeatureFPU : SubtargetFeature<"fpu", "HasFPU", "true", + "Implements floating point unit">; +def FeatureMul64 : SubtargetFeature<"mul64", "HasMul64", "true", + "Implements multiplier with 64-bit result">; +def FeatureSqrt : SubtargetFeature<"sqrt", "HasSqrt", "true", + "Implements sqrt and floating point convert">; + +//===----------------------------------------------------------------------===// +// MBlaze processors supported. +//===----------------------------------------------------------------------===// + +def : Processor<"mblaze", NoItineraries, []>; +def : Processor<"mblaze3", MBlazePipe3Itineraries, []>; +def : Processor<"mblaze5", MBlazePipe5Itineraries, []>; + +//===----------------------------------------------------------------------===// +// Instruction Descriptions +//===----------------------------------------------------------------------===// + +def MBlazeAsmWriter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; + bit isMCAsmWriter = 1; +} + +//===----------------------------------------------------------------------===// +// Target Declaration +//===----------------------------------------------------------------------===// + +def MBlaze : Target { + let InstructionSet = MBlazeInstrInfo; + let AssemblyWriters = [MBlazeAsmWriter]; +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeAsmPrinter.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeAsmPrinter.cpp new file mode 100644 index 0000000..e9f340f --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeAsmPrinter.cpp @@ -0,0 +1,326 @@ +//===-- MBlazeAsmPrinter.cpp - MBlaze LLVM assembly writer ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to GAS-format MBlaze assembly language. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mblaze-asm-printer" + +#include "MBlaze.h" +#include "MBlazeSubtarget.h" +#include "MBlazeInstrInfo.h" +#include "MBlazeTargetMachine.h" +#include "MBlazeMachineFunction.h" +#include "MBlazeMCInstLower.h" +#include "InstPrinter/MBlazeInstPrinter.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include <cctype> + +using namespace llvm; + +namespace { + class MBlazeAsmPrinter : public AsmPrinter { + const MBlazeSubtarget *Subtarget; + public: + explicit MBlazeAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer) { + Subtarget = &TM.getSubtarget<MBlazeSubtarget>(); + } + + virtual const char *getPassName() const { + return "MBlaze Assembly Printer"; + } + + void printSavedRegsBitmask(); + void emitFrameDirective(); + virtual void EmitFunctionBodyStart(); + virtual void EmitFunctionBodyEnd(); + virtual void EmitFunctionEntryLabel(); + + virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) + const; + + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O); + void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); + void printUnsignedImm(const MachineInstr *MI, int opNum, raw_ostream &O); + void printFSLImm(const MachineInstr *MI, int opNum, raw_ostream &O); + void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O, + const char *Modifier = 0); + + void EmitInstruction(const MachineInstr *MI); + }; +} // end of anonymous namespace + +// #include "MBlazeGenAsmWriter.inc" + +//===----------------------------------------------------------------------===// +// +// MBlaze Asm Directives +// +// -- Frame directive "frame Stackpointer, Stacksize, RARegister" +// Describe the stack frame. +// +// -- Mask directives "mask bitmask, offset" +// Tells the assembler which registers are saved and where. +// bitmask - contain a little endian bitset indicating which registers are +// saved on function prologue (e.g. with a 0x80000000 mask, the +// assembler knows the register 31 (RA) is saved at prologue. +// offset - the position before stack pointer subtraction indicating where +// the first saved register on prologue is located. (e.g. with a +// +// Consider the following function prologue: +// +// .frame R19,48,R15 +// .mask 0xc0000000,-8 +// addiu R1, R1, -48 +// sw R15, 40(R1) +// sw R19, 36(R1) +// +// With a 0xc0000000 mask, the assembler knows the register 15 (R15) and +// 19 (R19) are saved at prologue. As the save order on prologue is from +// left to right, R15 is saved first. A -8 offset means that after the +// stack pointer subtration, the first register in the mask (R15) will be +// saved at address 48-8=40. +// +//===----------------------------------------------------------------------===// + +// Print a 32 bit hex number with all numbers. +static void printHex32(unsigned int Value, raw_ostream &O) { + O << "0x"; + for (int i = 7; i >= 0; i--) + O.write_hex((Value & (0xF << (i*4))) >> (i*4)); +} + +// Create a bitmask with all callee saved registers for CPU or Floating Point +// registers. For CPU registers consider RA, GP and FP for saving if necessary. +void MBlazeAsmPrinter::printSavedRegsBitmask() { + const TargetFrameLowering *TFI = TM.getFrameLowering(); + const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + + // CPU Saved Registers Bitmasks + unsigned int CPUBitmask = 0; + + // Set the CPU Bitmasks + const MachineFrameInfo *MFI = MF->getFrameInfo(); + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + unsigned Reg = CSI[i].getReg(); + unsigned RegNum = getMBlazeRegisterNumbering(Reg); + if (MBlaze::GPRRegClass.contains(Reg)) + CPUBitmask |= (1 << RegNum); + } + + // Return Address and Frame registers must also be set in CPUBitmask. + if (TFI->hasFP(*MF)) + CPUBitmask |= (1 << getMBlazeRegisterNumbering(RI.getFrameRegister(*MF))); + + if (MFI->adjustsStack()) + CPUBitmask |= (1 << getMBlazeRegisterNumbering(RI.getRARegister())); + + // Print CPUBitmask + OutStreamer.EmitRawText("\t.mask\t0x" + Twine::utohexstr(CPUBitmask)); +} + +/// Frame Directive +void MBlazeAsmPrinter::emitFrameDirective() { + if (!OutStreamer.hasRawTextSupport()) + return; + + const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + unsigned stkReg = RI.getFrameRegister(*MF); + unsigned retReg = RI.getRARegister(); + unsigned stkSze = MF->getFrameInfo()->getStackSize(); + + OutStreamer.EmitRawText("\t.frame\t" + + Twine(MBlazeInstPrinter::getRegisterName(stkReg)) + + "," + Twine(stkSze) + "," + + Twine(MBlazeInstPrinter::getRegisterName(retReg))); +} + +void MBlazeAsmPrinter::EmitFunctionEntryLabel() { + if (OutStreamer.hasRawTextSupport()) + OutStreamer.EmitRawText("\t.ent\t" + Twine(CurrentFnSym->getName())); + AsmPrinter::EmitFunctionEntryLabel(); +} + +void MBlazeAsmPrinter::EmitFunctionBodyStart() { + if (!OutStreamer.hasRawTextSupport()) + return; + + emitFrameDirective(); + printSavedRegsBitmask(); +} + +void MBlazeAsmPrinter::EmitFunctionBodyEnd() { + if (OutStreamer.hasRawTextSupport()) + OutStreamer.EmitRawText("\t.end\t" + Twine(CurrentFnSym->getName())); +} + +//===----------------------------------------------------------------------===// +void MBlazeAsmPrinter::EmitInstruction(const MachineInstr *MI) { + MBlazeMCInstLower MCInstLowering(OutContext, *this); + + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + OutStreamer.EmitInstruction(TmpInst); +} + +// Print out an operand for an inline asm expression. +bool MBlazeAsmPrinter:: +PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant,const char *ExtraCode, raw_ostream &O) { + // Does this asm operand have a single letter operand modifier? + if (ExtraCode && ExtraCode[0]) + if (ExtraCode[1] != 0) return true; // Unknown modifier. + + switch (ExtraCode[0]) { + default: + // See if this is a generic print operand + return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); + } + + printOperand(MI, OpNo, O); + return false; +} + +void MBlazeAsmPrinter::printOperand(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + + switch (MO.getType()) { + case MachineOperand::MO_Register: + O << MBlazeInstPrinter::getRegisterName(MO.getReg()); + break; + + case MachineOperand::MO_Immediate: + O << (int32_t)MO.getImm(); + break; + + case MachineOperand::MO_FPImmediate: { + const ConstantFP *fp = MO.getFPImm(); + printHex32(fp->getValueAPF().bitcastToAPInt().getZExtValue(), O); + O << ";\t# immediate = " << *fp; + break; + } + + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + return; + + case MachineOperand::MO_GlobalAddress: + O << *Mang->getSymbol(MO.getGlobal()); + break; + + case MachineOperand::MO_ExternalSymbol: + O << *GetExternalSymbolSymbol(MO.getSymbolName()); + break; + + case MachineOperand::MO_JumpTableIndex: + O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() + << '_' << MO.getIndex(); + break; + + case MachineOperand::MO_ConstantPoolIndex: + O << MAI->getPrivateGlobalPrefix() << "CPI" + << getFunctionNumber() << "_" << MO.getIndex(); + if (MO.getOffset()) + O << "+" << MO.getOffset(); + break; + + default: + llvm_unreachable("<unknown operand type>"); + } +} + +void MBlazeAsmPrinter::printUnsignedImm(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) + O << (uint32_t)MO.getImm(); + else + printOperand(MI, opNum, O); +} + +void MBlazeAsmPrinter::printFSLImm(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) + O << "rfsl" << (unsigned int)MO.getImm(); + else + printOperand(MI, opNum, O); +} + +void MBlazeAsmPrinter:: +printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O, + const char *Modifier) { + printOperand(MI, opNum, O); + O << ", "; + printOperand(MI, opNum+1, O); +} + +/// isBlockOnlyReachableByFallthough - Return true if the basic block has +/// exactly one predecessor and the control transfer mechanism between +/// the predecessor and this block is a fall-through. +bool MBlazeAsmPrinter:: +isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const { + // If this is a landing pad, it isn't a fall through. If it has no preds, + // then nothing falls through to it. + if (MBB->isLandingPad() || MBB->pred_empty()) + return false; + + // If there isn't exactly one predecessor, it can't be a fall through. + MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI; + ++PI2; + if (PI2 != MBB->pred_end()) + return false; + + // The predecessor has to be immediately before this block. + const MachineBasicBlock *Pred = *PI; + + if (!Pred->isLayoutSuccessor(MBB)) + return false; + + // If the block is completely empty, then it definitely does fall through. + if (Pred->empty()) + return true; + + // Check if the last terminator is an unconditional branch. + MachineBasicBlock::const_iterator I = Pred->end(); + while (I != Pred->begin() && !(--I)->isTerminator()) + ; // Noop + return I == Pred->end() || !I->isBarrier(); +} + +// Force static initialization. +extern "C" void LLVMInitializeMBlazeAsmPrinter() { + RegisterAsmPrinter<MBlazeAsmPrinter> X(TheMBlazeTarget); +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeCallingConv.td b/contrib/llvm/lib/Target/MBlaze/MBlazeCallingConv.td new file mode 100644 index 0000000..00a4219 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeCallingConv.td @@ -0,0 +1,24 @@ +//===- MBlazeCallingConv.td - Calling Conventions for MBlaze -*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This describes the calling conventions for MBlaze architecture. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MBlaze ABI Calling Convention +//===----------------------------------------------------------------------===// + +def RetCC_MBlaze : CallingConv<[ + // i32 are returned in registers R3, R4 + CCIfType<[i32,f32], CCAssignToReg<[R3, R4]>> +]>; + +def CC_MBlaze : CallingConv<[ + CCIfType<[i32,f32], CCCustom<"CC_MBlaze_AssignReg">>, + CCIfType<[i32,f32], CCAssignToStack<4, 4>> +]>; diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp new file mode 100644 index 0000000..19e787d --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp @@ -0,0 +1,254 @@ +//===-- DelaySlotFiller.cpp - MBlaze delay slot filler --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A pass that attempts to fill instructions with delay slots. If no +// instructions can be moved into the delay slot then a NOP is placed there. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "delay-slot-filler" + +#include "MBlaze.h" +#include "MBlazeTargetMachine.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +STATISTIC(FilledSlots, "Number of delay slots filled"); + +static cl::opt<bool> MBDisableDelaySlotFiller( + "disable-mblaze-delay-filler", + cl::init(false), + cl::desc("Disable the MBlaze delay slot filter."), + cl::Hidden); + +namespace { + struct Filler : public MachineFunctionPass { + + TargetMachine &TM; + const TargetInstrInfo *TII; + + static char ID; + Filler(TargetMachine &tm) + : MachineFunctionPass(ID), TM(tm), TII(tm.getInstrInfo()) { } + + virtual const char *getPassName() const { + return "MBlaze Delay Slot Filler"; + } + + bool runOnMachineBasicBlock(MachineBasicBlock &MBB); + bool runOnMachineFunction(MachineFunction &F) { + bool Changed = false; + for (MachineFunction::iterator FI = F.begin(), FE = F.end(); + FI != FE; ++FI) + Changed |= runOnMachineBasicBlock(*FI); + return Changed; + } + + }; + char Filler::ID = 0; +} // end of anonymous namespace + +static bool hasImmInstruction(MachineBasicBlock::iterator &candidate) { + // Any instruction with an immediate mode operand greater than + // 16-bits requires an implicit IMM instruction. + unsigned numOper = candidate->getNumOperands(); + for (unsigned op = 0; op < numOper; ++op) { + MachineOperand &mop = candidate->getOperand(op); + + // The operand requires more than 16-bits to represent. + if (mop.isImm() && (mop.getImm() < -0x8000 || mop.getImm() > 0x7fff)) + return true; + + // We must assume that unknown immediate values require more than + // 16-bits to represent. + if (mop.isGlobal() || mop.isSymbol() || mop.isJTI() || mop.isCPI()) + return true; + + // FIXME: we could probably check to see if the FP value happens + // to not need an IMM instruction. For now we just always + // assume that FP values do. + if (mop.isFPImm()) + return true; + } + + return false; +} + +static unsigned getLastRealOperand(MachineBasicBlock::iterator &instr) { + switch (instr->getOpcode()) { + default: return instr->getNumOperands(); + + // These instructions have a variable number of operands but the first two + // are the "real" operands that we care about during hazard detection. + case MBlaze::BRLID: + case MBlaze::BRALID: + case MBlaze::BRLD: + case MBlaze::BRALD: + return 2; + } +} + +static bool delayHasHazard(MachineBasicBlock::iterator &candidate, + MachineBasicBlock::iterator &slot) { + // Hazard check + MachineBasicBlock::iterator a = candidate; + MachineBasicBlock::iterator b = slot; + + // MBB layout:- + // candidate := a0 = operation(a1, a2) + // ...middle bit... + // slot := b0 = operation(b1, b2) + + // Possible hazards:-/ + // 1. a1 or a2 was written during the middle bit + // 2. a0 was read or written during the middle bit + // 3. a0 is one or more of {b0, b1, b2} + // 4. b0 is one or more of {a1, a2} + // 5. a accesses memory, and the middle bit + // contains a store operation. + bool a_is_memory = candidate->mayLoad() || candidate->mayStore(); + + // Determine the number of operands in the slot instruction and in the + // candidate instruction. + const unsigned aend = getLastRealOperand(a); + const unsigned bend = getLastRealOperand(b); + + // Check hazards type 1, 2 and 5 by scanning the middle bit + MachineBasicBlock::iterator m = a; + for (++m; m != b; ++m) { + for (unsigned aop = 0; aop<aend; ++aop) { + bool aop_is_reg = a->getOperand(aop).isReg(); + if (!aop_is_reg) continue; + + bool aop_is_def = a->getOperand(aop).isDef(); + unsigned aop_reg = a->getOperand(aop).getReg(); + + const unsigned mend = getLastRealOperand(m); + for (unsigned mop = 0; mop<mend; ++mop) { + bool mop_is_reg = m->getOperand(mop).isReg(); + if (!mop_is_reg) continue; + + bool mop_is_def = m->getOperand(mop).isDef(); + unsigned mop_reg = m->getOperand(mop).getReg(); + + if (aop_is_def && (mop_reg == aop_reg)) + return true; // Hazard type 2, because aop = a0 + else if (mop_is_def && (mop_reg == aop_reg)) + return true; // Hazard type 1, because aop in {a1, a2} + } + } + + // Check hazard type 5 + if (a_is_memory && m->mayStore()) + return true; + } + + // Check hazard type 3 & 4 + for (unsigned aop = 0; aop<aend; ++aop) { + if (a->getOperand(aop).isReg()) { + unsigned aop_reg = a->getOperand(aop).getReg(); + + for (unsigned bop = 0; bop<bend; ++bop) { + if (b->getOperand(bop).isReg() && !b->getOperand(bop).isImplicit()) { + unsigned bop_reg = b->getOperand(bop).getReg(); + if (aop_reg == bop_reg) + return true; + } + } + } + } + + return false; +} + +static bool isDelayFiller(MachineBasicBlock &MBB, + MachineBasicBlock::iterator candidate) { + if (candidate == MBB.begin()) + return false; + + --candidate; + return (candidate->hasDelaySlot()); +} + +static bool hasUnknownSideEffects(MachineBasicBlock::iterator &I) { + if (!I->hasUnmodeledSideEffects()) + return false; + + unsigned op = I->getOpcode(); + if (op == MBlaze::ADDK || op == MBlaze::ADDIK || + op == MBlaze::ADDC || op == MBlaze::ADDIC || + op == MBlaze::ADDKC || op == MBlaze::ADDIKC || + op == MBlaze::RSUBK || op == MBlaze::RSUBIK || + op == MBlaze::RSUBC || op == MBlaze::RSUBIC || + op == MBlaze::RSUBKC || op == MBlaze::RSUBIKC) + return false; + + return true; +} + +static MachineBasicBlock::iterator +findDelayInstr(MachineBasicBlock &MBB,MachineBasicBlock::iterator slot) { + MachineBasicBlock::iterator I = slot; + while (true) { + if (I == MBB.begin()) + break; + + --I; + if (I->hasDelaySlot() || I->isBranch() || isDelayFiller(MBB,I) || + I->isCall() || I->isReturn() || I->isBarrier() || + hasUnknownSideEffects(I)) + break; + + if (hasImmInstruction(I) || delayHasHazard(I,slot)) + continue; + + return I; + } + + return MBB.end(); +} + +/// runOnMachineBasicBlock - Fill in delay slots for the given basic block. +/// Currently, we fill delay slots with NOPs. We assume there is only one +/// delay slot per delayed instruction. +bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { + bool Changed = false; + for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) + if (I->hasDelaySlot()) { + MachineBasicBlock::iterator D = MBB.end(); + MachineBasicBlock::iterator J = I; + + if (!MBDisableDelaySlotFiller) + D = findDelayInstr(MBB,I); + + ++FilledSlots; + Changed = true; + + if (D == MBB.end()) + BuildMI(MBB, ++J, I->getDebugLoc(), TII->get(MBlaze::NOP)); + else + MBB.splice(++J, &MBB, D); + } + return Changed; +} + +/// createMBlazeDelaySlotFillerPass - Returns a pass that fills in delay +/// slots in MBlaze MachineFunctions +FunctionPass *llvm::createMBlazeDelaySlotFillerPass(MBlazeTargetMachine &tm) { + return new Filler(tm); +} + diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeELFWriterInfo.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeELFWriterInfo.cpp new file mode 100644 index 0000000..e3c7236 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeELFWriterInfo.cpp @@ -0,0 +1,107 @@ +//===-- MBlazeELFWriterInfo.cpp - ELF Writer Info for the MBlaze backend --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements ELF writer information for the MBlaze backend. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeELFWriterInfo.h" +#include "MBlazeRelocations.h" +#include "llvm/Function.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" + +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Implementation of the MBlazeELFWriterInfo class +//===----------------------------------------------------------------------===// + +MBlazeELFWriterInfo::MBlazeELFWriterInfo(TargetMachine &TM) + : TargetELFWriterInfo(TM.getTargetData()->getPointerSizeInBits() == 64, + TM.getTargetData()->isLittleEndian()) { +} + +MBlazeELFWriterInfo::~MBlazeELFWriterInfo() {} + +unsigned MBlazeELFWriterInfo::getRelocationType(unsigned MachineRelTy) const { + switch (MachineRelTy) { + case MBlaze::reloc_pcrel_word: + return ELF::R_MICROBLAZE_64_PCREL; + case MBlaze::reloc_absolute_word: + return ELF::R_MICROBLAZE_NONE; + default: + llvm_unreachable("unknown mblaze machine relocation type"); + } +} + +long int MBlazeELFWriterInfo::getDefaultAddendForRelTy(unsigned RelTy, + long int Modifier) const { + switch (RelTy) { + case ELF::R_MICROBLAZE_32_PCREL: + return Modifier - 4; + case ELF::R_MICROBLAZE_32: + return Modifier; + default: + llvm_unreachable("unknown mblaze relocation type"); + } +} + +unsigned MBlazeELFWriterInfo::getRelocationTySize(unsigned RelTy) const { + // FIXME: Most of these sizes are guesses based on the name + switch (RelTy) { + case ELF::R_MICROBLAZE_32: + case ELF::R_MICROBLAZE_32_PCREL: + case ELF::R_MICROBLAZE_32_PCREL_LO: + case ELF::R_MICROBLAZE_32_LO: + case ELF::R_MICROBLAZE_SRO32: + case ELF::R_MICROBLAZE_SRW32: + case ELF::R_MICROBLAZE_32_SYM_OP_SYM: + case ELF::R_MICROBLAZE_GOTOFF_32: + return 32; + + case ELF::R_MICROBLAZE_64_PCREL: + case ELF::R_MICROBLAZE_64: + case ELF::R_MICROBLAZE_GOTPC_64: + case ELF::R_MICROBLAZE_GOT_64: + case ELF::R_MICROBLAZE_PLT_64: + case ELF::R_MICROBLAZE_GOTOFF_64: + return 64; + } + + return 0; +} + +bool MBlazeELFWriterInfo::isPCRelativeRel(unsigned RelTy) const { + // FIXME: Most of these are guesses based on the name + switch (RelTy) { + case ELF::R_MICROBLAZE_32_PCREL: + case ELF::R_MICROBLAZE_64_PCREL: + case ELF::R_MICROBLAZE_32_PCREL_LO: + case ELF::R_MICROBLAZE_GOTPC_64: + return true; + } + + return false; +} + +unsigned MBlazeELFWriterInfo::getAbsoluteLabelMachineRelTy() const { + return MBlaze::reloc_absolute_word; +} + +long int MBlazeELFWriterInfo::computeRelocation(unsigned SymOffset, + unsigned RelOffset, + unsigned RelTy) const { + assert((RelTy == ELF::R_MICROBLAZE_32_PCREL || + RelTy == ELF::R_MICROBLAZE_64_PCREL) && + "computeRelocation unknown for this relocation type"); + return SymOffset - (RelOffset + 4); +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeELFWriterInfo.h b/contrib/llvm/lib/Target/MBlaze/MBlazeELFWriterInfo.h new file mode 100644 index 0000000..a314eb7 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeELFWriterInfo.h @@ -0,0 +1,59 @@ +//===-- MBlazeELFWriterInfo.h - ELF Writer Info for MBlaze ------*- 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 ELF writer information for the MBlaze backend. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZE_ELF_WRITER_INFO_H +#define MBLAZE_ELF_WRITER_INFO_H + +#include "llvm/Target/TargetELFWriterInfo.h" + +namespace llvm { + class TargetMachine; + + class MBlazeELFWriterInfo : public TargetELFWriterInfo { + public: + MBlazeELFWriterInfo(TargetMachine &TM); + virtual ~MBlazeELFWriterInfo(); + + /// getRelocationType - Returns the target specific ELF Relocation type. + /// 'MachineRelTy' contains the object code independent relocation type + virtual unsigned getRelocationType(unsigned MachineRelTy) const; + + /// hasRelocationAddend - True if the target uses an addend in the + /// ELF relocation entry. + virtual bool hasRelocationAddend() const { return false; } + + /// getDefaultAddendForRelTy - Gets the default addend value for a + /// relocation entry based on the target ELF relocation type. + virtual long int getDefaultAddendForRelTy(unsigned RelTy, + long int Modifier = 0) const; + + /// getRelTySize - Returns the size of relocatable field in bits + virtual unsigned getRelocationTySize(unsigned RelTy) const; + + /// isPCRelativeRel - True if the relocation type is pc relative + virtual bool isPCRelativeRel(unsigned RelTy) const; + + /// getJumpTableRelocationTy - Returns the machine relocation type used + /// to reference a jumptable. + virtual unsigned getAbsoluteLabelMachineRelTy() const; + + /// computeRelocation - Some relocatable fields could be relocated + /// directly, avoiding the relocation symbol emission, compute the + /// final relocation value for this symbol. + virtual long int computeRelocation(unsigned SymOffset, unsigned RelOffset, + unsigned RelTy) const; + }; + +} // end llvm namespace + +#endif // MBLAZE_ELF_WRITER_INFO_H diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeFrameLowering.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeFrameLowering.cpp new file mode 100644 index 0000000..d2f14a5 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeFrameLowering.cpp @@ -0,0 +1,449 @@ +//===-- MBlazeFrameLowering.cpp - MBlaze Frame Information ---------------====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the MBlaze implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mblaze-frame-lowering" + +#include "MBlazeFrameLowering.h" +#include "MBlazeInstrInfo.h" +#include "MBlazeMachineFunction.h" +#include "InstPrinter/MBlazeInstPrinter.h" +#include "llvm/Function.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +static cl::opt<bool> MBDisableStackAdjust( + "disable-mblaze-stack-adjust", + cl::init(false), + cl::desc("Disable MBlaze stack layout adjustment."), + cl::Hidden); + +static void replaceFrameIndexes(MachineFunction &MF, + SmallVector<std::pair<int,int64_t>, 16> &FR) { + MachineFrameInfo *MFI = MF.getFrameInfo(); + MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + const SmallVector<std::pair<int,int64_t>, 16>::iterator FRB = FR.begin(); + const SmallVector<std::pair<int,int64_t>, 16>::iterator FRE = FR.end(); + + SmallVector<std::pair<int,int64_t>, 16>::iterator FRI = FRB; + for (; FRI != FRE; ++FRI) { + MFI->RemoveStackObject(FRI->first); + int NFI = MFI->CreateFixedObject(4, FRI->second, true); + MBlazeFI->recordReplacement(FRI->first, NFI); + + for (MachineFunction::iterator MB=MF.begin(), ME=MF.end(); MB!=ME; ++MB) { + MachineBasicBlock::iterator MBB = MB->begin(); + const MachineBasicBlock::iterator MBE = MB->end(); + + for (; MBB != MBE; ++MBB) { + MachineInstr::mop_iterator MIB = MBB->operands_begin(); + const MachineInstr::mop_iterator MIE = MBB->operands_end(); + + for (MachineInstr::mop_iterator MII = MIB; MII != MIE; ++MII) { + if (!MII->isFI() || MII->getIndex() != FRI->first) continue; + DEBUG(dbgs() << "FOUND FI#" << MII->getIndex() << "\n"); + MII->setIndex(NFI); + } + } + } + } +} + +//===----------------------------------------------------------------------===// +// +// Stack Frame Processing methods +// +----------------------------+ +// +// The stack is allocated decrementing the stack pointer on +// the first instruction of a function prologue. Once decremented, +// all stack references are are done through a positive offset +// from the stack/frame pointer, so the stack is considered +// to grow up. +// +//===----------------------------------------------------------------------===// + +static void analyzeFrameIndexes(MachineFunction &MF) { + if (MBDisableStackAdjust) return; + + MachineFrameInfo *MFI = MF.getFrameInfo(); + MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + const MachineRegisterInfo &MRI = MF.getRegInfo(); + + MachineRegisterInfo::livein_iterator LII = MRI.livein_begin(); + MachineRegisterInfo::livein_iterator LIE = MRI.livein_end(); + const SmallVector<int, 16> &LiveInFI = MBlazeFI->getLiveIn(); + SmallVector<MachineInstr*, 16> EraseInstr; + SmallVector<std::pair<int,int64_t>, 16> FrameRelocate; + + MachineBasicBlock *MBB = MF.getBlockNumbered(0); + MachineBasicBlock::iterator MIB = MBB->begin(); + MachineBasicBlock::iterator MIE = MBB->end(); + + int StackAdjust = 0; + int StackOffset = -28; + + // In this loop we are searching frame indexes that corrospond to incoming + // arguments that are already in the stack. We look for instruction sequences + // like the following: + // + // LWI REG, FI1, 0 + // ... + // SWI REG, FI2, 0 + // + // As long as there are no defs of REG in the ... part, we can eliminate + // the SWI instruction because the value has already been stored to the + // stack by the caller. All we need to do is locate FI at the correct + // stack location according to the calling convensions. + // + // Additionally, if the SWI operation kills the def of REG then we don't + // need the LWI operation so we can erase it as well. + for (unsigned i = 0, e = LiveInFI.size(); i < e; ++i) { + for (MachineBasicBlock::iterator I=MIB; I != MIE; ++I) { + if (I->getOpcode() != MBlaze::LWI || I->getNumOperands() != 3 || + !I->getOperand(1).isFI() || !I->getOperand(0).isReg() || + I->getOperand(1).getIndex() != LiveInFI[i]) continue; + + unsigned FIReg = I->getOperand(0).getReg(); + MachineBasicBlock::iterator SI = I; + for (SI++; SI != MIE; ++SI) { + if (!SI->getOperand(0).isReg() || + !SI->getOperand(1).isFI() || + SI->getOpcode() != MBlaze::SWI) continue; + + int FI = SI->getOperand(1).getIndex(); + if (SI->getOperand(0).getReg() != FIReg || + MFI->isFixedObjectIndex(FI) || + MFI->getObjectSize(FI) != 4) continue; + + if (SI->getOperand(0).isDef()) break; + + if (SI->getOperand(0).isKill()) { + DEBUG(dbgs() << "LWI for FI#" << I->getOperand(1).getIndex() + << " removed\n"); + EraseInstr.push_back(I); + } + + EraseInstr.push_back(SI); + DEBUG(dbgs() << "SWI for FI#" << FI << " removed\n"); + + FrameRelocate.push_back(std::make_pair(FI,StackOffset)); + DEBUG(dbgs() << "FI#" << FI << " relocated to " << StackOffset << "\n"); + + StackOffset -= 4; + StackAdjust += 4; + break; + } + } + } + + // In this loop we are searching for frame indexes that corrospond to + // incoming arguments that are in registers. We look for instruction + // sequences like the following: + // + // ... SWI REG, FI, 0 + // + // As long as the ... part does not define REG and if REG is an incoming + // parameter register then we know that, according to ABI convensions, the + // caller has allocated stack space for it already. Instead of allocating + // stack space on our frame, we record the correct location in the callers + // frame. + for (MachineRegisterInfo::livein_iterator LI = LII; LI != LIE; ++LI) { + for (MachineBasicBlock::iterator I=MIB; I != MIE; ++I) { + if (I->definesRegister(LI->first)) + break; + + if (I->getOpcode() != MBlaze::SWI || I->getNumOperands() != 3 || + !I->getOperand(1).isFI() || !I->getOperand(0).isReg() || + I->getOperand(1).getIndex() < 0) continue; + + if (I->getOperand(0).getReg() == LI->first) { + int FI = I->getOperand(1).getIndex(); + MBlazeFI->recordLiveIn(FI); + + int FILoc = 0; + switch (LI->first) { + default: llvm_unreachable("invalid incoming parameter!"); + case MBlaze::R5: FILoc = -4; break; + case MBlaze::R6: FILoc = -8; break; + case MBlaze::R7: FILoc = -12; break; + case MBlaze::R8: FILoc = -16; break; + case MBlaze::R9: FILoc = -20; break; + case MBlaze::R10: FILoc = -24; break; + } + + StackAdjust += 4; + FrameRelocate.push_back(std::make_pair(FI,FILoc)); + DEBUG(dbgs() << "FI#" << FI << " relocated to " << FILoc << "\n"); + break; + } + } + } + + // Go ahead and erase all of the instructions that we determined were + // no longer needed. + for (int i = 0, e = EraseInstr.size(); i < e; ++i) + MBB->erase(EraseInstr[i]); + + // Replace all of the frame indexes that we have relocated with new + // fixed object frame indexes. + replaceFrameIndexes(MF, FrameRelocate); +} + +static void interruptFrameLayout(MachineFunction &MF) { + const Function *F = MF.getFunction(); + CallingConv::ID CallConv = F->getCallingConv(); + + // If this function is not using either the interrupt_handler + // calling convention or the save_volatiles calling convention + // then we don't need to do any additional frame layout. + if (CallConv != CallingConv::MBLAZE_INTR && + CallConv != CallingConv::MBLAZE_SVOL) + return; + + MachineFrameInfo *MFI = MF.getFrameInfo(); + const MachineRegisterInfo &MRI = MF.getRegInfo(); + const MBlazeInstrInfo &TII = + *static_cast<const MBlazeInstrInfo*>(MF.getTarget().getInstrInfo()); + + // Determine if the calling convention is the interrupt_handler + // calling convention. Some pieces of the prologue and epilogue + // only need to be emitted if we are lowering and interrupt handler. + bool isIntr = CallConv == CallingConv::MBLAZE_INTR; + + // Determine where to put prologue and epilogue additions + MachineBasicBlock &MENT = MF.front(); + MachineBasicBlock &MEXT = MF.back(); + + MachineBasicBlock::iterator MENTI = MENT.begin(); + MachineBasicBlock::iterator MEXTI = prior(MEXT.end()); + + DebugLoc ENTDL = MENTI != MENT.end() ? MENTI->getDebugLoc() : DebugLoc(); + DebugLoc EXTDL = MEXTI != MEXT.end() ? MEXTI->getDebugLoc() : DebugLoc(); + + // Store the frame indexes generated during prologue additions for use + // when we are generating the epilogue additions. + SmallVector<int, 10> VFI; + + // Build the prologue SWI for R3 - R12 if needed. Note that R11 must + // always have a SWI because it is used when processing RMSR. + for (unsigned r = MBlaze::R3; r <= MBlaze::R12; ++r) { + if (!MRI.isPhysRegUsed(r) && !(isIntr && r == MBlaze::R11)) continue; + + int FI = MFI->CreateStackObject(4,4,false,false); + VFI.push_back(FI); + + BuildMI(MENT, MENTI, ENTDL, TII.get(MBlaze::SWI), r) + .addFrameIndex(FI).addImm(0); + } + + // Build the prologue SWI for R17, R18 + int R17FI = MFI->CreateStackObject(4,4,false,false); + int R18FI = MFI->CreateStackObject(4,4,false,false); + + BuildMI(MENT, MENTI, ENTDL, TII.get(MBlaze::SWI), MBlaze::R17) + .addFrameIndex(R17FI).addImm(0); + + BuildMI(MENT, MENTI, ENTDL, TII.get(MBlaze::SWI), MBlaze::R18) + .addFrameIndex(R18FI).addImm(0); + + // Buid the prologue SWI and the epilogue LWI for RMSR if needed + if (isIntr) { + int MSRFI = MFI->CreateStackObject(4,4,false,false); + BuildMI(MENT, MENTI, ENTDL, TII.get(MBlaze::MFS), MBlaze::R11) + .addReg(MBlaze::RMSR); + BuildMI(MENT, MENTI, ENTDL, TII.get(MBlaze::SWI), MBlaze::R11) + .addFrameIndex(MSRFI).addImm(0); + + BuildMI(MEXT, MEXTI, EXTDL, TII.get(MBlaze::LWI), MBlaze::R11) + .addFrameIndex(MSRFI).addImm(0); + BuildMI(MEXT, MEXTI, EXTDL, TII.get(MBlaze::MTS), MBlaze::RMSR) + .addReg(MBlaze::R11); + } + + // Build the epilogue LWI for R17, R18 + BuildMI(MEXT, MEXTI, EXTDL, TII.get(MBlaze::LWI), MBlaze::R18) + .addFrameIndex(R18FI).addImm(0); + + BuildMI(MEXT, MEXTI, EXTDL, TII.get(MBlaze::LWI), MBlaze::R17) + .addFrameIndex(R17FI).addImm(0); + + // Build the epilogue LWI for R3 - R12 if needed + for (unsigned r = MBlaze::R12, i = VFI.size(); r >= MBlaze::R3; --r) { + if (!MRI.isPhysRegUsed(r)) continue; + BuildMI(MEXT, MEXTI, EXTDL, TII.get(MBlaze::LWI), r) + .addFrameIndex(VFI[--i]).addImm(0); + } +} + +static void determineFrameLayout(MachineFunction &MF) { + MachineFrameInfo *MFI = MF.getFrameInfo(); + MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + + // Replace the dummy '0' SPOffset by the negative offsets, as explained on + // LowerFORMAL_ARGUMENTS. Leaving '0' for while is necessary to avoid + // the approach done by calculateFrameObjectOffsets to the stack frame. + MBlazeFI->adjustLoadArgsFI(MFI); + MBlazeFI->adjustStoreVarArgsFI(MFI); + + // Get the number of bytes to allocate from the FrameInfo + unsigned FrameSize = MFI->getStackSize(); + DEBUG(dbgs() << "Original Frame Size: " << FrameSize << "\n" ); + + // Get the alignments provided by the target, and the maximum alignment + // (if any) of the fixed frame objects. + // unsigned MaxAlign = MFI->getMaxAlignment(); + unsigned TargetAlign = MF.getTarget().getFrameLowering()->getStackAlignment(); + unsigned AlignMask = TargetAlign - 1; + + // Make sure the frame is aligned. + FrameSize = (FrameSize + AlignMask) & ~AlignMask; + MFI->setStackSize(FrameSize); + DEBUG(dbgs() << "Aligned Frame Size: " << FrameSize << "\n" ); +} + +int MBlazeFrameLowering::getFrameIndexOffset(const MachineFunction &MF, int FI) + const { + const MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + if (MBlazeFI->hasReplacement(FI)) + FI = MBlazeFI->getReplacement(FI); + return TargetFrameLowering::getFrameIndexOffset(MF,FI); +} + +// hasFP - Return true if the specified function should have a dedicated frame +// pointer register. This is true if the function has variable sized allocas or +// if frame pointer elimination is disabled. +bool MBlazeFrameLowering::hasFP(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + return MF.getTarget().Options.DisableFramePointerElim(MF) || + MFI->hasVarSizedObjects(); +} + +void MBlazeFrameLowering::emitPrologue(MachineFunction &MF) const { + MachineBasicBlock &MBB = MF.front(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const MBlazeInstrInfo &TII = + *static_cast<const MBlazeInstrInfo*>(MF.getTarget().getInstrInfo()); + MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + MachineBasicBlock::iterator MBBI = MBB.begin(); + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + CallingConv::ID CallConv = MF.getFunction()->getCallingConv(); + bool requiresRA = CallConv == CallingConv::MBLAZE_INTR; + + // Determine the correct frame layout + determineFrameLayout(MF); + + // Get the number of bytes to allocate from the FrameInfo. + unsigned StackSize = MFI->getStackSize(); + + // No need to allocate space on the stack. + if (StackSize == 0 && !MFI->adjustsStack() && !requiresRA) return; + + int FPOffset = MBlazeFI->getFPStackOffset(); + int RAOffset = MBlazeFI->getRAStackOffset(); + + // Adjust stack : addi R1, R1, -imm + BuildMI(MBB, MBBI, DL, TII.get(MBlaze::ADDIK), MBlaze::R1) + .addReg(MBlaze::R1).addImm(-StackSize); + + // swi R15, R1, stack_loc + if (MFI->adjustsStack() || requiresRA) { + BuildMI(MBB, MBBI, DL, TII.get(MBlaze::SWI)) + .addReg(MBlaze::R15).addReg(MBlaze::R1).addImm(RAOffset); + } + + if (hasFP(MF)) { + // swi R19, R1, stack_loc + BuildMI(MBB, MBBI, DL, TII.get(MBlaze::SWI)) + .addReg(MBlaze::R19).addReg(MBlaze::R1).addImm(FPOffset); + + // add R19, R1, R0 + BuildMI(MBB, MBBI, DL, TII.get(MBlaze::ADD), MBlaze::R19) + .addReg(MBlaze::R1).addReg(MBlaze::R0); + } +} + +void MBlazeFrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + const MBlazeInstrInfo &TII = + *static_cast<const MBlazeInstrInfo*>(MF.getTarget().getInstrInfo()); + + DebugLoc dl = MBBI->getDebugLoc(); + + CallingConv::ID CallConv = MF.getFunction()->getCallingConv(); + bool requiresRA = CallConv == CallingConv::MBLAZE_INTR; + + // Get the FI's where RA and FP are saved. + int FPOffset = MBlazeFI->getFPStackOffset(); + int RAOffset = MBlazeFI->getRAStackOffset(); + + if (hasFP(MF)) { + // add R1, R19, R0 + BuildMI(MBB, MBBI, dl, TII.get(MBlaze::ADD), MBlaze::R1) + .addReg(MBlaze::R19).addReg(MBlaze::R0); + + // lwi R19, R1, stack_loc + BuildMI(MBB, MBBI, dl, TII.get(MBlaze::LWI), MBlaze::R19) + .addReg(MBlaze::R1).addImm(FPOffset); + } + + // lwi R15, R1, stack_loc + if (MFI->adjustsStack() || requiresRA) { + BuildMI(MBB, MBBI, dl, TII.get(MBlaze::LWI), MBlaze::R15) + .addReg(MBlaze::R1).addImm(RAOffset); + } + + // Get the number of bytes from FrameInfo + int StackSize = (int) MFI->getStackSize(); + + // addi R1, R1, imm + if (StackSize) { + BuildMI(MBB, MBBI, dl, TII.get(MBlaze::ADDIK), MBlaze::R1) + .addReg(MBlaze::R1).addImm(StackSize); + } +} + +void MBlazeFrameLowering:: +processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const { + MachineFrameInfo *MFI = MF.getFrameInfo(); + MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + CallingConv::ID CallConv = MF.getFunction()->getCallingConv(); + bool requiresRA = CallConv == CallingConv::MBLAZE_INTR; + + if (MFI->adjustsStack() || requiresRA) { + MBlazeFI->setRAStackOffset(0); + MFI->CreateFixedObject(4,0,true); + } + + if (hasFP(MF)) { + MBlazeFI->setFPStackOffset(4); + MFI->CreateFixedObject(4,4,true); + } + + interruptFrameLayout(MF); + analyzeFrameIndexes(MF); +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeFrameLowering.h b/contrib/llvm/lib/Target/MBlaze/MBlazeFrameLowering.h new file mode 100644 index 0000000..01e6578 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeFrameLowering.h @@ -0,0 +1,52 @@ +//=- MBlazeFrameLowering.h - Define frame lowering for MicroBlaze -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZE_FRAMEINFO_H +#define MBLAZE_FRAMEINFO_H + +#include "MBlaze.h" +#include "llvm/Target/TargetFrameLowering.h" + +namespace llvm { +class MBlazeSubtarget; + +class MBlazeFrameLowering : public TargetFrameLowering { +protected: + const MBlazeSubtarget &STI; + +public: + explicit MBlazeFrameLowering(const MBlazeSubtarget &sti) + : TargetFrameLowering(TargetFrameLowering::StackGrowsUp, 4, 0), STI(sti) { + } + + /// targetHandlesStackFrameRounding - Returns true if the target is + /// responsible for rounding up the stack frame (probably at emitPrologue + /// time). + bool targetHandlesStackFrameRounding() const { return true; } + + /// emitProlog/emitEpilog - These methods insert prolog and epilog code into + /// the function. + void emitPrologue(MachineFunction &MF) const; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + + bool hasFP(const MachineFunction &MF) const; + + int getFrameIndexOffset(const MachineFunction &MF, int FI) const; + + virtual void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const; +}; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp new file mode 100644 index 0000000..6b43497 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp @@ -0,0 +1,277 @@ +//===-- MBlazeISelDAGToDAG.cpp - A dag to dag inst selector for MBlaze ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an instruction selector for the MBlaze target. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mblaze-isel" +#include "MBlaze.h" +#include "MBlazeMachineFunction.h" +#include "MBlazeRegisterInfo.h" +#include "MBlazeSubtarget.h" +#include "MBlazeTargetMachine.h" +#include "llvm/GlobalValue.h" +#include "llvm/Instructions.h" +#include "llvm/Intrinsics.h" +#include "llvm/Support/CFG.h" +#include "llvm/Type.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Instruction Selector Implementation +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MBlazeDAGToDAGISel - MBlaze specific code to select MBlaze machine +// instructions for SelectionDAG operations. +//===----------------------------------------------------------------------===// +namespace { + +class MBlazeDAGToDAGISel : public SelectionDAGISel { + + /// TM - Keep a reference to MBlazeTargetMachine. + MBlazeTargetMachine &TM; + + /// Subtarget - Keep a pointer to the MBlazeSubtarget around so that we can + /// make the right decision when generating code for different targets. + const MBlazeSubtarget &Subtarget; + +public: + explicit MBlazeDAGToDAGISel(MBlazeTargetMachine &tm) : + SelectionDAGISel(tm), + TM(tm), Subtarget(tm.getSubtarget<MBlazeSubtarget>()) {} + + // Pass Name + virtual const char *getPassName() const { + return "MBlaze DAG->DAG Pattern Instruction Selection"; + } +private: + // Include the pieces autogenerated from the target description. + #include "MBlazeGenDAGISel.inc" + + /// getTargetMachine - Return a reference to the TargetMachine, casted + /// to the target-specific type. + const MBlazeTargetMachine &getTargetMachine() { + return static_cast<const MBlazeTargetMachine &>(TM); + } + + /// getInstrInfo - Return a reference to the TargetInstrInfo, casted + /// to the target-specific type. + const MBlazeInstrInfo *getInstrInfo() { + return getTargetMachine().getInstrInfo(); + } + + SDNode *getGlobalBaseReg(); + SDNode *Select(SDNode *N); + + // Address Selection + bool SelectAddrRegReg(SDValue N, SDValue &Base, SDValue &Index); + bool SelectAddrRegImm(SDValue N, SDValue &Disp, SDValue &Base); + + // getI32Imm - Return a target constant with the specified value, of type i32. + inline SDValue getI32Imm(unsigned Imm) { + return CurDAG->getTargetConstant(Imm, MVT::i32); + } +}; + +} + +/// isIntS32Immediate - This method tests to see if the node is either a 32-bit +/// or 64-bit immediate, and if the value can be accurately represented as a +/// sign extension from a 32-bit value. If so, this returns true and the +/// immediate. +static bool isIntS32Immediate(SDNode *N, int32_t &Imm) { + unsigned Opc = N->getOpcode(); + if (Opc != ISD::Constant) + return false; + + Imm = (int32_t)cast<ConstantSDNode>(N)->getZExtValue(); + if (N->getValueType(0) == MVT::i32) + return Imm == (int32_t)cast<ConstantSDNode>(N)->getZExtValue(); + else + return Imm == (int64_t)cast<ConstantSDNode>(N)->getZExtValue(); +} + +static bool isIntS32Immediate(SDValue Op, int32_t &Imm) { + return isIntS32Immediate(Op.getNode(), Imm); +} + + +/// SelectAddressRegReg - Given the specified addressed, check to see if it +/// can be represented as an indexed [r+r] operation. Returns false if it +/// can be more efficiently represented with [r+imm]. +bool MBlazeDAGToDAGISel:: +SelectAddrRegReg(SDValue N, SDValue &Base, SDValue &Index) { + if (N.getOpcode() == ISD::FrameIndex) return false; + if (N.getOpcode() == ISD::TargetExternalSymbol || + N.getOpcode() == ISD::TargetGlobalAddress) + return false; // direct calls. + + int32_t imm = 0; + if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) { + if (isIntS32Immediate(N.getOperand(1), imm)) + return false; // r+i + + if (N.getOperand(0).getOpcode() == ISD::TargetJumpTable || + N.getOperand(1).getOpcode() == ISD::TargetJumpTable) + return false; // jump tables. + + Base = N.getOperand(0); + Index = N.getOperand(1); + return true; + } + + return false; +} + +/// Returns true if the address N can be represented by a base register plus +/// a signed 32-bit displacement [r+imm], and if it is not better +/// represented as reg+reg. +bool MBlazeDAGToDAGISel:: +SelectAddrRegImm(SDValue N, SDValue &Base, SDValue &Disp) { + // If this can be more profitably realized as r+r, fail. + if (SelectAddrRegReg(N, Base, Disp)) + return false; + + if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) { + int32_t imm = 0; + if (isIntS32Immediate(N.getOperand(1), imm)) { + Disp = CurDAG->getTargetConstant(imm, MVT::i32); + if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N.getOperand(0))) { + Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType()); + } else { + Base = N.getOperand(0); + } + return true; // [r+i] + } + } else if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) { + // Loading from a constant address. + uint32_t Imm = CN->getZExtValue(); + Disp = CurDAG->getTargetConstant(Imm, CN->getValueType(0)); + Base = CurDAG->getRegister(MBlaze::R0, CN->getValueType(0)); + return true; + } + + Disp = CurDAG->getTargetConstant(0, TM.getTargetLowering()->getPointerTy()); + if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N)) + Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType()); + else + Base = N; + return true; // [r+0] +} + +/// getGlobalBaseReg - Output the instructions required to put the +/// GOT address into a register. +SDNode *MBlazeDAGToDAGISel::getGlobalBaseReg() { + unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF); + return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode(); +} + +/// Select instructions not customized! Used for +/// expanded, promoted and normal instructions +SDNode* MBlazeDAGToDAGISel::Select(SDNode *Node) { + unsigned Opcode = Node->getOpcode(); + DebugLoc dl = Node->getDebugLoc(); + + // If we have a custom node, we already have selected! + if (Node->isMachineOpcode()) + return NULL; + + /// + // Instruction Selection not handled by the auto-generated + // tablegen selection should be handled here. + /// + switch (Opcode) { + default: break; + + // Get target GOT address. + case ISD::GLOBAL_OFFSET_TABLE: + return getGlobalBaseReg(); + + case ISD::FrameIndex: { + SDValue imm = CurDAG->getTargetConstant(0, MVT::i32); + int FI = dyn_cast<FrameIndexSDNode>(Node)->getIndex(); + EVT VT = Node->getValueType(0); + SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); + unsigned Opc = MBlaze::ADDIK; + if (Node->hasOneUse()) + return CurDAG->SelectNodeTo(Node, Opc, VT, TFI, imm); + return CurDAG->getMachineNode(Opc, dl, VT, TFI, imm); + } + + + /// Handle direct and indirect calls when using PIC. On PIC, when + /// GOT is smaller than about 64k (small code) the GA target is + /// loaded with only one instruction. Otherwise GA's target must + /// be loaded with 3 instructions. + case MBlazeISD::JmpLink: { + if (TM.getRelocationModel() == Reloc::PIC_) { + SDValue Chain = Node->getOperand(0); + SDValue Callee = Node->getOperand(1); + SDValue R20Reg = CurDAG->getRegister(MBlaze::R20, MVT::i32); + SDValue InFlag(0, 0); + + if ((isa<GlobalAddressSDNode>(Callee)) || + (isa<ExternalSymbolSDNode>(Callee))) + { + /// Direct call for global addresses and external symbols + SDValue GPReg = CurDAG->getRegister(MBlaze::R15, MVT::i32); + + // Use load to get GOT target + SDValue Ops[] = { Callee, GPReg, Chain }; + SDValue Load = SDValue(CurDAG->getMachineNode(MBlaze::LW, dl, + MVT::i32, MVT::Other, Ops, 3), 0); + Chain = Load.getValue(1); + + // Call target must be on T9 + Chain = CurDAG->getCopyToReg(Chain, dl, R20Reg, Load, InFlag); + } else + /// Indirect call + Chain = CurDAG->getCopyToReg(Chain, dl, R20Reg, Callee, InFlag); + + // Emit Jump and Link Register + SDNode *ResNode = CurDAG->getMachineNode(MBlaze::BRLID, dl, MVT::Other, + MVT::Glue, R20Reg, Chain); + Chain = SDValue(ResNode, 0); + InFlag = SDValue(ResNode, 1); + ReplaceUses(SDValue(Node, 0), Chain); + ReplaceUses(SDValue(Node, 1), InFlag); + return ResNode; + } + } + } + + // Select the default instruction + SDNode *ResNode = SelectCode(Node); + + DEBUG(errs() << "=> "); + if (ResNode == NULL || ResNode == Node) + DEBUG(Node->dump(CurDAG)); + else + DEBUG(ResNode->dump(CurDAG)); + DEBUG(errs() << "\n"); + return ResNode; +} + +/// createMBlazeISelDag - This pass converts a legalized DAG into a +/// MBlaze-specific DAG, ready for instruction scheduling. +FunctionPass *llvm::createMBlazeISelDag(MBlazeTargetMachine &TM) { + return new MBlazeDAGToDAGISel(TM); +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeISelLowering.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeISelLowering.cpp new file mode 100644 index 0000000..310c25e --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeISelLowering.cpp @@ -0,0 +1,1154 @@ +//===-- MBlazeISelLowering.cpp - MBlaze DAG Lowering Implementation -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that MBlaze uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mblaze-lower" +#include "MBlazeISelLowering.h" +#include "MBlazeMachineFunction.h" +#include "MBlazeTargetMachine.h" +#include "MBlazeTargetObjectFile.h" +#include "MBlazeSubtarget.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Intrinsics.h" +#include "llvm/CallingConv.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +static bool CC_MBlaze_AssignReg(unsigned &ValNo, MVT &ValVT, MVT &LocVT, + CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, + CCState &State); + +const char *MBlazeTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + case MBlazeISD::JmpLink : return "MBlazeISD::JmpLink"; + case MBlazeISD::GPRel : return "MBlazeISD::GPRel"; + case MBlazeISD::Wrap : return "MBlazeISD::Wrap"; + case MBlazeISD::ICmp : return "MBlazeISD::ICmp"; + case MBlazeISD::Ret : return "MBlazeISD::Ret"; + case MBlazeISD::Select_CC : return "MBlazeISD::Select_CC"; + default : return NULL; + } +} + +MBlazeTargetLowering::MBlazeTargetLowering(MBlazeTargetMachine &TM) + : TargetLowering(TM, new MBlazeTargetObjectFile()) { + Subtarget = &TM.getSubtarget<MBlazeSubtarget>(); + + // MBlaze does not have i1 type, so use i32 for + // setcc operations results (slt, sgt, ...). + setBooleanContents(ZeroOrOneBooleanContent); + setBooleanVectorContents(ZeroOrOneBooleanContent); // FIXME: Is this correct? + + // Set up the register classes + addRegisterClass(MVT::i32, &MBlaze::GPRRegClass); + if (Subtarget->hasFPU()) { + addRegisterClass(MVT::f32, &MBlaze::GPRRegClass); + setOperationAction(ISD::ConstantFP, MVT::f32, Legal); + } + + // Floating point operations which are not supported + setOperationAction(ISD::FREM, MVT::f32, Expand); + setOperationAction(ISD::FMA, MVT::f32, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i8, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i16, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand); + setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand); + setOperationAction(ISD::FP_ROUND, MVT::f32, Expand); + setOperationAction(ISD::FP_ROUND, MVT::f64, Expand); + setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand); + setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand); + setOperationAction(ISD::FSIN, MVT::f32, Expand); + setOperationAction(ISD::FCOS, MVT::f32, Expand); + setOperationAction(ISD::FPOWI, MVT::f32, Expand); + setOperationAction(ISD::FPOW, MVT::f32, Expand); + setOperationAction(ISD::FLOG, MVT::f32, Expand); + setOperationAction(ISD::FLOG2, MVT::f32, Expand); + setOperationAction(ISD::FLOG10, MVT::f32, Expand); + setOperationAction(ISD::FEXP, MVT::f32, Expand); + + // Load extented operations for i1 types must be promoted + setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); + + // Sign extended loads must be expanded + setLoadExtAction(ISD::SEXTLOAD, MVT::i8, Expand); + setLoadExtAction(ISD::SEXTLOAD, MVT::i16, Expand); + + // MBlaze has no REM or DIVREM operations. + setOperationAction(ISD::UREM, MVT::i32, Expand); + setOperationAction(ISD::SREM, MVT::i32, Expand); + setOperationAction(ISD::SDIVREM, MVT::i32, Expand); + setOperationAction(ISD::UDIVREM, MVT::i32, Expand); + + // If the processor doesn't support multiply then expand it + if (!Subtarget->hasMul()) { + setOperationAction(ISD::MUL, MVT::i32, Expand); + } + + // If the processor doesn't support 64-bit multiply then expand + if (!Subtarget->hasMul() || !Subtarget->hasMul64()) { + setOperationAction(ISD::MULHS, MVT::i32, Expand); + setOperationAction(ISD::MULHS, MVT::i64, Expand); + setOperationAction(ISD::MULHU, MVT::i32, Expand); + setOperationAction(ISD::MULHU, MVT::i64, Expand); + } + + // If the processor doesn't support division then expand + if (!Subtarget->hasDiv()) { + setOperationAction(ISD::UDIV, MVT::i32, Expand); + setOperationAction(ISD::SDIV, MVT::i32, Expand); + } + + // Expand unsupported conversions + setOperationAction(ISD::BITCAST, MVT::f32, Expand); + setOperationAction(ISD::BITCAST, MVT::i32, Expand); + + // Expand SELECT_CC + setOperationAction(ISD::SELECT_CC, MVT::Other, Expand); + + // MBlaze doesn't have MUL_LOHI + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand); + + // Used by legalize types to correctly generate the setcc result. + // Without this, every float setcc comes with a AND/OR with the result, + // we don't want this, since the fpcmp result goes to a flag register, + // which is used implicitly by brcond and select operations. + AddPromotedToType(ISD::SETCC, MVT::i1, MVT::i32); + AddPromotedToType(ISD::SELECT, MVT::i1, MVT::i32); + AddPromotedToType(ISD::SELECT_CC, MVT::i1, MVT::i32); + + // MBlaze Custom Operations + setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); + setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom); + setOperationAction(ISD::JumpTable, MVT::i32, Custom); + setOperationAction(ISD::ConstantPool, MVT::i32, Custom); + + // Variable Argument support + setOperationAction(ISD::VASTART, MVT::Other, Custom); + setOperationAction(ISD::VAEND, MVT::Other, Expand); + setOperationAction(ISD::VAARG, MVT::Other, Expand); + setOperationAction(ISD::VACOPY, MVT::Other, Expand); + + + // Operations not directly supported by MBlaze. + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::BR_CC, MVT::Other, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + setOperationAction(ISD::ROTL, MVT::i32, Expand); + setOperationAction(ISD::ROTR, MVT::i32, Expand); + setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand); + setOperationAction(ISD::CTLZ, MVT::i32, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction(ISD::CTTZ, MVT::i32, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction(ISD::CTPOP, MVT::i32, Expand); + setOperationAction(ISD::BSWAP, MVT::i32, Expand); + + // We don't have line number support yet. + setOperationAction(ISD::EH_LABEL, MVT::Other, Expand); + + // Use the default for now + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + + // MBlaze doesn't have extending float->double load/store + setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand); + setTruncStoreAction(MVT::f64, MVT::f32, Expand); + + setMinFunctionAlignment(2); + + setStackPointerRegisterToSaveRestore(MBlaze::R1); + computeRegisterProperties(); +} + +EVT MBlazeTargetLowering::getSetCCResultType(EVT VT) const { + return MVT::i32; +} + +SDValue MBlazeTargetLowering::LowerOperation(SDValue Op, + SelectionDAG &DAG) const { + switch (Op.getOpcode()) + { + case ISD::ConstantPool: return LowerConstantPool(Op, DAG); + case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); + case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); + case ISD::JumpTable: return LowerJumpTable(Op, DAG); + case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); + case ISD::VASTART: return LowerVASTART(Op, DAG); + } + return SDValue(); +} + +//===----------------------------------------------------------------------===// +// Lower helper functions +//===----------------------------------------------------------------------===// +MachineBasicBlock* +MBlazeTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) + const { + switch (MI->getOpcode()) { + default: llvm_unreachable("Unexpected instr type to insert"); + + case MBlaze::ShiftRL: + case MBlaze::ShiftRA: + case MBlaze::ShiftL: + return EmitCustomShift(MI, MBB); + + case MBlaze::Select_FCC: + case MBlaze::Select_CC: + return EmitCustomSelect(MI, MBB); + + case MBlaze::CAS32: + case MBlaze::SWP32: + case MBlaze::LAA32: + case MBlaze::LAS32: + case MBlaze::LAD32: + case MBlaze::LAO32: + case MBlaze::LAX32: + case MBlaze::LAN32: + return EmitCustomAtomic(MI, MBB); + + case MBlaze::MEMBARRIER: + // The Microblaze does not need memory barriers. Just delete the pseudo + // instruction and finish. + MI->eraseFromParent(); + return MBB; + } +} + +MachineBasicBlock* +MBlazeTargetLowering::EmitCustomShift(MachineInstr *MI, + MachineBasicBlock *MBB) const { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + DebugLoc dl = MI->getDebugLoc(); + + // To "insert" a shift left instruction, we actually have to insert a + // simple loop. The incoming instruction knows the destination vreg to + // set, the source vreg to operate over and the shift amount. + const BasicBlock *LLVM_BB = MBB->getBasicBlock(); + MachineFunction::iterator It = MBB; + ++It; + + // start: + // andi samt, samt, 31 + // beqid samt, finish + // add dst, src, r0 + // loop: + // addik samt, samt, -1 + // sra dst, dst + // bneid samt, loop + // nop + // finish: + MachineFunction *F = MBB->getParent(); + MachineRegisterInfo &R = F->getRegInfo(); + MachineBasicBlock *loop = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *finish = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, loop); + F->insert(It, finish); + + // Update machine-CFG edges by transferring adding all successors and + // remaining instructions from the current block to the new block which + // will contain the Phi node for the select. + finish->splice(finish->begin(), MBB, + llvm::next(MachineBasicBlock::iterator(MI)), + MBB->end()); + finish->transferSuccessorsAndUpdatePHIs(MBB); + + // Add the true and fallthrough blocks as its successors. + MBB->addSuccessor(loop); + MBB->addSuccessor(finish); + + // Next, add the finish block as a successor of the loop block + loop->addSuccessor(finish); + loop->addSuccessor(loop); + + unsigned IAMT = R.createVirtualRegister(&MBlaze::GPRRegClass); + BuildMI(MBB, dl, TII->get(MBlaze::ANDI), IAMT) + .addReg(MI->getOperand(2).getReg()) + .addImm(31); + + unsigned IVAL = R.createVirtualRegister(&MBlaze::GPRRegClass); + BuildMI(MBB, dl, TII->get(MBlaze::ADDIK), IVAL) + .addReg(MI->getOperand(1).getReg()) + .addImm(0); + + BuildMI(MBB, dl, TII->get(MBlaze::BEQID)) + .addReg(IAMT) + .addMBB(finish); + + unsigned DST = R.createVirtualRegister(&MBlaze::GPRRegClass); + unsigned NDST = R.createVirtualRegister(&MBlaze::GPRRegClass); + BuildMI(loop, dl, TII->get(MBlaze::PHI), DST) + .addReg(IVAL).addMBB(MBB) + .addReg(NDST).addMBB(loop); + + unsigned SAMT = R.createVirtualRegister(&MBlaze::GPRRegClass); + unsigned NAMT = R.createVirtualRegister(&MBlaze::GPRRegClass); + BuildMI(loop, dl, TII->get(MBlaze::PHI), SAMT) + .addReg(IAMT).addMBB(MBB) + .addReg(NAMT).addMBB(loop); + + if (MI->getOpcode() == MBlaze::ShiftL) + BuildMI(loop, dl, TII->get(MBlaze::ADD), NDST).addReg(DST).addReg(DST); + else if (MI->getOpcode() == MBlaze::ShiftRA) + BuildMI(loop, dl, TII->get(MBlaze::SRA), NDST).addReg(DST); + else if (MI->getOpcode() == MBlaze::ShiftRL) + BuildMI(loop, dl, TII->get(MBlaze::SRL), NDST).addReg(DST); + else + llvm_unreachable("Cannot lower unknown shift instruction"); + + BuildMI(loop, dl, TII->get(MBlaze::ADDIK), NAMT) + .addReg(SAMT) + .addImm(-1); + + BuildMI(loop, dl, TII->get(MBlaze::BNEID)) + .addReg(NAMT) + .addMBB(loop); + + BuildMI(*finish, finish->begin(), dl, + TII->get(MBlaze::PHI), MI->getOperand(0).getReg()) + .addReg(IVAL).addMBB(MBB) + .addReg(NDST).addMBB(loop); + + // The pseudo instruction is no longer needed so remove it + MI->eraseFromParent(); + return finish; +} + +MachineBasicBlock* +MBlazeTargetLowering::EmitCustomSelect(MachineInstr *MI, + MachineBasicBlock *MBB) const { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + DebugLoc dl = MI->getDebugLoc(); + + // To "insert" a SELECT_CC instruction, we actually have to insert the + // diamond control-flow pattern. The incoming instruction knows the + // destination vreg to set, the condition code register to branch on, the + // true/false values to select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = MBB->getBasicBlock(); + MachineFunction::iterator It = MBB; + ++It; + + // thisMBB: + // ... + // TrueVal = ... + // setcc r1, r2, r3 + // bNE r1, r0, copy1MBB + // fallthrough --> copy0MBB + MachineFunction *F = MBB->getParent(); + MachineBasicBlock *flsBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *dneBB = F->CreateMachineBasicBlock(LLVM_BB); + + unsigned Opc; + switch (MI->getOperand(4).getImm()) { + default: llvm_unreachable("Unknown branch condition"); + case MBlazeCC::EQ: Opc = MBlaze::BEQID; break; + case MBlazeCC::NE: Opc = MBlaze::BNEID; break; + case MBlazeCC::GT: Opc = MBlaze::BGTID; break; + case MBlazeCC::LT: Opc = MBlaze::BLTID; break; + case MBlazeCC::GE: Opc = MBlaze::BGEID; break; + case MBlazeCC::LE: Opc = MBlaze::BLEID; break; + } + + F->insert(It, flsBB); + F->insert(It, dneBB); + + // Transfer the remainder of MBB and its successor edges to dneBB. + dneBB->splice(dneBB->begin(), MBB, + llvm::next(MachineBasicBlock::iterator(MI)), + MBB->end()); + dneBB->transferSuccessorsAndUpdatePHIs(MBB); + + MBB->addSuccessor(flsBB); + MBB->addSuccessor(dneBB); + flsBB->addSuccessor(dneBB); + + BuildMI(MBB, dl, TII->get(Opc)) + .addReg(MI->getOperand(3).getReg()) + .addMBB(dneBB); + + // sinkMBB: + // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] + // ... + //BuildMI(dneBB, dl, TII->get(MBlaze::PHI), MI->getOperand(0).getReg()) + // .addReg(MI->getOperand(1).getReg()).addMBB(flsBB) + // .addReg(MI->getOperand(2).getReg()).addMBB(BB); + + BuildMI(*dneBB, dneBB->begin(), dl, + TII->get(MBlaze::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()).addMBB(flsBB) + .addReg(MI->getOperand(1).getReg()).addMBB(MBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return dneBB; +} + +MachineBasicBlock* +MBlazeTargetLowering::EmitCustomAtomic(MachineInstr *MI, + MachineBasicBlock *MBB) const { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + DebugLoc dl = MI->getDebugLoc(); + + // All atomic instructions on the Microblaze are implemented using the + // load-linked / store-conditional style atomic instruction sequences. + // Thus, all operations will look something like the following: + // + // start: + // lwx RV, RP, 0 + // <do stuff> + // swx RV, RP, 0 + // addic RC, R0, 0 + // bneid RC, start + // + // exit: + // + // To "insert" a shift left instruction, we actually have to insert a + // simple loop. The incoming instruction knows the destination vreg to + // set, the source vreg to operate over and the shift amount. + const BasicBlock *LLVM_BB = MBB->getBasicBlock(); + MachineFunction::iterator It = MBB; + ++It; + + // start: + // andi samt, samt, 31 + // beqid samt, finish + // add dst, src, r0 + // loop: + // addik samt, samt, -1 + // sra dst, dst + // bneid samt, loop + // nop + // finish: + MachineFunction *F = MBB->getParent(); + MachineRegisterInfo &R = F->getRegInfo(); + + // Create the start and exit basic blocks for the atomic operation + MachineBasicBlock *start = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *exit = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, start); + F->insert(It, exit); + + // Update machine-CFG edges by transferring adding all successors and + // remaining instructions from the current block to the new block which + // will contain the Phi node for the select. + exit->splice(exit->begin(), MBB, llvm::next(MachineBasicBlock::iterator(MI)), + MBB->end()); + exit->transferSuccessorsAndUpdatePHIs(MBB); + + // Add the fallthrough block as its successors. + MBB->addSuccessor(start); + + BuildMI(start, dl, TII->get(MBlaze::LWX), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addReg(MBlaze::R0); + + MachineBasicBlock *final = start; + unsigned finalReg = 0; + + switch (MI->getOpcode()) { + default: llvm_unreachable("Cannot lower unknown atomic instruction!"); + + case MBlaze::SWP32: + finalReg = MI->getOperand(2).getReg(); + start->addSuccessor(exit); + start->addSuccessor(start); + break; + + case MBlaze::LAN32: + case MBlaze::LAX32: + case MBlaze::LAO32: + case MBlaze::LAD32: + case MBlaze::LAS32: + case MBlaze::LAA32: { + unsigned opcode = 0; + switch (MI->getOpcode()) { + default: llvm_unreachable("Cannot lower unknown atomic load!"); + case MBlaze::LAA32: opcode = MBlaze::ADDIK; break; + case MBlaze::LAS32: opcode = MBlaze::RSUBIK; break; + case MBlaze::LAD32: opcode = MBlaze::AND; break; + case MBlaze::LAO32: opcode = MBlaze::OR; break; + case MBlaze::LAX32: opcode = MBlaze::XOR; break; + case MBlaze::LAN32: opcode = MBlaze::AND; break; + } + + finalReg = R.createVirtualRegister(&MBlaze::GPRRegClass); + start->addSuccessor(exit); + start->addSuccessor(start); + + BuildMI(start, dl, TII->get(opcode), finalReg) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()); + + if (MI->getOpcode() == MBlaze::LAN32) { + unsigned tmp = finalReg; + finalReg = R.createVirtualRegister(&MBlaze::GPRRegClass); + BuildMI(start, dl, TII->get(MBlaze::XORI), finalReg) + .addReg(tmp) + .addImm(-1); + } + break; + } + + case MBlaze::CAS32: { + finalReg = MI->getOperand(3).getReg(); + final = F->CreateMachineBasicBlock(LLVM_BB); + + F->insert(It, final); + start->addSuccessor(exit); + start->addSuccessor(final); + final->addSuccessor(exit); + final->addSuccessor(start); + + unsigned CMP = R.createVirtualRegister(&MBlaze::GPRRegClass); + BuildMI(start, dl, TII->get(MBlaze::CMP), CMP) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()); + + BuildMI(start, dl, TII->get(MBlaze::BNEID)) + .addReg(CMP) + .addMBB(exit); + + final->moveAfter(start); + exit->moveAfter(final); + break; + } + } + + unsigned CHK = R.createVirtualRegister(&MBlaze::GPRRegClass); + BuildMI(final, dl, TII->get(MBlaze::SWX)) + .addReg(finalReg) + .addReg(MI->getOperand(1).getReg()) + .addReg(MBlaze::R0); + + BuildMI(final, dl, TII->get(MBlaze::ADDIC), CHK) + .addReg(MBlaze::R0) + .addImm(0); + + BuildMI(final, dl, TII->get(MBlaze::BNEID)) + .addReg(CHK) + .addMBB(start); + + // The pseudo instruction is no longer needed so remove it + MI->eraseFromParent(); + return exit; +} + +//===----------------------------------------------------------------------===// +// Misc Lower Operation implementation +//===----------------------------------------------------------------------===// +// + +SDValue MBlazeTargetLowering::LowerSELECT_CC(SDValue Op, + SelectionDAG &DAG) const { + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + SDValue TrueVal = Op.getOperand(2); + SDValue FalseVal = Op.getOperand(3); + DebugLoc dl = Op.getDebugLoc(); + unsigned Opc; + + SDValue CompareFlag; + if (LHS.getValueType() == MVT::i32) { + Opc = MBlazeISD::Select_CC; + CompareFlag = DAG.getNode(MBlazeISD::ICmp, dl, MVT::i32, LHS, RHS) + .getValue(1); + } else { + llvm_unreachable("Cannot lower select_cc with unknown type"); + } + + return DAG.getNode(Opc, dl, TrueVal.getValueType(), TrueVal, FalseVal, + CompareFlag); +} + +SDValue MBlazeTargetLowering:: +LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const { + // FIXME there isn't actually debug info here + DebugLoc dl = Op.getDebugLoc(); + const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); + SDValue GA = DAG.getTargetGlobalAddress(GV, dl, MVT::i32); + + return DAG.getNode(MBlazeISD::Wrap, dl, MVT::i32, GA); +} + +SDValue MBlazeTargetLowering:: +LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { + llvm_unreachable("TLS not implemented for MicroBlaze."); +} + +SDValue MBlazeTargetLowering:: +LowerJumpTable(SDValue Op, SelectionDAG &DAG) const { + SDValue ResNode; + SDValue HiPart; + // FIXME there isn't actually debug info here + DebugLoc dl = Op.getDebugLoc(); + + EVT PtrVT = Op.getValueType(); + JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); + + SDValue JTI = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, 0); + return DAG.getNode(MBlazeISD::Wrap, dl, MVT::i32, JTI); +} + +SDValue MBlazeTargetLowering:: +LowerConstantPool(SDValue Op, SelectionDAG &DAG) const { + SDValue ResNode; + ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); + const Constant *C = N->getConstVal(); + DebugLoc dl = Op.getDebugLoc(); + + SDValue CP = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), + N->getOffset(), 0); + return DAG.getNode(MBlazeISD::Wrap, dl, MVT::i32, CP); +} + +SDValue MBlazeTargetLowering::LowerVASTART(SDValue Op, + SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + MBlazeFunctionInfo *FuncInfo = MF.getInfo<MBlazeFunctionInfo>(); + + DebugLoc dl = Op.getDebugLoc(); + SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), + getPointerTy()); + + // vastart just stores the address of the VarArgsFrameIndex slot into the + // memory location argument. + const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); + return DAG.getStore(Op.getOperand(0), dl, FI, Op.getOperand(1), + MachinePointerInfo(SV), + false, false, 0); +} + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +//===----------------------------------------------------------------------===// + +#include "MBlazeGenCallingConv.inc" + +static bool CC_MBlaze_AssignReg(unsigned &ValNo, MVT &ValVT, MVT &LocVT, + CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, + CCState &State) { + static const uint16_t ArgRegs[] = { + MBlaze::R5, MBlaze::R6, MBlaze::R7, + MBlaze::R8, MBlaze::R9, MBlaze::R10 + }; + + const unsigned NumArgRegs = array_lengthof(ArgRegs); + unsigned Reg = State.AllocateReg(ArgRegs, NumArgRegs); + if (!Reg) return false; + + unsigned SizeInBytes = ValVT.getSizeInBits() >> 3; + State.AllocateStack(SizeInBytes, SizeInBytes); + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + + return true; +} + +//===----------------------------------------------------------------------===// +// Call Calling Convention Implementation +//===----------------------------------------------------------------------===// + +/// LowerCall - functions arguments are copied from virtual regs to +/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. +/// TODO: isVarArg, isTailCall. +SDValue MBlazeTargetLowering:: +LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl<SDValue> &InVals) const { + SelectionDAG &DAG = CLI.DAG; + DebugLoc &dl = CLI.DL; + SmallVector<ISD::OutputArg, 32> &Outs = CLI.Outs; + SmallVector<SDValue, 32> &OutVals = CLI.OutVals; + SmallVector<ISD::InputArg, 32> &Ins = CLI.Ins; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + bool &isTailCall = CLI.IsTailCall; + CallingConv::ID CallConv = CLI.CallConv; + bool isVarArg = CLI.IsVarArg; + + // MBlaze does not yet support tail call optimization + isTailCall = false; + + // The MBlaze requires stack slots for arguments passed to var arg + // functions even if they are passed in registers. + bool needsRegArgSlots = isVarArg; + + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const TargetFrameLowering &TFI = *MF.getTarget().getFrameLowering(); + + // Analyze operands of the call, assigning locations to each operand. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), + getTargetMachine(), ArgLocs, *DAG.getContext()); + CCInfo.AnalyzeCallOperands(Outs, CC_MBlaze); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NumBytes = CCInfo.getNextStackOffset(); + + // Variable argument function calls require a minimum of 24-bytes of stack + if (isVarArg && NumBytes < 24) NumBytes = 24; + + Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(NumBytes, true)); + + SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass; + SmallVector<SDValue, 8> MemOpChains; + + // Walk the register/memloc assignments, inserting copies/loads. + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + MVT RegVT = VA.getLocVT(); + SDValue Arg = OutVals[i]; + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: break; + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, RegVT, Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, RegVT, Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, dl, RegVT, Arg); + break; + } + + // Arguments that can be passed on register must be kept at + // RegsToPass vector + if (VA.isRegLoc()) { + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + } else { + // Register can't get to this point... + assert(VA.isMemLoc()); + + // Since we are alread passing values on the stack we don't + // need to worry about creating additional slots for the + // values passed via registers. + needsRegArgSlots = false; + + // Create the frame index object for this incoming parameter + unsigned ArgSize = VA.getValVT().getSizeInBits()/8; + unsigned StackLoc = VA.getLocMemOffset() + 4; + int FI = MFI->CreateFixedObject(ArgSize, StackLoc, true); + + SDValue PtrOff = DAG.getFrameIndex(FI,getPointerTy()); + + // emit ISD::STORE whichs stores the + // parameter value to a stack Location + MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, + MachinePointerInfo(), + false, false, 0)); + } + } + + // If we need to reserve stack space for the arguments passed via registers + // then create a fixed stack object at the beginning of the stack. + if (needsRegArgSlots && TFI.hasReservedCallFrame(MF)) + MFI->CreateFixedObject(28,0,true); + + // Transform all store nodes into one single node because all store + // nodes are independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + &MemOpChains[0], MemOpChains.size()); + + // Build a sequence of copy-to-reg nodes chained together with token + // chain and flag operands which copy the outgoing args into registers. + // The InFlag in necessary since all emitted instructions must be + // stuck together. + SDValue InFlag; + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, + RegsToPass[i].second, InFlag); + InFlag = Chain.getValue(1); + } + + // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every + // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol + // node so that legalize doesn't hack it. + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, + getPointerTy(), 0, 0); + else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) + Callee = DAG.getTargetExternalSymbol(S->getSymbol(), + getPointerTy(), 0); + + // MBlazeJmpLink = #chain, #target_address, #opt_in_flags... + // = Chain, Callee, Reg#1, Reg#2, ... + // + // Returns a chain & a flag for retval copy to use. + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + SmallVector<SDValue, 8> Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + // Add argument registers to the end of the list so that they are + // known live into the call. + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Ops.push_back(DAG.getRegister(RegsToPass[i].first, + RegsToPass[i].second.getValueType())); + } + + if (InFlag.getNode()) + Ops.push_back(InFlag); + + Chain = DAG.getNode(MBlazeISD::JmpLink, dl, NodeTys, &Ops[0], Ops.size()); + InFlag = Chain.getValue(1); + + // Create the CALLSEQ_END node. + Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, true), + DAG.getIntPtrConstant(0, true), InFlag); + if (!Ins.empty()) + InFlag = Chain.getValue(1); + + // Handle result values, copying them out of physregs into vregs that we + // return. + return LowerCallResult(Chain, InFlag, CallConv, isVarArg, + Ins, dl, DAG, InVals); +} + +/// LowerCallResult - Lower the result values of a call into the +/// appropriate copies out of appropriate physical registers. +SDValue MBlazeTargetLowering:: +LowerCallResult(SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, + bool isVarArg, const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + // Assign locations to each value returned by this call. + SmallVector<CCValAssign, 16> RVLocs; + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), + getTargetMachine(), RVLocs, *DAG.getContext()); + + CCInfo.AnalyzeCallResult(Ins, RetCC_MBlaze); + + // Copy all of the result registers out of their specified physreg. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + Chain = DAG.getCopyFromReg(Chain, dl, RVLocs[i].getLocReg(), + RVLocs[i].getValVT(), InFlag).getValue(1); + InFlag = Chain.getValue(2); + InVals.push_back(Chain.getValue(0)); + } + + return Chain; +} + +//===----------------------------------------------------------------------===// +// Formal Arguments Calling Convention Implementation +//===----------------------------------------------------------------------===// + +/// LowerFormalArguments - transform physical registers into +/// virtual registers and generate load operations for +/// arguments places on the stack. +SDValue MBlazeTargetLowering:: +LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + + unsigned StackReg = MF.getTarget().getRegisterInfo()->getFrameRegister(MF); + MBlazeFI->setVarArgsFrameIndex(0); + + // Used with vargs to acumulate store chains. + std::vector<SDValue> OutChains; + + // Keep track of the last register used for arguments + unsigned ArgRegEnd = 0; + + // Assign locations to all of the incoming arguments. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), + getTargetMachine(), ArgLocs, *DAG.getContext()); + + CCInfo.AnalyzeFormalArguments(Ins, CC_MBlaze); + SDValue StackPtr; + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + + // Arguments stored on registers + if (VA.isRegLoc()) { + MVT RegVT = VA.getLocVT(); + ArgRegEnd = VA.getLocReg(); + const TargetRegisterClass *RC; + + if (RegVT == MVT::i32) + RC = &MBlaze::GPRRegClass; + else if (RegVT == MVT::f32) + RC = &MBlaze::GPRRegClass; + else + llvm_unreachable("RegVT not supported by LowerFormalArguments"); + + // Transform the arguments stored on + // physical registers into virtual ones + unsigned Reg = MF.addLiveIn(ArgRegEnd, RC); + SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, RegVT); + + // If this is an 8 or 16-bit value, it has been passed promoted + // to 32 bits. Insert an assert[sz]ext to capture this, then + // truncate to the right size. If if is a floating point value + // then convert to the correct type. + if (VA.getLocInfo() != CCValAssign::Full) { + unsigned Opcode = 0; + if (VA.getLocInfo() == CCValAssign::SExt) + Opcode = ISD::AssertSext; + else if (VA.getLocInfo() == CCValAssign::ZExt) + Opcode = ISD::AssertZext; + if (Opcode) + ArgValue = DAG.getNode(Opcode, dl, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); + } + + InVals.push_back(ArgValue); + } else { // VA.isRegLoc() + // sanity check + assert(VA.isMemLoc()); + + // The last argument is not a register + ArgRegEnd = 0; + + // The stack pointer offset is relative to the caller stack frame. + // Since the real stack size is unknown here, a negative SPOffset + // is used so there's a way to adjust these offsets when the stack + // size get known (on EliminateFrameIndex). A dummy SPOffset is + // used instead of a direct negative address (which is recorded to + // be used on emitPrologue) to avoid mis-calc of the first stack + // offset on PEI::calculateFrameObjectOffsets. + // Arguments are always 32-bit. + unsigned ArgSize = VA.getLocVT().getSizeInBits()/8; + unsigned StackLoc = VA.getLocMemOffset() + 4; + int FI = MFI->CreateFixedObject(ArgSize, 0, true); + MBlazeFI->recordLoadArgsFI(FI, -StackLoc); + MBlazeFI->recordLiveIn(FI); + + // Create load nodes to retrieve arguments from the stack + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); + InVals.push_back(DAG.getLoad(VA.getValVT(), dl, Chain, FIN, + MachinePointerInfo::getFixedStack(FI), + false, false, false, 0)); + } + } + + // To meet ABI, when VARARGS are passed on registers, the registers + // must have their values written to the caller stack frame. If the last + // argument was placed in the stack, there's no need to save any register. + if ((isVarArg) && ArgRegEnd) { + if (StackPtr.getNode() == 0) + StackPtr = DAG.getRegister(StackReg, getPointerTy()); + + // The last register argument that must be saved is MBlaze::R10 + const TargetRegisterClass *RC = &MBlaze::GPRRegClass; + + unsigned Begin = getMBlazeRegisterNumbering(MBlaze::R5); + unsigned Start = getMBlazeRegisterNumbering(ArgRegEnd+1); + unsigned End = getMBlazeRegisterNumbering(MBlaze::R10); + unsigned StackLoc = Start - Begin + 1; + + for (; Start <= End; ++Start, ++StackLoc) { + unsigned Reg = getMBlazeRegisterFromNumbering(Start); + unsigned LiveReg = MF.addLiveIn(Reg, RC); + SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, LiveReg, MVT::i32); + + int FI = MFI->CreateFixedObject(4, 0, true); + MBlazeFI->recordStoreVarArgsFI(FI, -(StackLoc*4)); + SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy()); + OutChains.push_back(DAG.getStore(Chain, dl, ArgValue, PtrOff, + MachinePointerInfo(), + false, false, 0)); + + // Record the frame index of the first variable argument + // which is a value necessary to VASTART. + if (!MBlazeFI->getVarArgsFrameIndex()) + MBlazeFI->setVarArgsFrameIndex(FI); + } + } + + // All stores are grouped in one node to allow the matching between + // the size of Ins and InVals. This only happens when on varg functions + if (!OutChains.empty()) { + OutChains.push_back(Chain); + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + &OutChains[0], OutChains.size()); + } + + return Chain; +} + +//===----------------------------------------------------------------------===// +// Return Value Calling Convention Implementation +//===----------------------------------------------------------------------===// + +SDValue MBlazeTargetLowering:: +LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + DebugLoc dl, SelectionDAG &DAG) const { + // CCValAssign - represent the assignment of + // the return value to a location + SmallVector<CCValAssign, 16> RVLocs; + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), + getTargetMachine(), RVLocs, *DAG.getContext()); + + // Analize return values. + CCInfo.AnalyzeReturn(Outs, RetCC_MBlaze); + + // If this is the first return lowered for this function, add + // the regs to the liveout set for the function. + if (DAG.getMachineFunction().getRegInfo().liveout_empty()) { + for (unsigned i = 0; i != RVLocs.size(); ++i) + if (RVLocs[i].isRegLoc()) + DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg()); + } + + SDValue Flag; + + // Copy the result values into the output registers. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), + OutVals[i], Flag); + + // guarantee that all emitted copies are + // stuck together, avoiding something bad + Flag = Chain.getValue(1); + } + + // If this function is using the interrupt_handler calling convention + // then use "rtid r14, 0" otherwise use "rtsd r15, 8" + unsigned Ret = (CallConv == CallingConv::MBLAZE_INTR) ? MBlazeISD::IRet + : MBlazeISD::Ret; + unsigned Reg = (CallConv == CallingConv::MBLAZE_INTR) ? MBlaze::R14 + : MBlaze::R15; + SDValue DReg = DAG.getRegister(Reg, MVT::i32); + + if (Flag.getNode()) + return DAG.getNode(Ret, dl, MVT::Other, Chain, DReg, Flag); + + return DAG.getNode(Ret, dl, MVT::Other, Chain, DReg); +} + +//===----------------------------------------------------------------------===// +// MBlaze Inline Assembly Support +//===----------------------------------------------------------------------===// + +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target. +MBlazeTargetLowering::ConstraintType MBlazeTargetLowering:: +getConstraintType(const std::string &Constraint) const +{ + // MBlaze specific constrainy + // + // 'd' : An address register. Equivalent to r. + // 'y' : Equivalent to r; retained for + // backwards compatibility. + // 'f' : Floating Point registers. + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default : break; + case 'd': + case 'y': + case 'f': + return C_RegisterClass; + } + } + return TargetLowering::getConstraintType(Constraint); +} + +/// Examine constraint type and operand type and determine a weight value. +/// This object must already have been set up with the operand type +/// and the current alternative constraint selected. +TargetLowering::ConstraintWeight +MBlazeTargetLowering::getSingleConstraintMatchWeight( + AsmOperandInfo &info, const char *constraint) const { + ConstraintWeight weight = CW_Invalid; + Value *CallOperandVal = info.CallOperandVal; + // If we don't have a value, we can't do a match, + // but allow it at the lowest weight. + if (CallOperandVal == NULL) + return CW_Default; + Type *type = CallOperandVal->getType(); + // Look at the constraint type. + switch (*constraint) { + default: + weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint); + break; + case 'd': + case 'y': + if (type->isIntegerTy()) + weight = CW_Register; + break; + case 'f': + if (type->isFloatTy()) + weight = CW_Register; + break; + } + return weight; +} + +/// Given a register class constraint, like 'r', if this corresponds directly +/// to an LLVM register class, return a register of 0 and the register class +/// pointer. +std::pair<unsigned, const TargetRegisterClass*> MBlazeTargetLowering:: +getRegForInlineAsmConstraint(const std::string &Constraint, EVT VT) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + case 'r': + return std::make_pair(0U, &MBlaze::GPRRegClass); + // TODO: These can't possibly be right, but match what was in + // getRegClassForInlineAsmConstraint. + case 'd': + case 'y': + case 'f': + if (VT == MVT::f32) + return std::make_pair(0U, &MBlaze::GPRRegClass); + } + } + return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); +} + +bool MBlazeTargetLowering:: +isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { + // The MBlaze target isn't yet aware of offsets. + return false; +} + +bool MBlazeTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { + return VT != MVT::f32; +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeISelLowering.h b/contrib/llvm/lib/Target/MBlaze/MBlazeISelLowering.h new file mode 100644 index 0000000..a01fab5 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeISelLowering.h @@ -0,0 +1,179 @@ +//===-- MBlazeISelLowering.h - MBlaze DAG Lowering Interface ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that MBlaze uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef MBlazeISELLOWERING_H +#define MBlazeISELLOWERING_H + +#include "MBlaze.h" +#include "MBlazeSubtarget.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Target/TargetLowering.h" + +namespace llvm { + namespace MBlazeCC { + enum CC { + FIRST = 0, + EQ, + NE, + GT, + LT, + GE, + LE + }; + + inline static CC getOppositeCondition(CC cc) { + switch (cc) { + default: llvm_unreachable("Unknown condition code"); + case EQ: return NE; + case NE: return EQ; + case GT: return LE; + case LT: return GE; + case GE: return LT; + case LE: return GE; + } + } + + inline static const char *MBlazeCCToString(CC cc) { + switch (cc) { + default: llvm_unreachable("Unknown condition code"); + case EQ: return "eq"; + case NE: return "ne"; + case GT: return "gt"; + case LT: return "lt"; + case GE: return "ge"; + case LE: return "le"; + } + } + } + + namespace MBlazeISD { + enum NodeType { + // Start the numbering from where ISD NodeType finishes. + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + // Jump and link (call) + JmpLink, + + // Handle gp_rel (small data/bss sections) relocation. + GPRel, + + // Select CC Pseudo Instruction + Select_CC, + + // Wrap up multiple types of instructions + Wrap, + + // Integer Compare + ICmp, + + // Return from subroutine + Ret, + + // Return from interrupt + IRet + }; + } + + //===--------------------------------------------------------------------===// + // TargetLowering Implementation + //===--------------------------------------------------------------------===// + + class MBlazeTargetLowering : public TargetLowering { + public: + explicit MBlazeTargetLowering(MBlazeTargetMachine &TM); + + /// LowerOperation - Provide custom lowering hooks for some operations. + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const; + + /// getTargetNodeName - This method returns the name of a target specific + // DAG node. + virtual const char *getTargetNodeName(unsigned Opcode) const; + + /// getSetCCResultType - get the ISD::SETCC result ValueType + EVT getSetCCResultType(EVT VT) const; + + private: + // Subtarget Info + const MBlazeSubtarget *Subtarget; + + + // Lower Operand helpers + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + // Lower Operand specifics + SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const; + + virtual SDValue + LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + virtual SDValue + LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl<SDValue> &InVals) const; + + virtual SDValue + LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + DebugLoc dl, SelectionDAG &DAG) const; + + virtual MachineBasicBlock* + EmitCustomShift(MachineInstr *MI, MachineBasicBlock *MBB) const; + + virtual MachineBasicBlock* + EmitCustomSelect(MachineInstr *MI, MachineBasicBlock *MBB) const; + + virtual MachineBasicBlock* + EmitCustomAtomic(MachineInstr *MI, MachineBasicBlock *MBB) const; + + virtual MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) const; + + // Inline asm support + ConstraintType getConstraintType(const std::string &Constraint) const; + + /// Examine constraint string and operand type and determine a weight value. + /// The operand object must already have been set up with the operand type. + ConstraintWeight getSingleConstraintMatchWeight( + AsmOperandInfo &info, const char *constraint) const; + + std::pair<unsigned, const TargetRegisterClass*> + getRegForInlineAsmConstraint(const std::string &Constraint, + EVT VT) const; + + virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; + + /// isFPImmLegal - Returns true if the target can instruction select the + /// specified FP immediate natively. If false, the legalizer will + /// materialize the FP immediate as a load from a constant pool. + virtual bool isFPImmLegal(const APFloat &Imm, EVT VT) const; + }; +} + +#endif // MBlazeISELLOWERING_H diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeInstrFPU.td b/contrib/llvm/lib/Target/MBlaze/MBlazeInstrFPU.td new file mode 100644 index 0000000..3f14593 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeInstrFPU.td @@ -0,0 +1,219 @@ +//===-- MBlazeInstrFPU.td - MBlaze FPU Instruction defs ----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MBlaze profiles and nodes +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MBlaze Operand, Complex Patterns and Transformations Definitions. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Memory Access Instructions +//===----------------------------------------------------------------------===// +class LoadFM<bits<6> op, string instr_asm, PatFrag OpNode> : + TA<op, 0x000, (outs GPR:$dst), (ins memrr:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(set (f32 GPR:$dst), (OpNode xaddr:$addr))], IIC_MEMl>; + +class LoadFMI<bits<6> op, string instr_asm, PatFrag OpNode> : + TB<op, (outs GPR:$dst), (ins memri:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(set (f32 GPR:$dst), (OpNode iaddr:$addr))], IIC_MEMl>; + +class StoreFM<bits<6> op, string instr_asm, PatFrag OpNode> : + TA<op, 0x000, (outs), (ins GPR:$dst, memrr:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(OpNode (f32 GPR:$dst), xaddr:$addr)], IIC_MEMs>; + +class StoreFMI<bits<6> op, string instr_asm, PatFrag OpNode> : + TB<op, (outs), (ins GPR:$dst, memrr:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(OpNode (f32 GPR:$dst), iaddr:$addr)], IIC_MEMs>; + +class ArithF<bits<6> op, bits<11> flags, string instr_asm, SDNode OpNode, + InstrItinClass itin> : + TA<op, flags, (outs GPR:$dst), (ins GPR:$b, GPR:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set GPR:$dst, (OpNode GPR:$b, GPR:$c))], itin>; + +class CmpFN<bits<6> op, bits<11> flags, string instr_asm, + InstrItinClass itin> : + TA<op, flags, (outs GPR:$dst), (ins GPR:$b, GPR:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [], itin>; + +class ArithFR<bits<6> op, bits<11> flags, string instr_asm, SDNode OpNode, + InstrItinClass itin> : + TAR<op, flags, (outs GPR:$dst), (ins GPR:$b, GPR:$c), + !strconcat(instr_asm, " $dst, $c, $b"), + [(set GPR:$dst, (OpNode GPR:$b, GPR:$c))], itin>; + +class LogicFI<bits<6> op, string instr_asm> : + TB<op, (outs GPR:$dst), (ins GPR:$b, fimm:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [], IIC_ALU>; + +let rb=0 in { + class ArithF2<bits<6> op, bits<11> flags, string instr_asm, + InstrItinClass itin> : + TA<op, flags, (outs GPR:$dst), (ins GPR:$b), + !strconcat(instr_asm, " $dst, $b"), + [], itin>; + + class ArithIF<bits<6> op, bits<11> flags, string instr_asm, + InstrItinClass itin> : + TA<op, flags, (outs GPR:$dst), (ins GPR:$b), + !strconcat(instr_asm, " $dst, $b"), + [], itin>; + + class ArithFI<bits<6> op, bits<11> flags, string instr_asm, + InstrItinClass itin> : + TA<op, flags, (outs GPR:$dst), (ins GPR:$b), + !strconcat(instr_asm, " $dst, $b"), + [], itin>; +} + +//===----------------------------------------------------------------------===// +// Pseudo instructions +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// FPU Arithmetic Instructions +//===----------------------------------------------------------------------===// +let Predicates=[HasFPU] in { + def FORI : LogicFI<0x28, "ori ">; + def FADD : ArithF<0x16, 0x000, "fadd ", fadd, IIC_FPU>; + def FRSUB : ArithFR<0x16, 0x080, "frsub ", fsub, IIC_FPU>; + def FMUL : ArithF<0x16, 0x100, "fmul ", fmul, IIC_FPU>; + def FDIV : ArithF<0x16, 0x180, "fdiv ", fdiv, IIC_FPUd>; +} + +let Predicates=[HasFPU], isCodeGenOnly=1 in { + def LWF : LoadFM<0x32, "lw ", load>; + def LWFI : LoadFMI<0x3A, "lwi ", load>; + + def SWF : StoreFM<0x36, "sw ", store>; + def SWFI : StoreFMI<0x3E, "swi ", store>; +} + +let Predicates=[HasFPU,HasSqrt] in { + def FLT : ArithIF<0x16, 0x280, "flt ", IIC_FPUf>; + def FINT : ArithFI<0x16, 0x300, "fint ", IIC_FPUi>; + def FSQRT : ArithF2<0x16, 0x380, "fsqrt ", IIC_FPUs>; +} + +let isAsCheapAsAMove = 1 in { + def FCMP_UN : CmpFN<0x16, 0x200, "fcmp.un", IIC_FPUc>; + def FCMP_LT : CmpFN<0x16, 0x210, "fcmp.lt", IIC_FPUc>; + def FCMP_EQ : CmpFN<0x16, 0x220, "fcmp.eq", IIC_FPUc>; + def FCMP_LE : CmpFN<0x16, 0x230, "fcmp.le", IIC_FPUc>; + def FCMP_GT : CmpFN<0x16, 0x240, "fcmp.gt", IIC_FPUc>; + def FCMP_NE : CmpFN<0x16, 0x250, "fcmp.ne", IIC_FPUc>; + def FCMP_GE : CmpFN<0x16, 0x260, "fcmp.ge", IIC_FPUc>; +} + + +let usesCustomInserter = 1 in { + def Select_FCC : MBlazePseudo<(outs GPR:$dst), + (ins GPR:$T, GPR:$F, GPR:$CMP, i32imm:$CC), + "; SELECT_FCC PSEUDO!", + []>; +} + +// Floating point conversions +let Predicates=[HasFPU] in { + def : Pat<(sint_to_fp GPR:$V), (FLT GPR:$V)>; + def : Pat<(fp_to_sint GPR:$V), (FINT GPR:$V)>; + def : Pat<(fsqrt GPR:$V), (FSQRT GPR:$V)>; +} + +// SET_CC operations +let Predicates=[HasFPU] in { + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETEQ), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_EQ GPR:$L, GPR:$R), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETNE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_EQ GPR:$L, GPR:$R), 1)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETOEQ), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_EQ GPR:$L, GPR:$R), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETONE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (XOR (FCMP_UN GPR:$L, GPR:$R), + (FCMP_EQ GPR:$L, GPR:$R)), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETONE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (OR (FCMP_UN GPR:$L, GPR:$R), + (FCMP_EQ GPR:$L, GPR:$R)), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETGT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_GT GPR:$L, GPR:$R), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETLT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_LT GPR:$L, GPR:$R), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETGE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_GE GPR:$L, GPR:$R), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETLE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_LE GPR:$L, GPR:$R), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETOGT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_GT GPR:$L, GPR:$R), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETOLT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_LT GPR:$L, GPR:$R), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETOGE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_GE GPR:$L, GPR:$R), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETOLE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_LE GPR:$L, GPR:$R), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETUEQ), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (OR (FCMP_UN GPR:$L, GPR:$R), + (FCMP_EQ GPR:$L, GPR:$R)), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETUNE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_NE GPR:$L, GPR:$R), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETUGT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (OR (FCMP_UN GPR:$L, GPR:$R), + (FCMP_GT GPR:$L, GPR:$R)), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETULT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (OR (FCMP_UN GPR:$L, GPR:$R), + (FCMP_LT GPR:$L, GPR:$R)), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETUGE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (OR (FCMP_UN GPR:$L, GPR:$R), + (FCMP_GE GPR:$L, GPR:$R)), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETULE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (OR (FCMP_UN GPR:$L, GPR:$R), + (FCMP_LE GPR:$L, GPR:$R)), 2)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETO), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_UN GPR:$L, GPR:$R), 1)>; + def : Pat<(setcc (f32 GPR:$L), (f32 GPR:$R), SETUO), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (FCMP_UN GPR:$L, GPR:$R), 2)>; +} + +// SELECT operations +def : Pat<(select (i32 GPR:$C), (f32 GPR:$T), (f32 GPR:$F)), + (Select_FCC GPR:$T, GPR:$F, GPR:$C, 2)>; + +//===----------------------------------------------------------------------===// +// Patterns for Floating Point Instructions +//===----------------------------------------------------------------------===// +def : Pat<(f32 fpimm:$imm), (FORI (i32 R0), fpimm:$imm)>; diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeInstrFSL.td b/contrib/llvm/lib/Target/MBlaze/MBlazeInstrFSL.td new file mode 100644 index 0000000..91b69de --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeInstrFSL.td @@ -0,0 +1,229 @@ +//===-- MBlazeInstrFSL.td - MBlaze FSL Instruction defs ----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// FSL Instruction Formats +//===----------------------------------------------------------------------===// +class FSLGet<bits<6> op, bits<5> flags, string instr_asm, Intrinsic OpNode> : + MBlazeInst<op, FRCX, (outs GPR:$dst), (ins fslimm:$b), + !strconcat(instr_asm, " $dst, $b"), + [(set GPR:$dst, (OpNode immZExt4:$b))],IIC_FSLg> +{ + bits<5> rd; + bits<4> fslno; + + let Inst{6-10} = rd; + let Inst{11-15} = 0x0; + let Inst{16} = 0x0; + let Inst{17-21} = flags; // NCTAE + let Inst{22-27} = 0x0; + let Inst{28-31} = fslno; +} + +class FSLGetD<bits<6> op, bits<5> flags, string instr_asm, Intrinsic OpNode> : + MBlazeInst<op, FRCR, (outs GPR:$dst), (ins GPR:$b), + !strconcat(instr_asm, " $dst, $b"), + [(set GPR:$dst, (OpNode GPR:$b))], IIC_FSLg> +{ + bits<5> rd; + bits<5> rb; + + let Inst{6-10} = rd; + let Inst{11-15} = 0x0; + let Inst{16-20} = rb; + let Inst{21} = 0x0; + let Inst{22-26} = flags; // NCTAE + let Inst{27-31} = 0x0; +} + +class FSLPut<bits<6> op, bits<4> flags, string instr_asm, Intrinsic OpNode> : + MBlazeInst<op, FCRCX, (outs), (ins GPR:$v, fslimm:$b), + !strconcat(instr_asm, " $v, $b"), + [(OpNode GPR:$v, immZExt4:$b)], IIC_FSLp> +{ + bits<5> ra; + bits<4> fslno; + + let Inst{6-10} = 0x0; + let Inst{11-15} = ra; + let Inst{16} = 0x1; + let Inst{17-20} = flags; // NCTA + let Inst{21-27} = 0x0; + let Inst{28-31} = fslno; +} + +class FSLPutD<bits<6> op, bits<4> flags, string instr_asm, Intrinsic OpNode> : + MBlazeInst<op, FCRR, (outs), (ins GPR:$v, GPR:$b), + !strconcat(instr_asm, " $v, $b"), + [(OpNode GPR:$v, GPR:$b)], IIC_FSLp> +{ + bits<5> ra; + bits<5> rb; + + let Inst{6-10} = 0x0; + let Inst{11-15} = ra; + let Inst{16-20} = rb; + let Inst{21} = 0x1; + let Inst{22-25} = flags; // NCTA + let Inst{26-31} = 0x0; +} + +class FSLPutT<bits<6> op, bits<4> flags, string instr_asm, Intrinsic OpNode> : + MBlazeInst<op, FCX, (outs), (ins fslimm:$b), + !strconcat(instr_asm, " $b"), + [(OpNode immZExt4:$b)], IIC_FSLp> +{ + bits<4> fslno; + + let Inst{6-10} = 0x0; + let Inst{11-15} = 0x0; + let Inst{16} = 0x1; + let Inst{17-20} = flags; // NCTA + let Inst{21-27} = 0x0; + let Inst{28-31} = fslno; +} + +class FSLPutTD<bits<6> op, bits<4> flags, string instr_asm, Intrinsic OpNode> : + MBlazeInst<op, FCR, (outs), (ins GPR:$b), + !strconcat(instr_asm, " $b"), + [(OpNode GPR:$b)], IIC_FSLp> +{ + bits<5> rb; + + let Inst{6-10} = 0x0; + let Inst{11-15} = 0x0; + let Inst{16-20} = rb; + let Inst{21} = 0x1; + let Inst{22-25} = flags; // NCTA + let Inst{26-31} = 0x0; +} + +//===----------------------------------------------------------------------===// +// FSL Get Instructions +//===----------------------------------------------------------------------===// +def GET : FSLGet<0x1B, 0x00, "get ", int_mblaze_fsl_get>; +def AGET : FSLGet<0x1B, 0x02, "aget ", int_mblaze_fsl_aget>; +def CGET : FSLGet<0x1B, 0x08, "cget ", int_mblaze_fsl_cget>; +def CAGET : FSLGet<0x1B, 0x0A, "caget ", int_mblaze_fsl_caget>; +def EGET : FSLGet<0x1B, 0x01, "eget ", int_mblaze_fsl_eget>; +def EAGET : FSLGet<0x1B, 0x03, "eaget ", int_mblaze_fsl_eaget>; +def ECGET : FSLGet<0x1B, 0x09, "ecget ", int_mblaze_fsl_ecget>; +def ECAGET : FSLGet<0x1B, 0x0B, "ecaget ", int_mblaze_fsl_ecaget>; +def TGET : FSLGet<0x1B, 0x04, "tget ", int_mblaze_fsl_tget>; +def TAGET : FSLGet<0x1B, 0x06, "taget ", int_mblaze_fsl_taget>; +def TCGET : FSLGet<0x1B, 0x0C, "tcget ", int_mblaze_fsl_tcget>; +def TCAGET : FSLGet<0x1B, 0x0E, "tcaget ", int_mblaze_fsl_tcaget>; +def TEGET : FSLGet<0x1B, 0x05, "teget ", int_mblaze_fsl_teget>; +def TEAGET : FSLGet<0x1B, 0x07, "teaget ", int_mblaze_fsl_teaget>; +def TECGET : FSLGet<0x1B, 0x0D, "tecget ", int_mblaze_fsl_tecget>; +def TECAGET : FSLGet<0x1B, 0x0F, "tecaget ", int_mblaze_fsl_tecaget>; + +let Defs = [CARRY] in { + def NGET : FSLGet<0x1B, 0x10, "nget ", int_mblaze_fsl_nget>; + def NAGET : FSLGet<0x1B, 0x12, "naget ", int_mblaze_fsl_naget>; + def NCGET : FSLGet<0x1B, 0x18, "ncget ", int_mblaze_fsl_ncget>; + def NCAGET : FSLGet<0x1B, 0x1A, "ncaget ", int_mblaze_fsl_ncaget>; + def NEGET : FSLGet<0x1B, 0x11, "neget ", int_mblaze_fsl_neget>; + def NEAGET : FSLGet<0x1B, 0x13, "neaget ", int_mblaze_fsl_neaget>; + def NECGET : FSLGet<0x1B, 0x19, "necget ", int_mblaze_fsl_necget>; + def NECAGET : FSLGet<0x1B, 0x1B, "necaget ", int_mblaze_fsl_necaget>; + def TNGET : FSLGet<0x1B, 0x14, "tnget ", int_mblaze_fsl_tnget>; + def TNAGET : FSLGet<0x1B, 0x16, "tnaget ", int_mblaze_fsl_tnaget>; + def TNCGET : FSLGet<0x1B, 0x1C, "tncget ", int_mblaze_fsl_tncget>; + def TNCAGET : FSLGet<0x1B, 0x1E, "tncaget ", int_mblaze_fsl_tncaget>; + def TNEGET : FSLGet<0x1B, 0x15, "tneget ", int_mblaze_fsl_tneget>; + def TNEAGET : FSLGet<0x1B, 0x17, "tneaget ", int_mblaze_fsl_tneaget>; + def TNECGET : FSLGet<0x1B, 0x1D, "tnecget ", int_mblaze_fsl_tnecget>; + def TNECAGET : FSLGet<0x1B, 0x1F, "tnecaget ", int_mblaze_fsl_tnecaget>; +} + +//===----------------------------------------------------------------------===// +// FSL Dynamic Get Instructions +//===----------------------------------------------------------------------===// +def GETD : FSLGetD<0x13, 0x00, "getd ", int_mblaze_fsl_get>; +def AGETD : FSLGetD<0x13, 0x02, "agetd ", int_mblaze_fsl_aget>; +def CGETD : FSLGetD<0x13, 0x08, "cgetd ", int_mblaze_fsl_cget>; +def CAGETD : FSLGetD<0x13, 0x0A, "cagetd ", int_mblaze_fsl_caget>; +def EGETD : FSLGetD<0x13, 0x01, "egetd ", int_mblaze_fsl_eget>; +def EAGETD : FSLGetD<0x13, 0x03, "eagetd ", int_mblaze_fsl_eaget>; +def ECGETD : FSLGetD<0x13, 0x09, "ecgetd ", int_mblaze_fsl_ecget>; +def ECAGETD : FSLGetD<0x13, 0x0B, "ecagetd ", int_mblaze_fsl_ecaget>; +def TGETD : FSLGetD<0x13, 0x04, "tgetd ", int_mblaze_fsl_tget>; +def TAGETD : FSLGetD<0x13, 0x06, "tagetd ", int_mblaze_fsl_taget>; +def TCGETD : FSLGetD<0x13, 0x0C, "tcgetd ", int_mblaze_fsl_tcget>; +def TCAGETD : FSLGetD<0x13, 0x0E, "tcagetd ", int_mblaze_fsl_tcaget>; +def TEGETD : FSLGetD<0x13, 0x05, "tegetd ", int_mblaze_fsl_teget>; +def TEAGETD : FSLGetD<0x13, 0x07, "teagetd ", int_mblaze_fsl_teaget>; +def TECGETD : FSLGetD<0x13, 0x0D, "tecgetd ", int_mblaze_fsl_tecget>; +def TECAGETD : FSLGetD<0x13, 0x0F, "tecagetd ", int_mblaze_fsl_tecaget>; + +let Defs = [CARRY] in { + def NGETD : FSLGetD<0x13, 0x10, "ngetd ", int_mblaze_fsl_nget>; + def NAGETD : FSLGetD<0x13, 0x12, "nagetd ", int_mblaze_fsl_naget>; + def NCGETD : FSLGetD<0x13, 0x18, "ncgetd ", int_mblaze_fsl_ncget>; + def NCAGETD : FSLGetD<0x13, 0x1A, "ncagetd ", int_mblaze_fsl_ncaget>; + def NEGETD : FSLGetD<0x13, 0x11, "negetd ", int_mblaze_fsl_neget>; + def NEAGETD : FSLGetD<0x13, 0x13, "neagetd ", int_mblaze_fsl_neaget>; + def NECGETD : FSLGetD<0x13, 0x19, "necgetd ", int_mblaze_fsl_necget>; + def NECAGETD : FSLGetD<0x13, 0x1B, "necagetd ", int_mblaze_fsl_necaget>; + def TNGETD : FSLGetD<0x13, 0x14, "tngetd ", int_mblaze_fsl_tnget>; + def TNAGETD : FSLGetD<0x13, 0x16, "tnagetd ", int_mblaze_fsl_tnaget>; + def TNCGETD : FSLGetD<0x13, 0x1C, "tncgetd ", int_mblaze_fsl_tncget>; + def TNCAGETD : FSLGetD<0x13, 0x1E, "tncagetd ", int_mblaze_fsl_tncaget>; + def TNEGETD : FSLGetD<0x13, 0x15, "tnegetd ", int_mblaze_fsl_tneget>; + def TNEAGETD : FSLGetD<0x13, 0x17, "tneagetd ", int_mblaze_fsl_tneaget>; + def TNECGETD : FSLGetD<0x13, 0x1D, "tnecgetd ", int_mblaze_fsl_tnecget>; + def TNECAGETD : FSLGetD<0x13, 0x1F, "tnecagetd", int_mblaze_fsl_tnecaget>; +} + +//===----------------------------------------------------------------------===// +// FSL Put Instructions +//===----------------------------------------------------------------------===// +def PUT : FSLPut<0x1B, 0x0, "put ", int_mblaze_fsl_put>; +def APUT : FSLPut<0x1B, 0x1, "aput ", int_mblaze_fsl_aput>; +def CPUT : FSLPut<0x1B, 0x4, "cput ", int_mblaze_fsl_cput>; +def CAPUT : FSLPut<0x1B, 0x5, "caput ", int_mblaze_fsl_caput>; +def TPUT : FSLPutT<0x1B, 0x2, "tput ", int_mblaze_fsl_tput>; +def TAPUT : FSLPutT<0x1B, 0x3, "taput ", int_mblaze_fsl_taput>; +def TCPUT : FSLPutT<0x1B, 0x6, "tcput ", int_mblaze_fsl_tcput>; +def TCAPUT : FSLPutT<0x1B, 0x7, "tcaput ", int_mblaze_fsl_tcaput>; + +let Defs = [CARRY] in { + def NPUT : FSLPut<0x1B, 0x8, "nput ", int_mblaze_fsl_nput>; + def NAPUT : FSLPut<0x1B, 0x9, "naput ", int_mblaze_fsl_naput>; + def NCPUT : FSLPut<0x1B, 0xC, "ncput ", int_mblaze_fsl_ncput>; + def NCAPUT : FSLPut<0x1B, 0xD, "ncaput ", int_mblaze_fsl_ncaput>; + def TNPUT : FSLPutT<0x1B, 0xA, "tnput ", int_mblaze_fsl_tnput>; + def TNAPUT : FSLPutT<0x1B, 0xB, "tnaput ", int_mblaze_fsl_tnaput>; + def TNCPUT : FSLPutT<0x1B, 0xE, "tncput ", int_mblaze_fsl_tncput>; + def TNCAPUT : FSLPutT<0x1B, 0xF, "tncaput ", int_mblaze_fsl_tncaput>; +} + +//===----------------------------------------------------------------------===// +// FSL Dynamic Put Instructions +//===----------------------------------------------------------------------===// +def PUTD : FSLPutD<0x13, 0x0, "putd ", int_mblaze_fsl_put>; +def APUTD : FSLPutD<0x13, 0x1, "aputd ", int_mblaze_fsl_aput>; +def CPUTD : FSLPutD<0x13, 0x4, "cputd ", int_mblaze_fsl_cput>; +def CAPUTD : FSLPutD<0x13, 0x5, "caputd ", int_mblaze_fsl_caput>; +def TPUTD : FSLPutTD<0x13, 0x2, "tputd ", int_mblaze_fsl_tput>; +def TAPUTD : FSLPutTD<0x13, 0x3, "taputd ", int_mblaze_fsl_taput>; +def TCPUTD : FSLPutTD<0x13, 0x6, "tcputd ", int_mblaze_fsl_tcput>; +def TCAPUTD : FSLPutTD<0x13, 0x7, "tcaputd ", int_mblaze_fsl_tcaput>; + +let Defs = [CARRY] in { + def NPUTD : FSLPutD<0x13, 0x8, "nputd ", int_mblaze_fsl_nput>; + def NAPUTD : FSLPutD<0x13, 0x9, "naputd ", int_mblaze_fsl_naput>; + def NCPUTD : FSLPutD<0x13, 0xC, "ncputd ", int_mblaze_fsl_ncput>; + def NCAPUTD : FSLPutD<0x13, 0xD, "ncaputd ", int_mblaze_fsl_ncaput>; + def TNPUTD : FSLPutTD<0x13, 0xA, "tnputd ", int_mblaze_fsl_tnput>; + def TNAPUTD : FSLPutTD<0x13, 0xB, "tnaputd ", int_mblaze_fsl_tnaput>; + def TNCPUTD : FSLPutTD<0x13, 0xE, "tncputd ", int_mblaze_fsl_tncput>; + def TNCAPUTD : FSLPutTD<0x13, 0xF, "tncaputd ", int_mblaze_fsl_tncaput>; +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeInstrFormats.td b/contrib/llvm/lib/Target/MBlaze/MBlazeInstrFormats.td new file mode 100644 index 0000000..e40432a --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeInstrFormats.td @@ -0,0 +1,228 @@ +//===-- MBlazeInstrFormats.td - MB Instruction defs --------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Format specifies the encoding used by the instruction. This is part of the +// ad-hoc solution used to emit machine instruction encodings by our machine +// code emitter. +class Format<bits<6> val> { + bits<6> Value = val; +} + +def FPseudo : Format<0>; +def FRRR : Format<1>; // ADD, OR, etc. +def FRRI : Format<2>; // ADDI, ORI, etc. +def FCRR : Format<3>; // PUTD, WDC, WIC, BEQ, BNE, BGE, etc. +def FCRI : Format<4>; // RTID, RTED, RTSD, BEQI, BNEI, BGEI, etc. +def FRCR : Format<5>; // BRLD, BRALD, GETD +def FRCI : Format<6>; // BRLID, BRALID, MSRCLR, MSRSET +def FCCR : Format<7>; // BR, BRA, BRD, etc. +def FCCI : Format<8>; // IMM, BRI, BRAI, BRID, etc. +def FRRCI : Format<9>; // BSRLI, BSRAI, BSLLI +def FRRC : Format<10>; // SEXT8, SEXT16, SRA, SRC, SRL, FLT, FINT, FSQRT +def FRCX : Format<11>; // GET +def FRCS : Format<12>; // MFS +def FCRCS : Format<13>; // MTS +def FCRCX : Format<14>; // PUT +def FCX : Format<15>; // TPUT +def FCR : Format<16>; // TPUTD +def FRIR : Format<17>; // RSUBI +def FRRRR : Format<18>; // RSUB, FRSUB +def FRI : Format<19>; // RSUB, FRSUB +def FC : Format<20>; // NOP +def FRR : Format<21>; // CLZ + +//===----------------------------------------------------------------------===// +// Describe MBlaze instructions format +// +// CPU INSTRUCTION FORMATS +// +// opcode - operation code. +// rd - dst reg. +// ra - first src. reg. +// rb - second src. reg. +// imm16 - 16-bit immediate value. +// +//===----------------------------------------------------------------------===// + +// Generic MBlaze Format +class MBlazeInst<bits<6> op, Format form, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin> : Instruction { + let Namespace = "MBlaze"; + field bits<32> Inst; + + bits<6> opcode = op; + Format Form = form; + bits<6> FormBits = Form.Value; + + // Top 6 bits are the 'opcode' field + let Inst{0-5} = opcode; + + // If the instruction is marked as a pseudo, set isCodeGenOnly so that the + // assembler and disassmbler ignore it. + let isCodeGenOnly = !eq(!cast<string>(form), "FPseudo"); + + dag OutOperandList = outs; + dag InOperandList = ins; + + let AsmString = asmstr; + let Pattern = pattern; + let Itinerary = itin; + + // TSFlags layout should be kept in sync with MBlazeInstrInfo.h. + let TSFlags{5-0} = FormBits; +} + +//===----------------------------------------------------------------------===// +// Pseudo instruction class +//===----------------------------------------------------------------------===// +class MBlazePseudo<dag outs, dag ins, string asmstr, list<dag> pattern>: + MBlazeInst<0x0, FPseudo, outs, ins, asmstr, pattern, IIC_Pseudo>; + +//===----------------------------------------------------------------------===// +// Type A instruction class in MBlaze : <|opcode|rd|ra|rb|flags|> +//===----------------------------------------------------------------------===// + +class TA<bits<6> op, bits<11> flags, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin> : + MBlazeInst<op,FRRR,outs, ins, asmstr, pattern, itin> +{ + bits<5> rd; + bits<5> ra; + bits<5> rb; + + let Inst{6-10} = rd; + let Inst{11-15} = ra; + let Inst{16-20} = rb; + let Inst{21-31} = flags; +} + +//===----------------------------------------------------------------------===// +// Type B instruction class in MBlaze : <|opcode|rd|ra|immediate|> +//===----------------------------------------------------------------------===// + +class TB<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin> : + MBlazeInst<op, FRRI, outs, ins, asmstr, pattern, itin> +{ + bits<5> rd; + bits<5> ra; + bits<16> imm16; + + let Inst{6-10} = rd; + let Inst{11-15} = ra; + let Inst{16-31} = imm16; +} + +//===----------------------------------------------------------------------===// +// Type A instruction class in MBlaze but with the operands reversed +// in the LLVM DAG : <|opcode|rd|ra|rb|flags|> +//===----------------------------------------------------------------------===// + +class TAR<bits<6> op, bits<11> flags, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin> : + TA<op, flags, outs, ins, asmstr, pattern, itin> +{ + bits<5> rrd; + bits<5> rrb; + bits<5> rra; + + let Form = FRRRR; + + let rd = rrd; + let ra = rra; + let rb = rrb; +} + +//===----------------------------------------------------------------------===// +// Type B instruction class in MBlaze but with the operands reversed in +// the LLVM DAG : <|opcode|rd|ra|immediate|> +//===----------------------------------------------------------------------===// +class TBR<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin> : + TB<op, outs, ins, asmstr, pattern, itin> { + bits<5> rrd; + bits<16> rimm16; + bits<5> rra; + + let Form = FRIR; + + let rd = rrd; + let ra = rra; + let imm16 = rimm16; +} + +//===----------------------------------------------------------------------===// +// Shift immediate instruction class in MBlaze : <|opcode|rd|ra|immediate|> +//===----------------------------------------------------------------------===// +class SHT<bits<6> op, bits<2> flags, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin> : + MBlazeInst<op, FRRI, outs, ins, asmstr, pattern, itin> { + bits<5> rd; + bits<5> ra; + bits<5> imm5; + + let Inst{6-10} = rd; + let Inst{11-15} = ra; + let Inst{16-20} = 0x0; + let Inst{21-22} = flags; + let Inst{23-26} = 0x0; + let Inst{27-31} = imm5; +} + +//===----------------------------------------------------------------------===// +// Special instruction class in MBlaze : <|opcode|rd|imm14|> +//===----------------------------------------------------------------------===// +class SPC<bits<6> op, bits<2> flags, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin> : + MBlazeInst<op, FRI, outs, ins, asmstr, pattern, itin> { + bits<5> rd; + bits<14> imm14; + + let Inst{6-10} = rd; + let Inst{11-15} = 0x0; + let Inst{16-17} = flags; + let Inst{18-31} = imm14; +} + +//===----------------------------------------------------------------------===// +// MSR instruction class in MBlaze : <|opcode|rd|imm15|> +//===----------------------------------------------------------------------===// +class MSR<bits<6> op, bits<6> flags, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin> : + MBlazeInst<op, FRI, outs, ins, asmstr, pattern, itin> { + bits<5> rd; + bits<15> imm15; + + let Inst{6-10} = rd; + let Inst{11-16} = flags; + let Inst{17-31} = imm15; +} + +//===----------------------------------------------------------------------===// +// TCLZ instruction class in MBlaze : <|opcode|rd|imm15|> +//===----------------------------------------------------------------------===// +class TCLZ<bits<6> op, bits<16> flags, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin> : + MBlazeInst<op, FRR, outs, ins, asmstr, pattern, itin> { + bits<5> rd; + bits<5> ra; + + let Inst{6-10} = rd; + let Inst{11-15} = ra; + let Inst{16-31} = flags; +} + +//===----------------------------------------------------------------------===// +// MBAR instruction class in MBlaze : <|opcode|rd|imm15|> +//===----------------------------------------------------------------------===// +class MBAR<bits<6> op, bits<26> flags, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin> : + MBlazeInst<op, FC, outs, ins, asmstr, pattern, itin> { + let Inst{6-31} = flags; +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeInstrInfo.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeInstrInfo.cpp new file mode 100644 index 0000000..b5025fc --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeInstrInfo.cpp @@ -0,0 +1,297 @@ +//===-- MBlazeInstrInfo.cpp - MBlaze Instruction Information --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the MBlaze implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeInstrInfo.h" +#include "MBlazeTargetMachine.h" +#include "MBlazeMachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/ScoreboardHazardRecognizer.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/ADT/STLExtras.h" + +#define GET_INSTRINFO_CTOR +#include "MBlazeGenInstrInfo.inc" + +using namespace llvm; + +MBlazeInstrInfo::MBlazeInstrInfo(MBlazeTargetMachine &tm) + : MBlazeGenInstrInfo(MBlaze::ADJCALLSTACKDOWN, MBlaze::ADJCALLSTACKUP), + TM(tm), RI(*TM.getSubtargetImpl(), *this) {} + +static bool isZeroImm(const MachineOperand &op) { + return op.isImm() && op.getImm() == 0; +} + +/// isLoadFromStackSlot - If the specified machine instruction is a direct +/// load from a stack slot, return the virtual or physical register number of +/// the destination along with the FrameIndex of the loaded stack slot. If +/// not, return 0. This predicate must return 0 if the instruction has +/// any side effects other than loading from the stack slot. +unsigned MBlazeInstrInfo:: +isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const { + if (MI->getOpcode() == MBlaze::LWI) { + if ((MI->getOperand(1).isFI()) && // is a stack slot + (MI->getOperand(2).isImm()) && // the imm is zero + (isZeroImm(MI->getOperand(2)))) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + } + + return 0; +} + +/// isStoreToStackSlot - If the specified machine instruction is a direct +/// store to a stack slot, return the virtual or physical register number of +/// the source reg along with the FrameIndex of the loaded stack slot. If +/// not, return 0. This predicate must return 0 if the instruction has +/// any side effects other than storing to the stack slot. +unsigned MBlazeInstrInfo:: +isStoreToStackSlot(const MachineInstr *MI, int &FrameIndex) const { + if (MI->getOpcode() == MBlaze::SWI) { + if ((MI->getOperand(1).isFI()) && // is a stack slot + (MI->getOperand(2).isImm()) && // the imm is zero + (isZeroImm(MI->getOperand(2)))) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + } + return 0; +} + +/// insertNoop - If data hazard condition is found insert the target nop +/// instruction. +void MBlazeInstrInfo:: +insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const { + DebugLoc DL; + BuildMI(MBB, MI, DL, get(MBlaze::NOP)); +} + +void MBlazeInstrInfo:: +copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const { + llvm::BuildMI(MBB, I, DL, get(MBlaze::ADDK), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)).addReg(MBlaze::R0); +} + +void MBlazeInstrInfo:: +storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned SrcReg, bool isKill, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL; + BuildMI(MBB, I, DL, get(MBlaze::SWI)).addReg(SrcReg,getKillRegState(isKill)) + .addFrameIndex(FI).addImm(0); //.addFrameIndex(FI); +} + +void MBlazeInstrInfo:: +loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned DestReg, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL; + BuildMI(MBB, I, DL, get(MBlaze::LWI), DestReg) + .addFrameIndex(FI).addImm(0); //.addFrameIndex(FI); +} + +//===----------------------------------------------------------------------===// +// Branch Analysis +//===----------------------------------------------------------------------===// +bool MBlazeInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const { + // If the block has no terminators, it just falls into the block after it. + MachineBasicBlock::iterator I = MBB.end(); + if (I == MBB.begin()) + return false; + --I; + while (I->isDebugValue()) { + if (I == MBB.begin()) + return false; + --I; + } + if (!isUnpredicatedTerminator(I)) + return false; + + // Get the last instruction in the block. + MachineInstr *LastInst = I; + + // If there is only one terminator instruction, process it. + unsigned LastOpc = LastInst->getOpcode(); + if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) { + if (MBlaze::isUncondBranchOpcode(LastOpc)) { + TBB = LastInst->getOperand(0).getMBB(); + return false; + } + if (MBlaze::isCondBranchOpcode(LastOpc)) { + // Block ends with fall-through condbranch. + TBB = LastInst->getOperand(1).getMBB(); + Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode())); + Cond.push_back(LastInst->getOperand(0)); + return false; + } + // Otherwise, don't know what this is. + return true; + } + + // Get the instruction before it if it's a terminator. + MachineInstr *SecondLastInst = I; + + // If there are three terminators, we don't know what sort of block this is. + if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(--I)) + return true; + + // If the block ends with something like BEQID then BRID, handle it. + if (MBlaze::isCondBranchOpcode(SecondLastInst->getOpcode()) && + MBlaze::isUncondBranchOpcode(LastInst->getOpcode())) { + TBB = SecondLastInst->getOperand(1).getMBB(); + Cond.push_back(MachineOperand::CreateImm(SecondLastInst->getOpcode())); + Cond.push_back(SecondLastInst->getOperand(0)); + FBB = LastInst->getOperand(0).getMBB(); + return false; + } + + // If the block ends with two unconditional branches, handle it. + // The second one is not executed, so remove it. + if (MBlaze::isUncondBranchOpcode(SecondLastInst->getOpcode()) && + MBlaze::isUncondBranchOpcode(LastInst->getOpcode())) { + TBB = SecondLastInst->getOperand(0).getMBB(); + I = LastInst; + if (AllowModify) + I->eraseFromParent(); + return false; + } + + // Otherwise, can't handle this. + return true; +} + +unsigned MBlazeInstrInfo:: +InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond, + DebugLoc DL) const { + // Shouldn't be a fall through. + assert(TBB && "InsertBranch must not be told to insert a fallthrough"); + assert((Cond.size() == 2 || Cond.size() == 0) && + "MBlaze branch conditions have two components!"); + + unsigned Opc = MBlaze::BRID; + if (!Cond.empty()) + Opc = (unsigned)Cond[0].getImm(); + + if (FBB == 0) { + if (Cond.empty()) // Unconditional branch + BuildMI(&MBB, DL, get(Opc)).addMBB(TBB); + else // Conditional branch + BuildMI(&MBB, DL, get(Opc)).addReg(Cond[1].getReg()).addMBB(TBB); + return 1; + } + + BuildMI(&MBB, DL, get(Opc)).addReg(Cond[1].getReg()).addMBB(TBB); + BuildMI(&MBB, DL, get(MBlaze::BRID)).addMBB(FBB); + return 2; +} + +unsigned MBlazeInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator I = MBB.end(); + if (I == MBB.begin()) return 0; + --I; + while (I->isDebugValue()) { + if (I == MBB.begin()) + return 0; + --I; + } + + if (!MBlaze::isUncondBranchOpcode(I->getOpcode()) && + !MBlaze::isCondBranchOpcode(I->getOpcode())) + return 0; + + // Remove the branch. + I->eraseFromParent(); + + I = MBB.end(); + + if (I == MBB.begin()) return 1; + --I; + if (!MBlaze::isCondBranchOpcode(I->getOpcode())) + return 1; + + // Remove the branch. + I->eraseFromParent(); + return 2; +} + +bool MBlazeInstrInfo::ReverseBranchCondition(SmallVectorImpl<MachineOperand> + &Cond) const { + assert(Cond.size() == 2 && "Invalid MBlaze branch opcode!"); + switch (Cond[0].getImm()) { + default: return true; + case MBlaze::BEQ: Cond[0].setImm(MBlaze::BNE); return false; + case MBlaze::BNE: Cond[0].setImm(MBlaze::BEQ); return false; + case MBlaze::BGT: Cond[0].setImm(MBlaze::BLE); return false; + case MBlaze::BGE: Cond[0].setImm(MBlaze::BLT); return false; + case MBlaze::BLT: Cond[0].setImm(MBlaze::BGE); return false; + case MBlaze::BLE: Cond[0].setImm(MBlaze::BGT); return false; + case MBlaze::BEQI: Cond[0].setImm(MBlaze::BNEI); return false; + case MBlaze::BNEI: Cond[0].setImm(MBlaze::BEQI); return false; + case MBlaze::BGTI: Cond[0].setImm(MBlaze::BLEI); return false; + case MBlaze::BGEI: Cond[0].setImm(MBlaze::BLTI); return false; + case MBlaze::BLTI: Cond[0].setImm(MBlaze::BGEI); return false; + case MBlaze::BLEI: Cond[0].setImm(MBlaze::BGTI); return false; + case MBlaze::BEQD: Cond[0].setImm(MBlaze::BNED); return false; + case MBlaze::BNED: Cond[0].setImm(MBlaze::BEQD); return false; + case MBlaze::BGTD: Cond[0].setImm(MBlaze::BLED); return false; + case MBlaze::BGED: Cond[0].setImm(MBlaze::BLTD); return false; + case MBlaze::BLTD: Cond[0].setImm(MBlaze::BGED); return false; + case MBlaze::BLED: Cond[0].setImm(MBlaze::BGTD); return false; + case MBlaze::BEQID: Cond[0].setImm(MBlaze::BNEID); return false; + case MBlaze::BNEID: Cond[0].setImm(MBlaze::BEQID); return false; + case MBlaze::BGTID: Cond[0].setImm(MBlaze::BLEID); return false; + case MBlaze::BGEID: Cond[0].setImm(MBlaze::BLTID); return false; + case MBlaze::BLTID: Cond[0].setImm(MBlaze::BGEID); return false; + case MBlaze::BLEID: Cond[0].setImm(MBlaze::BGTID); return false; + } +} + +/// getGlobalBaseReg - Return a virtual register initialized with the +/// the global base register value. Output instructions required to +/// initialize the register in the function entry block, if necessary. +/// +unsigned MBlazeInstrInfo::getGlobalBaseReg(MachineFunction *MF) const { + MBlazeFunctionInfo *MBlazeFI = MF->getInfo<MBlazeFunctionInfo>(); + unsigned GlobalBaseReg = MBlazeFI->getGlobalBaseReg(); + if (GlobalBaseReg != 0) + return GlobalBaseReg; + + // Insert the set of GlobalBaseReg into the first MBB of the function + MachineBasicBlock &FirstMBB = MF->front(); + MachineBasicBlock::iterator MBBI = FirstMBB.begin(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetInstrInfo *TII = MF->getTarget().getInstrInfo(); + + GlobalBaseReg = RegInfo.createVirtualRegister(&MBlaze::GPRRegClass); + BuildMI(FirstMBB, MBBI, DebugLoc(), TII->get(TargetOpcode::COPY), + GlobalBaseReg).addReg(MBlaze::R20); + RegInfo.addLiveIn(MBlaze::R20); + + MBlazeFI->setGlobalBaseReg(GlobalBaseReg); + return GlobalBaseReg; +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeInstrInfo.h b/contrib/llvm/lib/Target/MBlaze/MBlazeInstrInfo.h new file mode 100644 index 0000000..5252147 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeInstrInfo.h @@ -0,0 +1,240 @@ +//===-- MBlazeInstrInfo.h - MBlaze Instruction Information ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the MBlaze implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZEINSTRUCTIONINFO_H +#define MBLAZEINSTRUCTIONINFO_H + +#include "MBlaze.h" +#include "MBlazeRegisterInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "MBlazeGenInstrInfo.inc" + +namespace llvm { + +namespace MBlaze { + + // MBlaze Branch Codes + enum FPBranchCode { + BRANCH_F, + BRANCH_T, + BRANCH_FL, + BRANCH_TL, + BRANCH_INVALID + }; + + // MBlaze Condition Codes + enum CondCode { + // To be used with float branch True + FCOND_F, + FCOND_UN, + FCOND_EQ, + FCOND_UEQ, + FCOND_OLT, + FCOND_ULT, + FCOND_OLE, + FCOND_ULE, + FCOND_SF, + FCOND_NGLE, + FCOND_SEQ, + FCOND_NGL, + FCOND_LT, + FCOND_NGE, + FCOND_LE, + FCOND_NGT, + + // To be used with float branch False + // This conditions have the same mnemonic as the + // above ones, but are used with a branch False; + FCOND_T, + FCOND_OR, + FCOND_NEQ, + FCOND_OGL, + FCOND_UGE, + FCOND_OGE, + FCOND_UGT, + FCOND_OGT, + FCOND_ST, + FCOND_GLE, + FCOND_SNE, + FCOND_GL, + FCOND_NLT, + FCOND_GE, + FCOND_NLE, + FCOND_GT, + + // Only integer conditions + COND_EQ, + COND_GT, + COND_GE, + COND_LT, + COND_LE, + COND_NE, + COND_INVALID + }; + + // Turn condition code into conditional branch opcode. + inline static unsigned GetCondBranchFromCond(CondCode CC) { + switch (CC) { + default: llvm_unreachable("Unknown condition code"); + case COND_EQ: return MBlaze::BEQID; + case COND_NE: return MBlaze::BNEID; + case COND_GT: return MBlaze::BGTID; + case COND_GE: return MBlaze::BGEID; + case COND_LT: return MBlaze::BLTID; + case COND_LE: return MBlaze::BLEID; + } + } + + /// GetOppositeBranchCondition - Return the inverse of the specified cond, + /// e.g. turning COND_E to COND_NE. + // CondCode GetOppositeBranchCondition(MBlaze::CondCode CC); + + /// MBlazeCCToString - Map each FP condition code to its string + inline static const char *MBlazeFCCToString(MBlaze::CondCode CC) { + switch (CC) { + default: llvm_unreachable("Unknown condition code"); + case FCOND_F: + case FCOND_T: return "f"; + case FCOND_UN: + case FCOND_OR: return "un"; + case FCOND_EQ: + case FCOND_NEQ: return "eq"; + case FCOND_UEQ: + case FCOND_OGL: return "ueq"; + case FCOND_OLT: + case FCOND_UGE: return "olt"; + case FCOND_ULT: + case FCOND_OGE: return "ult"; + case FCOND_OLE: + case FCOND_UGT: return "ole"; + case FCOND_ULE: + case FCOND_OGT: return "ule"; + case FCOND_SF: + case FCOND_ST: return "sf"; + case FCOND_NGLE: + case FCOND_GLE: return "ngle"; + case FCOND_SEQ: + case FCOND_SNE: return "seq"; + case FCOND_NGL: + case FCOND_GL: return "ngl"; + case FCOND_LT: + case FCOND_NLT: return "lt"; + case FCOND_NGE: + case FCOND_GE: return "ge"; + case FCOND_LE: + case FCOND_NLE: return "nle"; + case FCOND_NGT: + case FCOND_GT: return "gt"; + } + } + + inline static bool isUncondBranchOpcode(int Opc) { + switch (Opc) { + default: return false; + case MBlaze::BRI: + case MBlaze::BRAI: + case MBlaze::BRID: + case MBlaze::BRAID: + return true; + } + } + + inline static bool isCondBranchOpcode(int Opc) { + switch (Opc) { + default: return false; + case MBlaze::BEQI: case MBlaze::BEQID: + case MBlaze::BNEI: case MBlaze::BNEID: + case MBlaze::BGTI: case MBlaze::BGTID: + case MBlaze::BGEI: case MBlaze::BGEID: + case MBlaze::BLTI: case MBlaze::BLTID: + case MBlaze::BLEI: case MBlaze::BLEID: + return true; + } + } +} + +class MBlazeInstrInfo : public MBlazeGenInstrInfo { + MBlazeTargetMachine &TM; + const MBlazeRegisterInfo RI; +public: + explicit MBlazeInstrInfo(MBlazeTargetMachine &TM); + + /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As + /// such, whenever a client has an instance of instruction info, it should + /// always be able to get register info as well (through this method). + /// + virtual const MBlazeRegisterInfo &getRegisterInfo() const { return RI; } + + /// isLoadFromStackSlot - If the specified machine instruction is a direct + /// load from a stack slot, return the virtual or physical register number of + /// the destination along with the FrameIndex of the loaded stack slot. If + /// not, return 0. This predicate must return 0 if the instruction has + /// any side effects other than loading from the stack slot. + virtual unsigned isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const; + + /// isStoreToStackSlot - If the specified machine instruction is a direct + /// store to a stack slot, return the virtual or physical register number of + /// the source reg along with the FrameIndex of the loaded stack slot. If + /// not, return 0. This predicate must return 0 if the instruction has + /// any side effects other than storing to the stack slot. + virtual unsigned isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const; + + /// Branch Analysis + virtual bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const; + virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond, + DebugLoc DL) const; + virtual unsigned RemoveBranch(MachineBasicBlock &MBB) const; + + virtual bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) + const; + + virtual void copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const; + virtual void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const; + + virtual void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const; + + /// Insert nop instruction when hazard condition is found + virtual void insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const; + + /// getGlobalBaseReg - Return a virtual register initialized with the + /// the global base register value. Output instructions required to + /// initialize the register in the function entry block, if necessary. + /// + unsigned getGlobalBaseReg(MachineFunction *MF) const; +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeInstrInfo.td b/contrib/llvm/lib/Target/MBlaze/MBlazeInstrInfo.td new file mode 100644 index 0000000..139bf71 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeInstrInfo.td @@ -0,0 +1,1052 @@ +//===-- MBlazeInstrInfo.td - MBlaze Instruction defs -------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Instruction format superclass +//===----------------------------------------------------------------------===// +include "MBlazeInstrFormats.td" + +//===----------------------------------------------------------------------===// +// MBlaze type profiles +//===----------------------------------------------------------------------===// + +// def SDTMBlazeSelectCC : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>]>; +def SDT_MBlazeRet : SDTypeProfile<0, 1, [SDTCisInt<0>]>; +def SDT_MBlazeIRet : SDTypeProfile<0, 1, [SDTCisInt<0>]>; +def SDT_MBlazeJmpLink : SDTypeProfile<0, -1, [SDTCisVT<0, i32>]>; +def SDT_MBCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>; +def SDT_MBCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; + +//===----------------------------------------------------------------------===// +// MBlaze specific nodes +//===----------------------------------------------------------------------===// + +def MBlazeRet : SDNode<"MBlazeISD::Ret", SDT_MBlazeRet, + [SDNPHasChain, SDNPOptInGlue]>; +def MBlazeIRet : SDNode<"MBlazeISD::IRet", SDT_MBlazeIRet, + [SDNPHasChain, SDNPOptInGlue]>; + +def MBlazeJmpLink : SDNode<"MBlazeISD::JmpLink",SDT_MBlazeJmpLink, + [SDNPHasChain,SDNPOptInGlue,SDNPOutGlue, + SDNPVariadic]>; + +def MBWrapper : SDNode<"MBlazeISD::Wrap", SDTIntUnaryOp>; + +def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_MBCallSeqStart, + [SDNPHasChain, SDNPOutGlue]>; + +def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_MBCallSeqEnd, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; + +//===----------------------------------------------------------------------===// +// MBlaze Instruction Predicate Definitions. +//===----------------------------------------------------------------------===// +// def HasPipe3 : Predicate<"Subtarget.hasPipe3()">; +def HasBarrel : Predicate<"Subtarget.hasBarrel()">; +// def NoBarrel : Predicate<"!Subtarget.hasBarrel()">; +def HasDiv : Predicate<"Subtarget.hasDiv()">; +def HasMul : Predicate<"Subtarget.hasMul()">; +// def HasFSL : Predicate<"Subtarget.hasFSL()">; +// def HasEFSL : Predicate<"Subtarget.hasEFSL()">; +// def HasMSRSet : Predicate<"Subtarget.hasMSRSet()">; +// def HasException : Predicate<"Subtarget.hasException()">; +def HasPatCmp : Predicate<"Subtarget.hasPatCmp()">; +def HasFPU : Predicate<"Subtarget.hasFPU()">; +// def HasESR : Predicate<"Subtarget.hasESR()">; +// def HasPVR : Predicate<"Subtarget.hasPVR()">; +def HasMul64 : Predicate<"Subtarget.hasMul64()">; +def HasSqrt : Predicate<"Subtarget.hasSqrt()">; +// def HasMMU : Predicate<"Subtarget.hasMMU()">; + +//===----------------------------------------------------------------------===// +// MBlaze Operand, Complex Patterns and Transformations Definitions. +//===----------------------------------------------------------------------===// + +def MBlazeMemAsmOperand : AsmOperandClass { + let Name = "Mem"; + let SuperClasses = []; +} + +def MBlazeFslAsmOperand : AsmOperandClass { + let Name = "Fsl"; + let SuperClasses = []; +} + +// Instruction operand types +def brtarget : Operand<OtherVT>; +def calltarget : Operand<i32>; +def simm16 : Operand<i32>; +def uimm5 : Operand<i32>; +def uimm15 : Operand<i32>; +def fimm : Operand<f32>; + +// Unsigned Operand +def uimm16 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; +} + +// FSL Operand +def fslimm : Operand<i32> { + let PrintMethod = "printFSLImm"; + let ParserMatchClass = MBlazeFslAsmOperand; +} + +// Address operand +def memri : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops GPR, simm16); + let ParserMatchClass = MBlazeMemAsmOperand; +} + +def memrr : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops GPR, GPR); + let ParserMatchClass = MBlazeMemAsmOperand; +} + +// Node immediate fits as 16-bit sign extended on target immediate. +def immSExt16 : PatLeaf<(imm), [{ + return (N->getZExtValue() >> 16) == 0; +}]>; + +// Node immediate fits as 16-bit zero extended on target immediate. +// The LO16 param means that only the lower 16 bits of the node +// immediate are caught. +// e.g. addiu, sltiu +def immZExt16 : PatLeaf<(imm), [{ + return (N->getZExtValue() >> 16) == 0; +}]>; + +// FSL immediate field must fit in 4 bits. +def immZExt4 : PatLeaf<(imm), [{ + return N->getZExtValue() == ((N->getZExtValue()) & 0xf) ; +}]>; + +// shamt field must fit in 5 bits. +def immZExt5 : PatLeaf<(imm), [{ + return N->getZExtValue() == ((N->getZExtValue()) & 0x1f) ; +}]>; + +// MBlaze Address Mode. SDNode frameindex could possibily be a match +// since load and store instructions from stack used it. +def iaddr : ComplexPattern<i32, 2, "SelectAddrRegImm", [frameindex], []>; +def xaddr : ComplexPattern<i32, 2, "SelectAddrRegReg", [], []>; + +//===----------------------------------------------------------------------===// +// Pseudo instructions +//===----------------------------------------------------------------------===// + +// As stack alignment is always done with addiu, we need a 16-bit immediate +let Defs = [R1], Uses = [R1] in { +def ADJCALLSTACKDOWN : MBlazePseudo<(outs), (ins simm16:$amt), + "#ADJCALLSTACKDOWN $amt", + [(callseq_start timm:$amt)]>; +def ADJCALLSTACKUP : MBlazePseudo<(outs), + (ins uimm16:$amt1, simm16:$amt2), + "#ADJCALLSTACKUP $amt1", + [(callseq_end timm:$amt1, timm:$amt2)]>; +} + +//===----------------------------------------------------------------------===// +// Instructions specific format +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Arithmetic Instructions +//===----------------------------------------------------------------------===// +class Arith<bits<6> op, bits<11> flags, string instr_asm, SDNode OpNode, + InstrItinClass itin> : + TA<op, flags, (outs GPR:$dst), (ins GPR:$b, GPR:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set GPR:$dst, (OpNode GPR:$b, GPR:$c))], itin>; + +class ArithI<bits<6> op, string instr_asm, SDNode OpNode, + Operand Od, PatLeaf imm_type> : + TB<op, (outs GPR:$dst), (ins GPR:$b, Od:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set GPR:$dst, (OpNode GPR:$b, imm_type:$c))], IIC_ALU>; + +class ArithI32<bits<6> op, string instr_asm,Operand Od, PatLeaf imm_type> : + TB<op, (outs GPR:$dst), (ins GPR:$b, Od:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [], IIC_ALU>; + +class ShiftI<bits<6> op, bits<2> flags, string instr_asm, SDNode OpNode, + Operand Od, PatLeaf imm_type> : + SHT<op, flags, (outs GPR:$dst), (ins GPR:$b, Od:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set GPR:$dst, (OpNode GPR:$b, imm_type:$c))], IIC_SHT>; + +class ArithR<bits<6> op, bits<11> flags, string instr_asm, SDNode OpNode, + InstrItinClass itin> : + TAR<op, flags, (outs GPR:$dst), (ins GPR:$b, GPR:$c), + !strconcat(instr_asm, " $dst, $c, $b"), + [(set GPR:$dst, (OpNode GPR:$b, GPR:$c))], itin>; + +class ArithRI<bits<6> op, string instr_asm, SDNode OpNode, + Operand Od, PatLeaf imm_type> : + TBR<op, (outs GPR:$dst), (ins Od:$b, GPR:$c), + !strconcat(instr_asm, " $dst, $c, $b"), + [(set GPR:$dst, (OpNode imm_type:$b, GPR:$c))], IIC_ALU>; + +class ArithN<bits<6> op, bits<11> flags, string instr_asm, + InstrItinClass itin> : + TA<op, flags, (outs GPR:$dst), (ins GPR:$b, GPR:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [], itin>; + +class ArithNI<bits<6> op, string instr_asm,Operand Od, PatLeaf imm_type> : + TB<op, (outs GPR:$dst), (ins GPR:$b, Od:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [], IIC_ALU>; + +class ArithRN<bits<6> op, bits<11> flags, string instr_asm, + InstrItinClass itin> : + TAR<op, flags, (outs GPR:$dst), (ins GPR:$c, GPR:$b), + !strconcat(instr_asm, " $dst, $b, $c"), + [], itin>; + +class ArithRNI<bits<6> op, string instr_asm,Operand Od, PatLeaf imm_type> : + TBR<op, (outs GPR:$dst), (ins Od:$c, GPR:$b), + !strconcat(instr_asm, " $dst, $b, $c"), + [], IIC_ALU>; + +//===----------------------------------------------------------------------===// +// Misc Arithmetic Instructions +//===----------------------------------------------------------------------===// + +class Logic<bits<6> op, bits<11> flags, string instr_asm, SDNode OpNode> : + TA<op, flags, (outs GPR:$dst), (ins GPR:$b, GPR:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set GPR:$dst, (OpNode GPR:$b, GPR:$c))], IIC_ALU>; + +class LogicI<bits<6> op, string instr_asm, SDNode OpNode> : + TB<op, (outs GPR:$dst), (ins GPR:$b, uimm16:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [(set GPR:$dst, (OpNode GPR:$b, immZExt16:$c))], + IIC_ALU>; + +class LogicI32<bits<6> op, string instr_asm> : + TB<op, (outs GPR:$dst), (ins GPR:$b, uimm16:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [], IIC_ALU>; + +class PatCmp<bits<6> op, bits<11> flags, string instr_asm> : + TA<op, flags, (outs GPR:$dst), (ins GPR:$b, GPR:$c), + !strconcat(instr_asm, " $dst, $b, $c"), + [], IIC_ALU>; + +//===----------------------------------------------------------------------===// +// Memory Access Instructions +//===----------------------------------------------------------------------===// + +let mayLoad = 1 in { +class LoadM<bits<6> op, bits<11> flags, string instr_asm> : + TA<op, flags, (outs GPR:$dst), (ins memrr:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [], IIC_MEMl>; +} + +class LoadMI<bits<6> op, string instr_asm, PatFrag OpNode> : + TB<op, (outs GPR:$dst), (ins memri:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(set (i32 GPR:$dst), (OpNode iaddr:$addr))], IIC_MEMl>; + +let mayStore = 1 in { +class StoreM<bits<6> op, bits<11> flags, string instr_asm> : + TA<op, flags, (outs), (ins GPR:$dst, memrr:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [], IIC_MEMs>; +} + +class StoreMI<bits<6> op, string instr_asm, PatFrag OpNode> : + TB<op, (outs), (ins GPR:$dst, memri:$addr), + !strconcat(instr_asm, " $dst, $addr"), + [(OpNode (i32 GPR:$dst), iaddr:$addr)], IIC_MEMs>; + +//===----------------------------------------------------------------------===// +// Branch Instructions +//===----------------------------------------------------------------------===// +class Branch<bits<6> op, bits<5> br, bits<11> flags, string instr_asm> : + TA<op, flags, (outs), (ins GPR:$target), + !strconcat(instr_asm, " $target"), + [], IIC_BR> { + let rd = 0x0; + let ra = br; + let Form = FCCR; +} + +class BranchI<bits<6> op, bits<5> br, string instr_asm> : + TB<op, (outs), (ins brtarget:$target), + !strconcat(instr_asm, " $target"), + [], IIC_BR> { + let rd = 0; + let ra = br; + let Form = FCCI; +} + +//===----------------------------------------------------------------------===// +// Branch and Link Instructions +//===----------------------------------------------------------------------===// +class BranchL<bits<6> op, bits<5> br, bits<11> flags, string instr_asm> : + TA<op, flags, (outs), (ins GPR:$link, GPR:$target), + !strconcat(instr_asm, " $link, $target"), + [], IIC_BRl> { + let ra = br; + let Form = FRCR; +} + +class BranchLI<bits<6> op, bits<5> br, string instr_asm> : + TB<op, (outs), (ins GPR:$link, calltarget:$target), + !strconcat(instr_asm, " $link, $target"), + [], IIC_BRl> { + let ra = br; + let Form = FRCI; +} + +//===----------------------------------------------------------------------===// +// Conditional Branch Instructions +//===----------------------------------------------------------------------===// +class BranchC<bits<6> op, bits<5> br, bits<11> flags, string instr_asm> : + TA<op, flags, (outs), + (ins GPR:$a, GPR:$b), + !strconcat(instr_asm, " $a, $b"), + [], IIC_BRc> { + let rd = br; + let Form = FCRR; +} + +class BranchCI<bits<6> op, bits<5> br, string instr_asm> : + TB<op, (outs), (ins GPR:$a, brtarget:$offset), + !strconcat(instr_asm, " $a, $offset"), + [], IIC_BRc> { + let rd = br; + let Form = FCRI; +} + +//===----------------------------------------------------------------------===// +// MBlaze arithmetic instructions +//===----------------------------------------------------------------------===// + +let isCommutable = 1, isAsCheapAsAMove = 1 in { + def ADDK : Arith<0x04, 0x000, "addk ", add, IIC_ALU>; + def AND : Logic<0x21, 0x000, "and ", and>; + def OR : Logic<0x20, 0x000, "or ", or>; + def XOR : Logic<0x22, 0x000, "xor ", xor>; + + let Predicates=[HasPatCmp] in { + def PCMPBF : PatCmp<0x20, 0x400, "pcmpbf ">; + def PCMPEQ : PatCmp<0x22, 0x400, "pcmpeq ">; + def PCMPNE : PatCmp<0x23, 0x400, "pcmpne ">; + } + + let Defs = [CARRY] in { + def ADD : Arith<0x00, 0x000, "add ", addc, IIC_ALU>; + + let Uses = [CARRY] in { + def ADDC : Arith<0x02, 0x000, "addc ", adde, IIC_ALU>; + } + } + + let Uses = [CARRY] in { + def ADDKC : ArithN<0x06, 0x000, "addkc ", IIC_ALU>; + } +} + +let isAsCheapAsAMove = 1 in { + def ANDN : ArithN<0x23, 0x000, "andn ", IIC_ALU>; + def CMP : ArithN<0x05, 0x001, "cmp ", IIC_ALU>; + def CMPU : ArithN<0x05, 0x003, "cmpu ", IIC_ALU>; + def RSUBK : ArithR<0x05, 0x000, "rsubk ", sub, IIC_ALU>; + + let Defs = [CARRY] in { + def RSUB : ArithR<0x01, 0x000, "rsub ", subc, IIC_ALU>; + + let Uses = [CARRY] in { + def RSUBC : ArithR<0x03, 0x000, "rsubc ", sube, IIC_ALU>; + } + } + + let Uses = [CARRY] in { + def RSUBKC : ArithRN<0x07, 0x000, "rsubkc ", IIC_ALU>; + } +} + +let isCommutable = 1, Predicates=[HasMul] in { + def MUL : Arith<0x10, 0x000, "mul ", mul, IIC_ALUm>; +} + +let isCommutable = 1, Predicates=[HasMul,HasMul64] in { + def MULH : Arith<0x10, 0x001, "mulh ", mulhs, IIC_ALUm>; + def MULHU : Arith<0x10, 0x003, "mulhu ", mulhu, IIC_ALUm>; +} + +let Predicates=[HasMul,HasMul64] in { + def MULHSU : ArithN<0x10, 0x002, "mulhsu ", IIC_ALUm>; +} + +let Predicates=[HasBarrel] in { + def BSRL : Arith<0x11, 0x000, "bsrl ", srl, IIC_SHT>; + def BSRA : Arith<0x11, 0x200, "bsra ", sra, IIC_SHT>; + def BSLL : Arith<0x11, 0x400, "bsll ", shl, IIC_SHT>; + def BSRLI : ShiftI<0x19, 0x0, "bsrli ", srl, uimm5, immZExt5>; + def BSRAI : ShiftI<0x19, 0x1, "bsrai ", sra, uimm5, immZExt5>; + def BSLLI : ShiftI<0x19, 0x2, "bslli ", shl, uimm5, immZExt5>; +} + +let Predicates=[HasDiv] in { + def IDIV : ArithR<0x12, 0x000, "idiv ", sdiv, IIC_ALUd>; + def IDIVU : ArithR<0x12, 0x002, "idivu ", udiv, IIC_ALUd>; +} + +//===----------------------------------------------------------------------===// +// MBlaze immediate mode arithmetic instructions +//===----------------------------------------------------------------------===// + +let isAsCheapAsAMove = 1 in { + def ADDIK : ArithI<0x0C, "addik ", add, simm16, immSExt16>; + def RSUBIK : ArithRI<0x0D, "rsubik ", sub, simm16, immSExt16>; + def ANDNI : ArithNI<0x2B, "andni ", uimm16, immZExt16>; + def ANDI : LogicI<0x29, "andi ", and>; + def ORI : LogicI<0x28, "ori ", or>; + def XORI : LogicI<0x2A, "xori ", xor>; + + let Defs = [CARRY] in { + def ADDI : ArithI<0x08, "addi ", addc, simm16, immSExt16>; + def RSUBI : ArithRI<0x09, "rsubi ", subc, simm16, immSExt16>; + + let Uses = [CARRY] in { + def ADDIC : ArithI<0x0A, "addic ", adde, simm16, immSExt16>; + def RSUBIC : ArithRI<0x0B, "rsubic ", sube, simm16, immSExt16>; + } + } + + let Uses = [CARRY] in { + def ADDIKC : ArithNI<0x0E, "addikc ", simm16, immSExt16>; + def RSUBIKC : ArithRNI<0x0F, "rsubikc", simm16, immSExt16>; + } +} + +let Predicates=[HasMul] in { + def MULI : ArithI<0x18, "muli ", mul, simm16, immSExt16>; +} + +//===----------------------------------------------------------------------===// +// MBlaze memory access instructions +//===----------------------------------------------------------------------===// + +let canFoldAsLoad = 1, isReMaterializable = 1 in { + let neverHasSideEffects = 1 in { + def LBU : LoadM<0x30, 0x000, "lbu ">; + def LBUR : LoadM<0x30, 0x200, "lbur ">; + + def LHU : LoadM<0x31, 0x000, "lhu ">; + def LHUR : LoadM<0x31, 0x200, "lhur ">; + + def LW : LoadM<0x32, 0x000, "lw ">; + def LWR : LoadM<0x32, 0x200, "lwr ">; + + let Defs = [CARRY] in { + def LWX : LoadM<0x32, 0x400, "lwx ">; + } + } + + def LBUI : LoadMI<0x38, "lbui ", zextloadi8>; + def LHUI : LoadMI<0x39, "lhui ", zextloadi16>; + def LWI : LoadMI<0x3A, "lwi ", load>; +} + +def SB : StoreM<0x34, 0x000, "sb ">; +def SBR : StoreM<0x34, 0x200, "sbr ">; + +def SH : StoreM<0x35, 0x000, "sh ">; +def SHR : StoreM<0x35, 0x200, "shr ">; + +def SW : StoreM<0x36, 0x000, "sw ">; +def SWR : StoreM<0x36, 0x200, "swr ">; + +let Defs = [CARRY] in { + def SWX : StoreM<0x36, 0x400, "swx ">; +} + +def SBI : StoreMI<0x3C, "sbi ", truncstorei8>; +def SHI : StoreMI<0x3D, "shi ", truncstorei16>; +def SWI : StoreMI<0x3E, "swi ", store>; + +//===----------------------------------------------------------------------===// +// MBlaze branch instructions +//===----------------------------------------------------------------------===// + +let isBranch = 1, isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in { + def BRI : BranchI<0x2E, 0x00, "bri ">; + def BRAI : BranchI<0x2E, 0x08, "brai ">; +} + +let isBranch = 1, isTerminator = 1, hasCtrlDep = 1 in { + def BEQI : BranchCI<0x2F, 0x00, "beqi ">; + def BNEI : BranchCI<0x2F, 0x01, "bnei ">; + def BLTI : BranchCI<0x2F, 0x02, "blti ">; + def BLEI : BranchCI<0x2F, 0x03, "blei ">; + def BGTI : BranchCI<0x2F, 0x04, "bgti ">; + def BGEI : BranchCI<0x2F, 0x05, "bgei ">; +} + +let isBranch = 1, isIndirectBranch = 1, isTerminator = 1, hasCtrlDep = 1, + isBarrier = 1 in { + def BR : Branch<0x26, 0x00, 0x000, "br ">; + def BRA : Branch<0x26, 0x08, 0x000, "bra ">; +} + +let isBranch = 1, isIndirectBranch = 1, isTerminator = 1, hasCtrlDep = 1 in { + def BEQ : BranchC<0x27, 0x00, 0x000, "beq ">; + def BNE : BranchC<0x27, 0x01, 0x000, "bne ">; + def BLT : BranchC<0x27, 0x02, 0x000, "blt ">; + def BLE : BranchC<0x27, 0x03, 0x000, "ble ">; + def BGT : BranchC<0x27, 0x04, 0x000, "bgt ">; + def BGE : BranchC<0x27, 0x05, 0x000, "bge ">; +} + +let isBranch = 1, isTerminator = 1, hasDelaySlot = 1, hasCtrlDep = 1, + isBarrier = 1 in { + def BRID : BranchI<0x2E, 0x10, "brid ">; + def BRAID : BranchI<0x2E, 0x18, "braid ">; +} + +let isBranch = 1, isTerminator = 1, hasDelaySlot = 1, hasCtrlDep = 1 in { + def BEQID : BranchCI<0x2F, 0x10, "beqid ">; + def BNEID : BranchCI<0x2F, 0x11, "bneid ">; + def BLTID : BranchCI<0x2F, 0x12, "bltid ">; + def BLEID : BranchCI<0x2F, 0x13, "bleid ">; + def BGTID : BranchCI<0x2F, 0x14, "bgtid ">; + def BGEID : BranchCI<0x2F, 0x15, "bgeid ">; +} + +let isBranch = 1, isIndirectBranch = 1, isTerminator = 1, + hasDelaySlot = 1, hasCtrlDep = 1, isBarrier = 1 in { + def BRD : Branch<0x26, 0x10, 0x000, "brd ">; + def BRAD : Branch<0x26, 0x18, 0x000, "brad ">; +} + +let isBranch = 1, isIndirectBranch = 1, isTerminator = 1, + hasDelaySlot = 1, hasCtrlDep = 1 in { + def BEQD : BranchC<0x27, 0x10, 0x000, "beqd ">; + def BNED : BranchC<0x27, 0x11, 0x000, "bned ">; + def BLTD : BranchC<0x27, 0x12, 0x000, "bltd ">; + def BLED : BranchC<0x27, 0x13, 0x000, "bled ">; + def BGTD : BranchC<0x27, 0x14, 0x000, "bgtd ">; + def BGED : BranchC<0x27, 0x15, 0x000, "bged ">; +} + +let isCall =1, hasDelaySlot = 1, + Defs = [R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,CARRY], + Uses = [R1] in { + def BRLID : BranchLI<0x2E, 0x14, "brlid ">; + def BRALID : BranchLI<0x2E, 0x1C, "bralid ">; +} + +let isCall = 1, hasDelaySlot = 1, + Defs = [R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,CARRY], + Uses = [R1] in { + def BRLD : BranchL<0x26, 0x14, 0x000, "brld ">; + def BRALD : BranchL<0x26, 0x1C, 0x000, "brald ">; +} + +let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, + rd=0x10, Form=FCRI in { + def RTSD : TB<0x2D, (outs), (ins GPR:$target, simm16:$imm), + "rtsd $target, $imm", + [], + IIC_BR>; +} + +let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, + rd=0x11, Form=FCRI in { + def RTID : TB<0x2D, (outs), (ins GPR:$target, simm16:$imm), + "rtid $target, $imm", + [], + IIC_BR>; +} + +let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, + rd=0x12, Form=FCRI in { + def RTBD : TB<0x2D, (outs), (ins GPR:$target, simm16:$imm), + "rtbd $target, $imm", + [], + IIC_BR>; +} + +let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, + rd=0x14, Form=FCRI in { + def RTED : TB<0x2D, (outs), (ins GPR:$target, simm16:$imm), + "rted $target, $imm", + [], + IIC_BR>; +} + +//===----------------------------------------------------------------------===// +// MBlaze misc instructions +//===----------------------------------------------------------------------===// + +let neverHasSideEffects = 1 in { + def NOP : MBlazeInst<0x20, FC, (outs), (ins), "nop ", [], IIC_ALU>; +} + +let Predicates=[HasPatCmp] in { + def CLZ : TCLZ<0x24, 0x00E0, (outs GPR:$dst), (ins GPR:$src), + "clz $dst, $src", [], IIC_ALU>; +} + +def IMEMBAR : MBAR<0x2E, 0x0420004, (outs), (ins), "mbar 2", [], IIC_ALU>; +def DMEMBAR : MBAR<0x2E, 0x0220004, (outs), (ins), "mbar 1", [], IIC_ALU>; +def IDMEMBAR : MBAR<0x2E, 0x0020004, (outs), (ins), "mbar 0", [], IIC_ALU>; + +let usesCustomInserter = 1 in { + def Select_CC : MBlazePseudo<(outs GPR:$dst), + (ins GPR:$T, GPR:$F, GPR:$CMP, i32imm:$CC), // F T reversed + "; SELECT_CC PSEUDO!", + []>; + + def ShiftL : MBlazePseudo<(outs GPR:$dst), + (ins GPR:$L, GPR:$R), + "; ShiftL PSEUDO!", + []>; + + def ShiftRA : MBlazePseudo<(outs GPR:$dst), + (ins GPR:$L, GPR:$R), + "; ShiftRA PSEUDO!", + []>; + + def ShiftRL : MBlazePseudo<(outs GPR:$dst), + (ins GPR:$L, GPR:$R), + "; ShiftRL PSEUDO!", + []>; +} + +let rb = 0 in { + def SEXT16 : TA<0x24, 0x061, (outs GPR:$dst), (ins GPR:$src), + "sext16 $dst, $src", [], IIC_ALU>; + def SEXT8 : TA<0x24, 0x060, (outs GPR:$dst), (ins GPR:$src), + "sext8 $dst, $src", [], IIC_ALU>; + let Defs = [CARRY] in { + def SRL : TA<0x24, 0x041, (outs GPR:$dst), (ins GPR:$src), + "srl $dst, $src", [], IIC_ALU>; + def SRA : TA<0x24, 0x001, (outs GPR:$dst), (ins GPR:$src), + "sra $dst, $src", [], IIC_ALU>; + let Uses = [CARRY] in { + def SRC : TA<0x24, 0x021, (outs GPR:$dst), (ins GPR:$src), + "src $dst, $src", [], IIC_ALU>; + } + } +} + +let isCodeGenOnly=1 in { + def ADDIK32 : ArithI32<0x08, "addik ", simm16, immSExt16>; + def ORI32 : LogicI32<0x28, "ori ">; + def BRLID32 : BranchLI<0x2E, 0x14, "brlid ">; +} + +//===----------------------------------------------------------------------===// +// Misc. instructions +//===----------------------------------------------------------------------===// +let Form=FRCS in { + def MFS : SPC<0x25, 0x2, (outs GPR:$dst), (ins SPR:$src), + "mfs $dst, $src", [], IIC_ALU>; +} + +let Form=FCRCS in { + def MTS : SPC<0x25, 0x3, (outs SPR:$dst), (ins GPR:$src), + "mts $dst, $src", [], IIC_ALU>; +} + +def MSRSET : MSR<0x25, 0x20, (outs GPR:$dst), (ins uimm15:$set), + "msrset $dst, $set", [], IIC_ALU>; + +def MSRCLR : MSR<0x25, 0x22, (outs GPR:$dst), (ins uimm15:$clr), + "msrclr $dst, $clr", [], IIC_ALU>; + +let rd=0x0, Form=FCRR in { + def WDC : TA<0x24, 0x64, (outs), (ins GPR:$a, GPR:$b), + "wdc $a, $b", [], IIC_WDC>; + def WDCF : TA<0x24, 0x74, (outs), (ins GPR:$a, GPR:$b), + "wdc.flush $a, $b", [], IIC_WDC>; + def WDCC : TA<0x24, 0x66, (outs), (ins GPR:$a, GPR:$b), + "wdc.clear $a, $b", [], IIC_WDC>; + def WIC : TA<0x24, 0x68, (outs), (ins GPR:$a, GPR:$b), + "wic $a, $b", [], IIC_WDC>; +} + +def BRK : BranchL<0x26, 0x0C, 0x000, "brk ">; +def BRKI : BranchLI<0x2E, 0x0C, "brki ">; + +def IMM : MBlazeInst<0x2C, FCCI, (outs), (ins simm16:$imm), + "imm $imm", [], IIC_ALU>; + +//===----------------------------------------------------------------------===// +// Pseudo instructions for atomic operations +//===----------------------------------------------------------------------===// +let usesCustomInserter=1 in { + def CAS32 : MBlazePseudo<(outs GPR:$dst), (ins GPR:$ptr, GPR:$cmp, GPR:$swp), + "# atomic compare and swap", + [(set GPR:$dst, (atomic_cmp_swap_32 GPR:$ptr, GPR:$cmp, GPR:$swp))]>; + + def SWP32 : MBlazePseudo<(outs GPR:$dst), (ins GPR:$ptr, GPR:$swp), + "# atomic swap", + [(set GPR:$dst, (atomic_swap_32 GPR:$ptr, GPR:$swp))]>; + + def LAA32 : MBlazePseudo<(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), + "# atomic load and add", + [(set GPR:$dst, (atomic_load_add_32 GPR:$ptr, GPR:$val))]>; + + def LAS32 : MBlazePseudo<(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), + "# atomic load and sub", + [(set GPR:$dst, (atomic_load_sub_32 GPR:$ptr, GPR:$val))]>; + + def LAD32 : MBlazePseudo<(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), + "# atomic load and and", + [(set GPR:$dst, (atomic_load_and_32 GPR:$ptr, GPR:$val))]>; + + def LAO32 : MBlazePseudo<(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), + "# atomic load and or", + [(set GPR:$dst, (atomic_load_or_32 GPR:$ptr, GPR:$val))]>; + + def LAX32 : MBlazePseudo<(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), + "# atomic load and xor", + [(set GPR:$dst, (atomic_load_xor_32 GPR:$ptr, GPR:$val))]>; + + def LAN32 : MBlazePseudo<(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), + "# atomic load and nand", + [(set GPR:$dst, (atomic_load_nand_32 GPR:$ptr, GPR:$val))]>; + + def MEMBARRIER : MBlazePseudo<(outs), (ins), + "# memory barrier", + [(membarrier (i32 imm), (i32 imm), (i32 imm), (i32 imm), (i32 imm))]>; +} + +//===----------------------------------------------------------------------===// +// Arbitrary patterns that map to one or more instructions +//===----------------------------------------------------------------------===// + +// Small immediates +def : Pat<(i32 0), (ADDK (i32 R0), (i32 R0))>; +def : Pat<(i32 immSExt16:$imm), (ADDIK (i32 R0), imm:$imm)>; +def : Pat<(i32 immZExt16:$imm), (ORI (i32 R0), imm:$imm)>; + +// Arbitrary immediates +def : Pat<(i32 imm:$imm), (ADDIK (i32 R0), imm:$imm)>; + +// In register sign extension +def : Pat<(sext_inreg GPR:$src, i16), (SEXT16 GPR:$src)>; +def : Pat<(sext_inreg GPR:$src, i8), (SEXT8 GPR:$src)>; + +// Call +def : Pat<(MBlazeJmpLink (i32 tglobaladdr:$dst)), + (BRLID (i32 R15), tglobaladdr:$dst)>; + +def : Pat<(MBlazeJmpLink (i32 texternalsym:$dst)), + (BRLID (i32 R15), texternalsym:$dst)>; + +def : Pat<(MBlazeJmpLink GPR:$dst), + (BRALD (i32 R15), GPR:$dst)>; + +// Shift Instructions +def : Pat<(shl GPR:$L, GPR:$R), (ShiftL GPR:$L, GPR:$R)>; +def : Pat<(sra GPR:$L, GPR:$R), (ShiftRA GPR:$L, GPR:$R)>; +def : Pat<(srl GPR:$L, GPR:$R), (ShiftRL GPR:$L, GPR:$R)>; + +// SET_CC operations +def : Pat<(setcc (i32 GPR:$L), (i32 0), SETEQ), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), GPR:$L, 1)>; +def : Pat<(setcc (i32 GPR:$L), (i32 0), SETNE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), GPR:$L, 2)>; +def : Pat<(setcc (i32 GPR:$L), (i32 0), SETGT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), GPR:$L, 3)>; +def : Pat<(setcc (i32 GPR:$L), (i32 0), SETLT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), GPR:$L, 4)>; +def : Pat<(setcc (i32 GPR:$L), (i32 0), SETGE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), GPR:$L, 5)>; +def : Pat<(setcc (i32 GPR:$L), (i32 0), SETLE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), GPR:$L, 6)>; +def : Pat<(setcc (i32 GPR:$L), (i32 0), SETUGT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMPU (i32 R0), GPR:$L), 3)>; +def : Pat<(setcc (i32 GPR:$L), (i32 0), SETULT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMPU (i32 R0), GPR:$L), 4)>; +def : Pat<(setcc (i32 GPR:$L), (i32 0), SETUGE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMPU (i32 R0), GPR:$L), 5)>; +def : Pat<(setcc (i32 GPR:$L), (i32 0), SETULE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMPU (i32 R0), GPR:$L), 6)>; + +def : Pat<(setcc (i32 0), (i32 GPR:$R), SETEQ), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), GPR:$R, 1)>; +def : Pat<(setcc (i32 0), (i32 GPR:$R), SETNE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), GPR:$R, 2)>; +def : Pat<(setcc (i32 0), (i32 GPR:$R), SETGT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), GPR:$R, 3)>; +def : Pat<(setcc (i32 0), (i32 GPR:$R), SETLT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), GPR:$R, 4)>; +def : Pat<(setcc (i32 0), (i32 GPR:$R), SETGE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), GPR:$R, 5)>; +def : Pat<(setcc (i32 0), (i32 GPR:$R), SETLE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), GPR:$R, 6)>; +def : Pat<(setcc (i32 0), (i32 GPR:$R), SETUGT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMPU GPR:$R, (i32 R0)), 3)>; +def : Pat<(setcc (i32 0), (i32 GPR:$R), SETULT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMPU GPR:$R, (i32 R0)), 4)>; +def : Pat<(setcc (i32 0), (i32 GPR:$R), SETUGE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMPU GPR:$R, (i32 R0)), 5)>; +def : Pat<(setcc (i32 0), (i32 GPR:$R), SETULE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMPU GPR:$R, (i32 R0)), 6)>; + +def : Pat<(setcc (i32 GPR:$L), (i32 GPR:$R), SETEQ), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMP GPR:$R, GPR:$L), 1)>; +def : Pat<(setcc (i32 GPR:$L), (i32 GPR:$R), SETNE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMP GPR:$R, GPR:$L), 2)>; +def : Pat<(setcc (i32 GPR:$L), (i32 GPR:$R), SETGT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMP GPR:$R, GPR:$L), 3)>; +def : Pat<(setcc (i32 GPR:$L), (i32 GPR:$R), SETLT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMP GPR:$R, GPR:$L), 4)>; +def : Pat<(setcc (i32 GPR:$L), (i32 GPR:$R), SETGE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMP GPR:$R, GPR:$L), 5)>; +def : Pat<(setcc (i32 GPR:$L), (i32 GPR:$R), SETLE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMP GPR:$R, GPR:$L), 6)>; +def : Pat<(setcc (i32 GPR:$L), (i32 GPR:$R), SETUGT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMPU GPR:$R, GPR:$L), 3)>; +def : Pat<(setcc (i32 GPR:$L), (i32 GPR:$R), SETULT), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMPU GPR:$R, GPR:$L), 4)>; +def : Pat<(setcc (i32 GPR:$L), (i32 GPR:$R), SETUGE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMPU GPR:$R, GPR:$L), 5)>; +def : Pat<(setcc (i32 GPR:$L), (i32 GPR:$R), SETULE), + (Select_CC (ADDIK (i32 R0), 1), (ADDIK (i32 R0), 0), + (CMPU GPR:$R, GPR:$L), 6)>; + +// SELECT operations +def : Pat<(select (i32 GPR:$C), (i32 GPR:$T), (i32 GPR:$F)), + (Select_CC GPR:$T, GPR:$F, GPR:$C, 2)>; + +// SELECT_CC +def : Pat<(selectcc (i32 GPR:$L), (i32 0), + (i32 GPR:$T), (i32 GPR:$F), SETEQ), + (Select_CC GPR:$T, GPR:$F, GPR:$L, 1)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 0), + (i32 GPR:$T), (i32 GPR:$F), SETNE), + (Select_CC GPR:$T, GPR:$F, GPR:$L, 2)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 0), + (i32 GPR:$T), (i32 GPR:$F), SETGT), + (Select_CC GPR:$T, GPR:$F, GPR:$L, 3)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 0), + (i32 GPR:$T), (i32 GPR:$F), SETLT), + (Select_CC GPR:$T, GPR:$F, GPR:$L, 4)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 0), + (i32 GPR:$T), (i32 GPR:$F), SETGE), + (Select_CC GPR:$T, GPR:$F, GPR:$L, 5)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 0), + (i32 GPR:$T), (i32 GPR:$F), SETLE), + (Select_CC GPR:$T, GPR:$F, GPR:$L, 6)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 0), + (i32 GPR:$T), (i32 GPR:$F), SETUGT), + (Select_CC GPR:$T, GPR:$F, (CMPU (i32 R0), GPR:$L), 3)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 0), + (i32 GPR:$T), (i32 GPR:$F), SETULT), + (Select_CC GPR:$T, GPR:$F, (CMPU (i32 R0), GPR:$L), 4)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 0), + (i32 GPR:$T), (i32 GPR:$F), SETUGE), + (Select_CC GPR:$T, GPR:$F, (CMPU (i32 R0), GPR:$L), 5)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 0), + (i32 GPR:$T), (i32 GPR:$F), SETULE), + (Select_CC GPR:$T, GPR:$F, (CMPU (i32 R0), GPR:$L), 6)>; + +def : Pat<(selectcc (i32 0), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETEQ), + (Select_CC GPR:$T, GPR:$F, GPR:$R, 1)>; +def : Pat<(selectcc (i32 0), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETNE), + (Select_CC GPR:$T, GPR:$F, GPR:$R, 2)>; +def : Pat<(selectcc (i32 0), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETGT), + (Select_CC GPR:$T, GPR:$F, GPR:$R, 3)>; +def : Pat<(selectcc (i32 0), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETLT), + (Select_CC GPR:$T, GPR:$F, GPR:$R, 4)>; +def : Pat<(selectcc (i32 0), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETGE), + (Select_CC GPR:$T, GPR:$F, GPR:$R, 5)>; +def : Pat<(selectcc (i32 0), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETLE), + (Select_CC GPR:$T, GPR:$F, GPR:$R, 6)>; +def : Pat<(selectcc (i32 0), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETUGT), + (Select_CC GPR:$T, GPR:$F, (CMPU GPR:$R, (i32 R0)), 3)>; +def : Pat<(selectcc (i32 0), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETULT), + (Select_CC GPR:$T, GPR:$F, (CMPU GPR:$R, (i32 R0)), 4)>; +def : Pat<(selectcc (i32 0), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETUGE), + (Select_CC GPR:$T, GPR:$F, (CMPU GPR:$R, (i32 R0)), 5)>; +def : Pat<(selectcc (i32 0), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETULE), + (Select_CC GPR:$T, GPR:$F, (CMPU GPR:$R, (i32 R0)), 6)>; + +def : Pat<(selectcc (i32 GPR:$L), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETEQ), + (Select_CC GPR:$T, GPR:$F, (CMP GPR:$R, GPR:$L), 1)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETNE), + (Select_CC GPR:$T, GPR:$F, (CMP GPR:$R, GPR:$L), 2)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETGT), + (Select_CC GPR:$T, GPR:$F, (CMP GPR:$R, GPR:$L), 3)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETLT), + (Select_CC GPR:$T, GPR:$F, (CMP GPR:$R, GPR:$L), 4)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETGE), + (Select_CC GPR:$T, GPR:$F, (CMP GPR:$R, GPR:$L), 5)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETLE), + (Select_CC GPR:$T, GPR:$F, (CMP GPR:$R, GPR:$L), 6)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETUGT), + (Select_CC GPR:$T, GPR:$F, (CMPU GPR:$R, GPR:$L), 3)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETULT), + (Select_CC GPR:$T, GPR:$F, (CMPU GPR:$R, GPR:$L), 4)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETUGE), + (Select_CC GPR:$T, GPR:$F, (CMPU GPR:$R, GPR:$L), 5)>; +def : Pat<(selectcc (i32 GPR:$L), (i32 GPR:$R), + (i32 GPR:$T), (i32 GPR:$F), SETULE), + (Select_CC GPR:$T, GPR:$F, (CMPU GPR:$R, GPR:$L), 6)>; + +// Ret instructions +def : Pat<(MBlazeRet GPR:$target), (RTSD GPR:$target, 0x8)>; +def : Pat<(MBlazeIRet GPR:$target), (RTID GPR:$target, 0x0)>; + +// BR instructions +def : Pat<(br bb:$T), (BRID bb:$T)>; +def : Pat<(brind GPR:$T), (BRAD GPR:$T)>; + +// BRCOND instructions +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 0), SETEQ), bb:$T), + (BEQID GPR:$L, bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 0), SETNE), bb:$T), + (BNEID GPR:$L, bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 0), SETGT), bb:$T), + (BGTID GPR:$L, bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 0), SETLT), bb:$T), + (BLTID GPR:$L, bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 0), SETGE), bb:$T), + (BGEID GPR:$L, bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 0), SETLE), bb:$T), + (BLEID GPR:$L, bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 0), SETUGT), bb:$T), + (BGTID (CMPU (i32 R0), GPR:$L), bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 0), SETULT), bb:$T), + (BLTID (CMPU (i32 R0), GPR:$L), bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 0), SETUGE), bb:$T), + (BGEID (CMPU (i32 R0), GPR:$L), bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 0), SETULE), bb:$T), + (BLEID (CMPU (i32 R0), GPR:$L), bb:$T)>; + +def : Pat<(brcond (setcc (i32 0), (i32 GPR:$R), SETEQ), bb:$T), + (BEQID GPR:$R, bb:$T)>; +def : Pat<(brcond (setcc (i32 0), (i32 GPR:$R), SETNE), bb:$T), + (BNEID GPR:$R, bb:$T)>; +def : Pat<(brcond (setcc (i32 0), (i32 GPR:$R), SETGT), bb:$T), + (BGTID GPR:$R, bb:$T)>; +def : Pat<(brcond (setcc (i32 0), (i32 GPR:$R), SETLT), bb:$T), + (BLTID GPR:$R, bb:$T)>; +def : Pat<(brcond (setcc (i32 0), (i32 GPR:$R), SETGE), bb:$T), + (BGEID GPR:$R, bb:$T)>; +def : Pat<(brcond (setcc (i32 0), (i32 GPR:$R), SETLE), bb:$T), + (BLEID GPR:$R, bb:$T)>; +def : Pat<(brcond (setcc (i32 0), (i32 GPR:$R), SETUGT), bb:$T), + (BGTID (CMPU GPR:$R, (i32 R0)), bb:$T)>; +def : Pat<(brcond (setcc (i32 0), (i32 GPR:$R), SETULT), bb:$T), + (BLTID (CMPU GPR:$R, (i32 R0)), bb:$T)>; +def : Pat<(brcond (setcc (i32 0), (i32 GPR:$R), SETUGE), bb:$T), + (BGEID (CMPU GPR:$R, (i32 R0)), bb:$T)>; +def : Pat<(brcond (setcc (i32 0), (i32 GPR:$R), SETULE), bb:$T), + (BLEID (CMPU GPR:$R, (i32 R0)), bb:$T)>; + +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 GPR:$R), SETEQ), bb:$T), + (BEQID (CMP GPR:$R, GPR:$L), bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 GPR:$R), SETNE), bb:$T), + (BNEID (CMP GPR:$R, GPR:$L), bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 GPR:$R), SETGT), bb:$T), + (BGTID (CMP GPR:$R, GPR:$L), bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 GPR:$R), SETLT), bb:$T), + (BLTID (CMP GPR:$R, GPR:$L), bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 GPR:$R), SETGE), bb:$T), + (BGEID (CMP GPR:$R, GPR:$L), bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 GPR:$R), SETLE), bb:$T), + (BLEID (CMP GPR:$R, GPR:$L), bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 GPR:$R), SETUGT), bb:$T), + (BGTID (CMPU GPR:$R, GPR:$L), bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 GPR:$R), SETULT), bb:$T), + (BLTID (CMPU GPR:$R, GPR:$L), bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 GPR:$R), SETUGE), bb:$T), + (BGEID (CMPU GPR:$R, GPR:$L), bb:$T)>; +def : Pat<(brcond (setcc (i32 GPR:$L), (i32 GPR:$R), SETULE), bb:$T), + (BLEID (CMPU GPR:$R, GPR:$L), bb:$T)>; +def : Pat<(brcond (i32 GPR:$C), bb:$T), + (BNEID GPR:$C, bb:$T)>; + +// Jump tables, global addresses, and constant pools +def : Pat<(MBWrapper tglobaladdr:$in), (ORI (i32 R0), tglobaladdr:$in)>; +def : Pat<(MBWrapper tjumptable:$in), (ORI (i32 R0), tjumptable:$in)>; +def : Pat<(MBWrapper tconstpool:$in), (ORI (i32 R0), tconstpool:$in)>; + +// Misc instructions +def : Pat<(and (i32 GPR:$lh), (not (i32 GPR:$rh))),(ANDN GPR:$lh, GPR:$rh)>; + +// Convert any extend loads into zero extend loads +def : Pat<(extloadi8 iaddr:$src), (i32 (LBUI iaddr:$src))>; +def : Pat<(extloadi16 iaddr:$src), (i32 (LHUI iaddr:$src))>; +def : Pat<(extloadi8 xaddr:$src), (i32 (LBU xaddr:$src))>; +def : Pat<(extloadi16 xaddr:$src), (i32 (LHU xaddr:$src))>; + +// 32-bit load and store +def : Pat<(store (i32 GPR:$dst), xaddr:$addr), (SW GPR:$dst, xaddr:$addr)>; +def : Pat<(load xaddr:$addr), (i32 (LW xaddr:$addr))>; + +// 16-bit load and store +def : Pat<(truncstorei16 (i32 GPR:$dst), xaddr:$ad), (SH GPR:$dst, xaddr:$ad)>; +def : Pat<(zextloadi16 xaddr:$addr), (i32 (LHU xaddr:$addr))>; + +// 8-bit load and store +def : Pat<(truncstorei8 (i32 GPR:$dst), xaddr:$ad), (SB GPR:$dst, xaddr:$ad)>; +def : Pat<(zextloadi8 xaddr:$addr), (i32 (LBU xaddr:$addr))>; + +// Peepholes +def : Pat<(store (i32 0), iaddr:$dst), (SWI (i32 R0), iaddr:$dst)>; + +// Atomic fence +def : Pat<(atomic_fence (imm), (imm)), (MEMBARRIER)>; + +//===----------------------------------------------------------------------===// +// Floating Point Support +//===----------------------------------------------------------------------===// +include "MBlazeInstrFSL.td" +include "MBlazeInstrFPU.td" diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeIntrinsicInfo.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeIntrinsicInfo.cpp new file mode 100644 index 0000000..91aaf94 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeIntrinsicInfo.cpp @@ -0,0 +1,111 @@ +//===-- MBlazeIntrinsicInfo.cpp - Intrinsic Information -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the MBlaze implementation of TargetIntrinsicInfo. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeIntrinsicInfo.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/Intrinsics.h" +#include "llvm/Module.h" +#include "llvm/Type.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" +#include <cstring> + +using namespace llvm; + +namespace mblazeIntrinsic { + + enum ID { + last_non_mblaze_intrinsic = Intrinsic::num_intrinsics-1, +#define GET_INTRINSIC_ENUM_VALUES +#include "MBlazeGenIntrinsics.inc" +#undef GET_INTRINSIC_ENUM_VALUES + , num_mblaze_intrinsics + }; + +#define GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN +#include "MBlazeGenIntrinsics.inc" +#undef GET_LLVM_INTRINSIC_FOR_GCC_BUILTIN +} + +std::string MBlazeIntrinsicInfo::getName(unsigned IntrID, Type **Tys, + unsigned numTys) const { + static const char *const names[] = { +#define GET_INTRINSIC_NAME_TABLE +#include "MBlazeGenIntrinsics.inc" +#undef GET_INTRINSIC_NAME_TABLE + }; + + assert(!isOverloaded(IntrID) && "MBlaze intrinsics are not overloaded"); + if (IntrID < Intrinsic::num_intrinsics) + return 0; + assert(IntrID < mblazeIntrinsic::num_mblaze_intrinsics && + "Invalid intrinsic ID"); + + std::string Result(names[IntrID - Intrinsic::num_intrinsics]); + return Result; +} + +unsigned MBlazeIntrinsicInfo:: +lookupName(const char *Name, unsigned Len) const { + if (Len < 5 || Name[4] != '.' || Name[0] != 'l' || Name[1] != 'l' + || Name[2] != 'v' || Name[3] != 'm') + return 0; // All intrinsics start with 'llvm.' + +#define GET_FUNCTION_RECOGNIZER +#include "MBlazeGenIntrinsics.inc" +#undef GET_FUNCTION_RECOGNIZER + return 0; +} + +unsigned MBlazeIntrinsicInfo:: +lookupGCCName(const char *Name) const { + return mblazeIntrinsic::getIntrinsicForGCCBuiltin("mblaze",Name); +} + +bool MBlazeIntrinsicInfo::isOverloaded(unsigned IntrID) const { + if (IntrID == 0) + return false; + + unsigned id = IntrID - Intrinsic::num_intrinsics + 1; +#define GET_INTRINSIC_OVERLOAD_TABLE +#include "MBlazeGenIntrinsics.inc" +#undef GET_INTRINSIC_OVERLOAD_TABLE +} + +/// This defines the "getAttributes(ID id)" method. +#define GET_INTRINSIC_ATTRIBUTES +#include "MBlazeGenIntrinsics.inc" +#undef GET_INTRINSIC_ATTRIBUTES + +static FunctionType *getType(LLVMContext &Context, unsigned id) { + Type *ResultTy = NULL; + SmallVector<Type*, 8> ArgTys; + bool IsVarArg = false; + +#define GET_INTRINSIC_GENERATOR +#include "MBlazeGenIntrinsics.inc" +#undef GET_INTRINSIC_GENERATOR + + return FunctionType::get(ResultTy, ArgTys, IsVarArg); +} + +Function *MBlazeIntrinsicInfo::getDeclaration(Module *M, unsigned IntrID, + Type **Tys, + unsigned numTy) const { + assert(!isOverloaded(IntrID) && "MBlaze intrinsics are not overloaded"); + AttrListPtr AList = getAttributes((mblazeIntrinsic::ID) IntrID); + return cast<Function>(M->getOrInsertFunction(getName(IntrID), + getType(M->getContext(), IntrID), + AList)); +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeIntrinsicInfo.h b/contrib/llvm/lib/Target/MBlaze/MBlazeIntrinsicInfo.h new file mode 100644 index 0000000..34f3792 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeIntrinsicInfo.h @@ -0,0 +1,33 @@ +//===-- MBlazeIntrinsicInfo.h - MBlaze Intrinsic Information ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the MBlaze implementation of TargetIntrinsicInfo. +// +//===----------------------------------------------------------------------===// +#ifndef MBLAZEINTRINSICS_H +#define MBLAZEINTRINSICS_H + +#include "llvm/Target/TargetIntrinsicInfo.h" + +namespace llvm { + + class MBlazeIntrinsicInfo : public TargetIntrinsicInfo { + public: + std::string getName(unsigned IntrID, Type **Tys = 0, + unsigned numTys = 0) const; + unsigned lookupName(const char *Name, unsigned Len) const; + unsigned lookupGCCName(const char *Name) const; + bool isOverloaded(unsigned IID) const; + Function *getDeclaration(Module *M, unsigned ID, Type **Tys = 0, + unsigned numTys = 0) const; + }; + +} + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeIntrinsics.td b/contrib/llvm/lib/Target/MBlaze/MBlazeIntrinsics.td new file mode 100644 index 0000000..b5dc595 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeIntrinsics.td @@ -0,0 +1,131 @@ +//===-- IntrinsicsMBlaze.td - Defines MBlaze intrinsics ----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines all of the MicroBlaze-specific intrinsics. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Definitions for all MBlaze intrinsics. +// + +// MBlaze intrinsic classes. +let TargetPrefix = "mblaze", isTarget = 1 in { + class MBFSL_Get_Intrinsic : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], []>; + + class MBFSL_Put_Intrinsic : Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; + + class MBFSL_PutT_Intrinsic : Intrinsic<[], [llvm_i32_ty], []>; +} + +//===----------------------------------------------------------------------===// +// MicroBlaze FSL Get Intrinsic Definitions. +// + +def int_mblaze_fsl_get : GCCBuiltin<"__builtin_mblaze_fsl_get">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_aget : GCCBuiltin<"__builtin_mblaze_fsl_aget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_cget : GCCBuiltin<"__builtin_mblaze_fsl_cget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_caget : GCCBuiltin<"__builtin_mblaze_fsl_caget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_eget : GCCBuiltin<"__builtin_mblaze_fsl_eget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_eaget : GCCBuiltin<"__builtin_mblaze_fsl_eaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_ecget : GCCBuiltin<"__builtin_mblaze_fsl_ecget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_ecaget : GCCBuiltin<"__builtin_mblaze_fsl_ecaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_nget : GCCBuiltin<"__builtin_mblaze_fsl_nget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_naget : GCCBuiltin<"__builtin_mblaze_fsl_naget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_ncget : GCCBuiltin<"__builtin_mblaze_fsl_ncget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_ncaget : GCCBuiltin<"__builtin_mblaze_fsl_ncaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_neget : GCCBuiltin<"__builtin_mblaze_fsl_neget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_neaget : GCCBuiltin<"__builtin_mblaze_fsl_neaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_necget : GCCBuiltin<"__builtin_mblaze_fsl_necget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_necaget : GCCBuiltin<"__builtin_mblaze_fsl_necaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tget : GCCBuiltin<"__builtin_mblaze_fsl_tget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_taget : GCCBuiltin<"__builtin_mblaze_fsl_taget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tcget : GCCBuiltin<"__builtin_mblaze_fsl_tcget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tcaget : GCCBuiltin<"__builtin_mblaze_fsl_tcaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_teget : GCCBuiltin<"__builtin_mblaze_fsl_teget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_teaget : GCCBuiltin<"__builtin_mblaze_fsl_teaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tecget : GCCBuiltin<"__builtin_mblaze_fsl_tecget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tecaget : GCCBuiltin<"__builtin_mblaze_fsl_tecaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tnget : GCCBuiltin<"__builtin_mblaze_fsl_tnget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tnaget : GCCBuiltin<"__builtin_mblaze_fsl_tnaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tncget : GCCBuiltin<"__builtin_mblaze_fsl_tncget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tncaget : GCCBuiltin<"__builtin_mblaze_fsl_tncaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tneget : GCCBuiltin<"__builtin_mblaze_fsl_tneget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tneaget : GCCBuiltin<"__builtin_mblaze_fsl_tneaget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tnecget : GCCBuiltin<"__builtin_mblaze_fsl_tnecget">, + MBFSL_Get_Intrinsic; +def int_mblaze_fsl_tnecaget : GCCBuiltin<"__builtin_mblaze_fsl_tnecaget">, + MBFSL_Get_Intrinsic; + +//===----------------------------------------------------------------------===// +// MicroBlaze FSL Put Intrinsic Definitions. +// + +def int_mblaze_fsl_put : GCCBuiltin<"__builtin_mblaze_fsl_put">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_aput : GCCBuiltin<"__builtin_mblaze_fsl_aput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_cput : GCCBuiltin<"__builtin_mblaze_fsl_cput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_caput : GCCBuiltin<"__builtin_mblaze_fsl_caput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_nput : GCCBuiltin<"__builtin_mblaze_fsl_nput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_naput : GCCBuiltin<"__builtin_mblaze_fsl_naput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_ncput : GCCBuiltin<"__builtin_mblaze_fsl_ncput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_ncaput : GCCBuiltin<"__builtin_mblaze_fsl_ncaput">, + MBFSL_Put_Intrinsic; +def int_mblaze_fsl_tput : GCCBuiltin<"__builtin_mblaze_fsl_tput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_taput : GCCBuiltin<"__builtin_mblaze_fsl_taput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_tcput : GCCBuiltin<"__builtin_mblaze_fsl_tcput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_tcaput : GCCBuiltin<"__builtin_mblaze_fsl_tcaput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_tnput : GCCBuiltin<"__builtin_mblaze_fsl_tnput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_tnaput : GCCBuiltin<"__builtin_mblaze_fsl_tnaput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_tncput : GCCBuiltin<"__builtin_mblaze_fsl_tncput">, + MBFSL_PutT_Intrinsic; +def int_mblaze_fsl_tncaput : GCCBuiltin<"__builtin_mblaze_fsl_tncaput">, + MBFSL_PutT_Intrinsic; diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeMCInstLower.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeMCInstLower.cpp new file mode 100644 index 0000000..6b9f42e --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeMCInstLower.cpp @@ -0,0 +1,167 @@ +//===-- MBlazeMCInstLower.cpp - Convert MBlaze MachineInstr to an MCInst---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower MBlaze MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeMCInstLower.h" +#include "MBlazeInstrInfo.h" +#include "llvm/Constants.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/SmallString.h" +using namespace llvm; + +MCSymbol *MBlazeMCInstLower:: +GetGlobalAddressSymbol(const MachineOperand &MO) const { + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + return Printer.Mang->getSymbol(MO.getGlobal()); +} + +MCSymbol *MBlazeMCInstLower:: +GetExternalSymbolSymbol(const MachineOperand &MO) const { + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + return Printer.GetExternalSymbolSymbol(MO.getSymbolName()); +} + +MCSymbol *MBlazeMCInstLower:: +GetJumpTableSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "JTI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *MBlazeMCInstLower:: +GetConstantPoolIndexSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "CPI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + + switch (MO.getTargetFlags()) { + default: + llvm_unreachable("Unknown target flag on GV operand"); + + case 0: break; + } + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *MBlazeMCInstLower:: +GetBlockAddressSymbol(const MachineOperand &MO) const { + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + return Printer.GetBlockAddressSymbol(MO.getBlockAddress()); +} + +MCOperand MBlazeMCInstLower:: +LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const { + // FIXME: We would like an efficient form for this, so we don't have to do a + // lot of extra uniquing. + const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); + + switch (MO.getTargetFlags()) { + default: + llvm_unreachable("Unknown target flag on GV operand"); + + case 0: break; + } + + if (!MO.isJTI() && MO.getOffset()) + Expr = MCBinaryExpr::CreateAdd(Expr, + MCConstantExpr::Create(MO.getOffset(), Ctx), + Ctx); + return MCOperand::CreateExpr(Expr); +} + +void MBlazeMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + + MCOperand MCOp; + switch (MO.getType()) { + default: llvm_unreachable("unknown operand type"); + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) continue; + MCOp = MCOperand::CreateReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::CreateImm(MO.getImm()); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( + MO.getMBB()->getSymbol(), Ctx)); + break; + case MachineOperand::MO_GlobalAddress: + MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); + break; + case MachineOperand::MO_ExternalSymbol: + MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); + break; + case MachineOperand::MO_JumpTableIndex: + MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO)); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO)); + break; + case MachineOperand::MO_BlockAddress: + MCOp = LowerSymbolOperand(MO, GetBlockAddressSymbol(MO)); + break; + case MachineOperand::MO_FPImmediate: { + bool ignored; + APFloat FVal = MO.getFPImm()->getValueAPF(); + FVal.convert(APFloat::IEEEsingle, APFloat::rmTowardZero, &ignored); + + APInt IVal = FVal.bitcastToAPInt(); + uint64_t Val = *IVal.getRawData(); + MCOp = MCOperand::CreateImm(Val); + break; + } + case MachineOperand::MO_RegisterMask: + continue; + } + + OutMI.addOperand(MCOp); + } +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeMCInstLower.h b/contrib/llvm/lib/Target/MBlaze/MBlazeMCInstLower.h new file mode 100644 index 0000000..8ab2c9a --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeMCInstLower.h @@ -0,0 +1,47 @@ +//===-- MBlazeMCInstLower.h - Lower MachineInstr to MCInst ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZE_MCINSTLOWER_H +#define MBLAZE_MCINSTLOWER_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { + class AsmPrinter; + class MCContext; + class MCInst; + class MCOperand; + class MCSymbol; + class MachineInstr; + class MachineModuleInfoMachO; + class MachineOperand; + + /// MBlazeMCInstLower - This class is used to lower an MachineInstr + /// into an MCInst. +class LLVM_LIBRARY_VISIBILITY MBlazeMCInstLower { + MCContext &Ctx; + + AsmPrinter &Printer; +public: + MBlazeMCInstLower(MCContext &ctx, AsmPrinter &printer) + : Ctx(ctx), Printer(printer) {} + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + + MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; + + MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; + MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; + MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const; + MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; + MCSymbol *GetBlockAddressSymbol(const MachineOperand &MO) const; +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeMachineFunction.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeMachineFunction.cpp new file mode 100644 index 0000000..2217b54 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeMachineFunction.cpp @@ -0,0 +1,14 @@ +//===-- MBlazeMachineFunctionInfo.cpp - Private data ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeMachineFunction.h" + +using namespace llvm; + +void MBlazeFunctionInfo::anchor() { } diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeMachineFunction.h b/contrib/llvm/lib/Target/MBlaze/MBlazeMachineFunction.h new file mode 100644 index 0000000..95cc507 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeMachineFunction.h @@ -0,0 +1,169 @@ +//===-- MBlazeMachineFunctionInfo.h - Private data --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the MBlaze specific subclass of MachineFunctionInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZE_MACHINE_FUNCTION_INFO_H +#define MBLAZE_MACHINE_FUNCTION_INFO_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" + +namespace llvm { + +/// MBlazeFunctionInfo - This class is derived from MachineFunction private +/// MBlaze target-specific information for each MachineFunction. +class MBlazeFunctionInfo : public MachineFunctionInfo { + virtual void anchor(); + + /// Holds for each function where on the stack the Frame Pointer must be + /// saved. This is used on Prologue and Epilogue to emit FP save/restore + int FPStackOffset; + + /// Holds for each function where on the stack the Return Address must be + /// saved. This is used on Prologue and Epilogue to emit RA save/restore + int RAStackOffset; + + /// MBlazeFIHolder - Holds a FrameIndex and it's Stack Pointer Offset + struct MBlazeFIHolder { + + int FI; + int SPOffset; + + MBlazeFIHolder(int FrameIndex, int StackPointerOffset) + : FI(FrameIndex), SPOffset(StackPointerOffset) {} + }; + + /// When PIC is used the GP must be saved on the stack on the function + /// prologue and must be reloaded from this stack location after every + /// call. A reference to its stack location and frame index must be kept + /// to be used on emitPrologue and processFunctionBeforeFrameFinalized. + MBlazeFIHolder GPHolder; + + /// On LowerFormalArguments the stack size is unknown, so the Stack + /// Pointer Offset calculation of "not in register arguments" must be + /// postponed to emitPrologue. + SmallVector<MBlazeFIHolder, 16> FnLoadArgs; + bool HasLoadArgs; + + // When VarArgs, we must write registers back to caller stack, preserving + // on register arguments. Since the stack size is unknown on + // LowerFormalArguments, the Stack Pointer Offset calculation must be + // postponed to emitPrologue. + SmallVector<MBlazeFIHolder, 4> FnStoreVarArgs; + bool HasStoreVarArgs; + + // When determining the final stack layout some of the frame indexes may + // be replaced by new frame indexes that reside in the caller's stack + // frame. The replacements are recorded in this structure. + DenseMap<int,int> FIReplacements; + + /// SRetReturnReg - Some subtargets require that sret lowering includes + /// returning the value of the returned struct in a register. This field + /// holds the virtual register into which the sret argument is passed. + unsigned SRetReturnReg; + + /// GlobalBaseReg - keeps track of the virtual register initialized for + /// use as the global base register. This is used for PIC in some PIC + /// relocation models. + unsigned GlobalBaseReg; + + // VarArgsFrameIndex - FrameIndex for start of varargs area. + int VarArgsFrameIndex; + + /// LiveInFI - keeps track of the frame indexes in a callers stack + /// frame that are live into a function. + SmallVector<int, 16> LiveInFI; + +public: + MBlazeFunctionInfo(MachineFunction& MF) + : FPStackOffset(0), RAStackOffset(0), GPHolder(-1,-1), HasLoadArgs(false), + HasStoreVarArgs(false), SRetReturnReg(0), GlobalBaseReg(0), + VarArgsFrameIndex(0), LiveInFI() + {} + + int getFPStackOffset() const { return FPStackOffset; } + void setFPStackOffset(int Off) { FPStackOffset = Off; } + + int getRAStackOffset() const { return RAStackOffset; } + void setRAStackOffset(int Off) { RAStackOffset = Off; } + + int getGPStackOffset() const { return GPHolder.SPOffset; } + int getGPFI() const { return GPHolder.FI; } + void setGPStackOffset(int Off) { GPHolder.SPOffset = Off; } + void setGPFI(int FI) { GPHolder.FI = FI; } + bool needGPSaveRestore() const { return GPHolder.SPOffset != -1; } + + bool hasLoadArgs() const { return HasLoadArgs; } + bool hasStoreVarArgs() const { return HasStoreVarArgs; } + + void recordLiveIn(int FI) { + LiveInFI.push_back(FI); + } + + bool isLiveIn(int FI) { + for (unsigned i = 0, e = LiveInFI.size(); i < e; ++i) + if (FI == LiveInFI[i]) return true; + + return false; + } + + const SmallVector<int, 16>& getLiveIn() const { return LiveInFI; } + + void recordReplacement(int OFI, int NFI) { + FIReplacements.insert(std::make_pair(OFI,NFI)); + } + + bool hasReplacement(int OFI) const { + return FIReplacements.find(OFI) != FIReplacements.end(); + } + + int getReplacement(int OFI) const { + return FIReplacements.lookup(OFI); + } + + void recordLoadArgsFI(int FI, int SPOffset) { + if (!HasLoadArgs) HasLoadArgs=true; + FnLoadArgs.push_back(MBlazeFIHolder(FI, SPOffset)); + } + + void recordStoreVarArgsFI(int FI, int SPOffset) { + if (!HasStoreVarArgs) HasStoreVarArgs=true; + FnStoreVarArgs.push_back(MBlazeFIHolder(FI, SPOffset)); + } + + void adjustLoadArgsFI(MachineFrameInfo *MFI) const { + if (!hasLoadArgs()) return; + for (unsigned i = 0, e = FnLoadArgs.size(); i != e; ++i) + MFI->setObjectOffset(FnLoadArgs[i].FI, FnLoadArgs[i].SPOffset); + } + + void adjustStoreVarArgsFI(MachineFrameInfo *MFI) const { + if (!hasStoreVarArgs()) return; + for (unsigned i = 0, e = FnStoreVarArgs.size(); i != e; ++i) + MFI->setObjectOffset(FnStoreVarArgs[i].FI, FnStoreVarArgs[i].SPOffset); + } + + unsigned getSRetReturnReg() const { return SRetReturnReg; } + void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; } + + unsigned getGlobalBaseReg() const { return GlobalBaseReg; } + void setGlobalBaseReg(unsigned Reg) { GlobalBaseReg = Reg; } + + int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } + void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; } +}; + +} // end of namespace llvm + +#endif // MBLAZE_MACHINE_FUNCTION_INFO_H diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeRegisterInfo.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeRegisterInfo.cpp new file mode 100644 index 0000000..46f5207 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeRegisterInfo.cpp @@ -0,0 +1,191 @@ +//===-- MBlazeRegisterInfo.cpp - MBlaze Register Information --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the MBlaze implementation of the TargetRegisterInfo +// class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mblaze-frame-info" + +#include "MBlazeRegisterInfo.h" +#include "MBlaze.h" +#include "MBlazeSubtarget.h" +#include "MBlazeMachineFunction.h" +#include "llvm/Constants.h" +#include "llvm/Type.h" +#include "llvm/Function.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" + +#define GET_REGINFO_TARGET_DESC +#include "MBlazeGenRegisterInfo.inc" + +using namespace llvm; + +MBlazeRegisterInfo:: +MBlazeRegisterInfo(const MBlazeSubtarget &ST, const TargetInstrInfo &tii) + : MBlazeGenRegisterInfo(MBlaze::R15), Subtarget(ST), TII(tii) {} + +unsigned MBlazeRegisterInfo::getPICCallReg() { + return MBlaze::R20; +} + +//===----------------------------------------------------------------------===// +// Callee Saved Registers methods +//===----------------------------------------------------------------------===// + +/// MBlaze Callee Saved Registers +const uint16_t* MBlazeRegisterInfo:: +getCalleeSavedRegs(const MachineFunction *MF) const { + // MBlaze callee-save register range is R20 - R31 + static const uint16_t CalleeSavedRegs[] = { + MBlaze::R20, MBlaze::R21, MBlaze::R22, MBlaze::R23, + MBlaze::R24, MBlaze::R25, MBlaze::R26, MBlaze::R27, + MBlaze::R28, MBlaze::R29, MBlaze::R30, MBlaze::R31, + 0 + }; + + return CalleeSavedRegs; +} + +BitVector MBlazeRegisterInfo:: +getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + Reserved.set(MBlaze::R0); + Reserved.set(MBlaze::R1); + Reserved.set(MBlaze::R2); + Reserved.set(MBlaze::R13); + Reserved.set(MBlaze::R14); + Reserved.set(MBlaze::R15); + Reserved.set(MBlaze::R16); + Reserved.set(MBlaze::R17); + Reserved.set(MBlaze::R18); + Reserved.set(MBlaze::R19); + return Reserved; +} + +// This function eliminate ADJCALLSTACKDOWN/ADJCALLSTACKUP pseudo instructions +void MBlazeRegisterInfo:: +eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + + if (!TFI->hasReservedCallFrame(MF)) { + // If we have a frame pointer, turn the adjcallstackup instruction into a + // 'addi r1, r1, -<amt>' and the adjcallstackdown instruction into + // 'addi r1, r1, <amt>' + MachineInstr *Old = I; + int Amount = Old->getOperand(0).getImm() + 4; + if (Amount != 0) { + // We need to keep the stack aligned properly. To do this, we round the + // amount of space needed for the outgoing arguments up to the next + // alignment boundary. + unsigned Align = TFI->getStackAlignment(); + Amount = (Amount+Align-1)/Align*Align; + + MachineInstr *New; + if (Old->getOpcode() == MBlaze::ADJCALLSTACKDOWN) { + New = BuildMI(MF,Old->getDebugLoc(),TII.get(MBlaze::ADDIK),MBlaze::R1) + .addReg(MBlaze::R1).addImm(-Amount); + } else { + assert(Old->getOpcode() == MBlaze::ADJCALLSTACKUP); + New = BuildMI(MF,Old->getDebugLoc(),TII.get(MBlaze::ADDIK),MBlaze::R1) + .addReg(MBlaze::R1).addImm(Amount); + } + + // Replace the pseudo instruction with a new instruction... + MBB.insert(I, New); + } + } + + // Simply discard ADJCALLSTACKDOWN, ADJCALLSTACKUP instructions. + MBB.erase(I); +} + +// FrameIndex represent objects inside a abstract stack. +// We must replace FrameIndex with an stack/frame pointer +// direct reference. +void MBlazeRegisterInfo:: +eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, + RegScavenger *RS) const { + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + + unsigned i = 0; + while (!MI.getOperand(i).isFI()) { + ++i; + assert(i < MI.getNumOperands() && + "Instr doesn't have FrameIndex operand!"); + } + + unsigned oi = i == 2 ? 1 : 2; + + DEBUG(dbgs() << "\nFunction : " << MF.getFunction()->getName() << "\n"; + dbgs() << "<--------->\n" << MI); + + int FrameIndex = MI.getOperand(i).getIndex(); + int stackSize = MFI->getStackSize(); + int spOffset = MFI->getObjectOffset(FrameIndex); + + DEBUG(MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + dbgs() << "FrameIndex : " << FrameIndex << "\n" + << "spOffset : " << spOffset << "\n" + << "stackSize : " << stackSize << "\n" + << "isFixed : " << MFI->isFixedObjectIndex(FrameIndex) << "\n" + << "isLiveIn : " << MBlazeFI->isLiveIn(FrameIndex) << "\n" + << "isSpill : " << MFI->isSpillSlotObjectIndex(FrameIndex) + << "\n" ); + + // as explained on LowerFormalArguments, detect negative offsets + // and adjust SPOffsets considering the final stack size. + int Offset = (spOffset < 0) ? (stackSize - spOffset) : spOffset; + Offset += MI.getOperand(oi).getImm(); + + DEBUG(dbgs() << "Offset : " << Offset << "\n" << "<--------->\n"); + + MI.getOperand(oi).ChangeToImmediate(Offset); + MI.getOperand(i).ChangeToRegister(getFrameRegister(MF), false); +} + +void MBlazeRegisterInfo:: +processFunctionBeforeFrameFinalized(MachineFunction &MF) const { + // Set the stack offset where GP must be saved/loaded from. + MachineFrameInfo *MFI = MF.getFrameInfo(); + MBlazeFunctionInfo *MBlazeFI = MF.getInfo<MBlazeFunctionInfo>(); + if (MBlazeFI->needGPSaveRestore()) + MFI->setObjectOffset(MBlazeFI->getGPFI(), MBlazeFI->getGPStackOffset()); +} + +unsigned MBlazeRegisterInfo::getFrameRegister(const MachineFunction &MF) const { + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + + return TFI->hasFP(MF) ? MBlaze::R19 : MBlaze::R1; +} + +unsigned MBlazeRegisterInfo::getEHExceptionRegister() const { + llvm_unreachable("What is the exception register"); +} + +unsigned MBlazeRegisterInfo::getEHHandlerRegister() const { + llvm_unreachable("What is the exception handler register"); +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeRegisterInfo.h b/contrib/llvm/lib/Target/MBlaze/MBlazeRegisterInfo.h new file mode 100644 index 0000000..1d51162 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeRegisterInfo.h @@ -0,0 +1,73 @@ +//===-- MBlazeRegisterInfo.h - MBlaze Register Information Impl -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the MBlaze implementation of the TargetRegisterInfo +// class. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZEREGISTERINFO_H +#define MBLAZEREGISTERINFO_H + +#include "MBlaze.h" +#include "llvm/Target/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "MBlazeGenRegisterInfo.inc" + +namespace llvm { +class MBlazeSubtarget; +class TargetInstrInfo; +class Type; + +namespace MBlaze { + /// SubregIndex - The index of various sized subregister classes. Note that + /// these indices must be kept in sync with the class indices in the + /// MBlazeRegisterInfo.td file. + enum SubregIndex { + SUBREG_FPEVEN = 1, SUBREG_FPODD = 2 + }; +} + +struct MBlazeRegisterInfo : public MBlazeGenRegisterInfo { + const MBlazeSubtarget &Subtarget; + const TargetInstrInfo &TII; + + MBlazeRegisterInfo(const MBlazeSubtarget &Subtarget, + const TargetInstrInfo &tii); + + /// Get PIC indirect call register + static unsigned getPICCallReg(); + + /// Code Generation virtual methods... + const uint16_t *getCalleeSavedRegs(const MachineFunction* MF = 0) const; + + BitVector getReservedRegs(const MachineFunction &MF) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + /// Stack Frame Processing Methods + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; + + void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; + + /// Debug information queries. + unsigned getFrameRegister(const MachineFunction &MF) const; + + /// Exception handling queries. + unsigned getEHExceptionRegister() const; + unsigned getEHHandlerRegister() const; +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeRegisterInfo.td b/contrib/llvm/lib/Target/MBlaze/MBlazeRegisterInfo.td new file mode 100644 index 0000000..64cae5c --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeRegisterInfo.td @@ -0,0 +1,148 @@ +//===-- MBlazeRegisterInfo.td - MBlaze Register defs -------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Declarations that describe the MicroBlaze register file +//===----------------------------------------------------------------------===// + +// We have banks of 32 registers each. +class MBlazeReg<string n> : Register<n> { + field bits<5> Num; + let Namespace = "MBlaze"; +} + +// Special purpose registers have 15-bit values +class MBlazeSReg<string n> : Register<n> { + field bits<15> Num; + let Namespace = "MBlaze"; +} + +// MBlaze general purpose registers +class MBlazeGPRReg<bits<5> num, string n> : MBlazeReg<n> { + let Num = num; +} + +// MBlaze special purpose registers +class MBlazeSPRReg<bits<15> num, string n> : MBlazeSReg<n> { + let Num = num; +} + +//===----------------------------------------------------------------------===// +// Registers +//===----------------------------------------------------------------------===// + +let Namespace = "MBlaze" in { + // General Purpose Registers + def R0 : MBlazeGPRReg< 0, "r0">, DwarfRegNum<[0]>; + def R1 : MBlazeGPRReg< 1, "r1">, DwarfRegNum<[1]>; + def R2 : MBlazeGPRReg< 2, "r2">, DwarfRegNum<[2]>; + def R3 : MBlazeGPRReg< 3, "r3">, DwarfRegNum<[3]>; + def R4 : MBlazeGPRReg< 4, "r4">, DwarfRegNum<[4]>; + def R5 : MBlazeGPRReg< 5, "r5">, DwarfRegNum<[5]>; + def R6 : MBlazeGPRReg< 6, "r6">, DwarfRegNum<[6]>; + def R7 : MBlazeGPRReg< 7, "r7">, DwarfRegNum<[7]>; + def R8 : MBlazeGPRReg< 8, "r8">, DwarfRegNum<[8]>; + def R9 : MBlazeGPRReg< 9, "r9">, DwarfRegNum<[9]>; + def R10 : MBlazeGPRReg< 10, "r10">, DwarfRegNum<[10]>; + def R11 : MBlazeGPRReg< 11, "r11">, DwarfRegNum<[11]>; + def R12 : MBlazeGPRReg< 12, "r12">, DwarfRegNum<[12]>; + def R13 : MBlazeGPRReg< 13, "r13">, DwarfRegNum<[13]>; + def R14 : MBlazeGPRReg< 14, "r14">, DwarfRegNum<[14]>; + def R15 : MBlazeGPRReg< 15, "r15">, DwarfRegNum<[15]>; + def R16 : MBlazeGPRReg< 16, "r16">, DwarfRegNum<[16]>; + def R17 : MBlazeGPRReg< 17, "r17">, DwarfRegNum<[17]>; + def R18 : MBlazeGPRReg< 18, "r18">, DwarfRegNum<[18]>; + def R19 : MBlazeGPRReg< 19, "r19">, DwarfRegNum<[19]>; + def R20 : MBlazeGPRReg< 20, "r20">, DwarfRegNum<[20]>; + def R21 : MBlazeGPRReg< 21, "r21">, DwarfRegNum<[21]>; + def R22 : MBlazeGPRReg< 22, "r22">, DwarfRegNum<[22]>; + def R23 : MBlazeGPRReg< 23, "r23">, DwarfRegNum<[23]>; + def R24 : MBlazeGPRReg< 24, "r24">, DwarfRegNum<[24]>; + def R25 : MBlazeGPRReg< 25, "r25">, DwarfRegNum<[25]>; + def R26 : MBlazeGPRReg< 26, "r26">, DwarfRegNum<[26]>; + def R27 : MBlazeGPRReg< 27, "r27">, DwarfRegNum<[27]>; + def R28 : MBlazeGPRReg< 28, "r28">, DwarfRegNum<[28]>; + def R29 : MBlazeGPRReg< 29, "r29">, DwarfRegNum<[29]>; + def R30 : MBlazeGPRReg< 30, "r30">, DwarfRegNum<[30]>; + def R31 : MBlazeGPRReg< 31, "r31">, DwarfRegNum<[31]>; + + // Special Purpose Registers + def RPC : MBlazeSPRReg<0x0000, "rpc">, DwarfRegNum<[32]>; + def RMSR : MBlazeSPRReg<0x0001, "rmsr">, DwarfRegNum<[33]>; + def REAR : MBlazeSPRReg<0x0003, "rear">, DwarfRegNum<[34]>; + def RESR : MBlazeSPRReg<0x0005, "resr">, DwarfRegNum<[35]>; + def RFSR : MBlazeSPRReg<0x0007, "rfsr">, DwarfRegNum<[36]>; + def RBTR : MBlazeSPRReg<0x000B, "rbtr">, DwarfRegNum<[37]>; + def REDR : MBlazeSPRReg<0x000D, "redr">, DwarfRegNum<[38]>; + def RPID : MBlazeSPRReg<0x1000, "rpid">, DwarfRegNum<[39]>; + def RZPR : MBlazeSPRReg<0x1001, "rzpr">, DwarfRegNum<[40]>; + def RTLBX : MBlazeSPRReg<0x1002, "rtlbx">, DwarfRegNum<[41]>; + def RTLBLO : MBlazeSPRReg<0x1003, "rtlblo">, DwarfRegNum<[42]>; + def RTLBHI : MBlazeSPRReg<0x1004, "rtlbhi">, DwarfRegNum<[43]>; + def RTLBSX : MBlazeSPRReg<0x1004, "rtlbsx">, DwarfRegNum<[44]>; + def RPVR0 : MBlazeSPRReg<0x2000, "rpvr0">, DwarfRegNum<[45]>; + def RPVR1 : MBlazeSPRReg<0x2001, "rpvr1">, DwarfRegNum<[46]>; + def RPVR2 : MBlazeSPRReg<0x2002, "rpvr2">, DwarfRegNum<[47]>; + def RPVR3 : MBlazeSPRReg<0x2003, "rpvr3">, DwarfRegNum<[48]>; + def RPVR4 : MBlazeSPRReg<0x2004, "rpvr4">, DwarfRegNum<[49]>; + def RPVR5 : MBlazeSPRReg<0x2005, "rpvr5">, DwarfRegNum<[50]>; + def RPVR6 : MBlazeSPRReg<0x2006, "rpvr6">, DwarfRegNum<[51]>; + def RPVR7 : MBlazeSPRReg<0x2007, "rpvr7">, DwarfRegNum<[52]>; + def RPVR8 : MBlazeSPRReg<0x2008, "rpvr8">, DwarfRegNum<[53]>; + def RPVR9 : MBlazeSPRReg<0x2009, "rpvr9">, DwarfRegNum<[54]>; + def RPVR10 : MBlazeSPRReg<0x200A, "rpvr10">, DwarfRegNum<[55]>; + def RPVR11 : MBlazeSPRReg<0x200B, "rpvr11">, DwarfRegNum<[56]>; + + // The carry bit. In the Microblaze this is really bit 29 of the + // MSR register but this is the only bit of that register that we + // are interested in modeling. + def CARRY : MBlazeSPRReg<0x0000, "rmsr[c]">; +} + +//===----------------------------------------------------------------------===// +// Register Classes +//===----------------------------------------------------------------------===// + +def GPR : RegisterClass<"MBlaze", [i32,f32], 32, (sequence "R%u", 0, 31)>; + +def SPR : RegisterClass<"MBlaze", [i32], 32, (add + // Reserved + RPC, + RMSR, + REAR, + RESR, + RFSR, + RBTR, + REDR, + RPID, + RZPR, + RTLBX, + RTLBLO, + RTLBHI, + RPVR0, + RPVR1, + RPVR2, + RPVR3, + RPVR4, + RPVR5, + RPVR6, + RPVR7, + RPVR8, + RPVR9, + RPVR10, + RPVR11 + )> +{ + // None of the special purpose registers are allocatable. + let isAllocatable = 0; +} + +def CRC : RegisterClass<"MBlaze", [i32], 32, (add CARRY)> { + let CopyCost = -1; +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeRelocations.h b/contrib/llvm/lib/Target/MBlaze/MBlazeRelocations.h new file mode 100644 index 0000000..6387ee2 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeRelocations.h @@ -0,0 +1,47 @@ +//===-- MBlazeRelocations.h - MBlaze Code Relocations -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MBlaze target-specific relocation types. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZERELOCATIONS_H +#define MBLAZERELOCATIONS_H + +#include "llvm/CodeGen/MachineRelocation.h" + +namespace llvm { + namespace MBlaze { + enum RelocationType { + /// reloc_pcrel_word - PC relative relocation, add the relocated value to + /// the value already in memory, after we adjust it for where the PC is. + reloc_pcrel_word = 0, + + /// reloc_picrel_word - PIC base relative relocation, add the relocated + /// value to the value already in memory, after we adjust it for where the + /// PIC base is. + reloc_picrel_word = 1, + + /// reloc_absolute_word - absolute relocation, just add the relocated + /// value to the value already in memory. + reloc_absolute_word = 2, + + /// reloc_absolute_word_sext - absolute relocation, just add the relocated + /// value to the value already in memory. In object files, it represents a + /// value which must be sign-extended when resolving the relocation. + reloc_absolute_word_sext = 3, + + /// reloc_absolute_dword - absolute relocation, just add the relocated + /// value to the value already in memory. + reloc_absolute_dword = 4 + }; + } +} + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeSchedule.td b/contrib/llvm/lib/Target/MBlaze/MBlazeSchedule.td new file mode 100644 index 0000000..cd5691c --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeSchedule.td @@ -0,0 +1,50 @@ +//===-- MBlazeSchedule.td - MBlaze Scheduling Definitions --*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MBlaze functional units. +//===----------------------------------------------------------------------===// +def IF : FuncUnit; +def ID : FuncUnit; +def EX : FuncUnit; +def MA : FuncUnit; +def WB : FuncUnit; + +//===----------------------------------------------------------------------===// +// Instruction Itinerary classes used for MBlaze +//===----------------------------------------------------------------------===// +def IIC_ALU : InstrItinClass; +def IIC_ALUm : InstrItinClass; +def IIC_ALUd : InstrItinClass; +def IIC_SHT : InstrItinClass; +def IIC_FSLg : InstrItinClass; +def IIC_FSLp : InstrItinClass; +def IIC_MEMs : InstrItinClass; +def IIC_MEMl : InstrItinClass; +def IIC_FPU : InstrItinClass; +def IIC_FPUd : InstrItinClass; +def IIC_FPUf : InstrItinClass; +def IIC_FPUi : InstrItinClass; +def IIC_FPUs : InstrItinClass; +def IIC_FPUc : InstrItinClass; +def IIC_BR : InstrItinClass; +def IIC_BRc : InstrItinClass; +def IIC_BRl : InstrItinClass; +def IIC_WDC : InstrItinClass; +def IIC_Pseudo : InstrItinClass; + +//===----------------------------------------------------------------------===// +// MBlaze instruction itineraries for three stage pipeline. +//===----------------------------------------------------------------------===// +include "MBlazeSchedule3.td" + +//===----------------------------------------------------------------------===// +// MBlaze instruction itineraries for five stage pipeline. +//===----------------------------------------------------------------------===// +include "MBlazeSchedule5.td" diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeSchedule3.td b/contrib/llvm/lib/Target/MBlaze/MBlazeSchedule3.td new file mode 100644 index 0000000..20257a6 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeSchedule3.td @@ -0,0 +1,236 @@ +//===-- MBlazeSchedule3.td - MBlaze Scheduling Definitions -*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MBlaze instruction itineraries for the three stage pipeline. +//===----------------------------------------------------------------------===// +def MBlazePipe3Itineraries : ProcessorItineraries< + [IF,ID,EX], [], [ + + // ALU instruction with one destination register and either two register + // source operands or one register source operand and one immediate operand. + // The instruction takes one cycle to execute in each of the stages. The + // two source operands are read during the decode stage and the result is + // ready after the execute stage. + InstrItinData< IIC_ALU, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]>], // one cycle in execute stage + [ 2 // result ready after two cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // ALU multiply instruction with one destination register and either two + // register source operands or one register source operand and one immediate + // operand. The instruction takes one cycle to execute in each of the + // pipeline stages except the execute stage, which takes three cycles. The + // two source operands are read during the decode stage and the result is + // ready after the execute stage. + InstrItinData< IIC_ALUm, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<3,[EX]>], // three cycles in execute stage + [ 4 // result ready after four cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // ALU divide instruction with one destination register two register source + // operands. The instruction takes one cycle to execute in each the pipeline + // stages except the execute stage, which takes 34 cycles. The two + // source operands are read during the decode stage and the result is ready + // after the execute stage. + InstrItinData< IIC_ALUd, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<34,[EX]>], // 34 cycles in execute stage + [ 35 // result ready after 35 cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Shift instruction with one destination register and either two register + // source operands or one register source operand and one immediate operand. + // The instruction takes one cycle to execute in each of the pipeline stages + // except the execute stage, which takes two cycles. The two source operands + // are read during the decode stage and the result is ready after the execute + // stage. + InstrItinData< IIC_SHT, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<2,[EX]>], // two cycles in execute stage + [ 3 // result ready after three cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Branch instruction with one source operand register. The instruction takes + // one cycle to execute in each of the pipeline stages. The source operand is + // read during the decode stage. + InstrItinData< IIC_BR, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]>], // one cycle in execute stage + [ 1 ]>, // first operand read after one cycle + + // Conditional branch instruction with two source operand registers. The + // instruction takes one cycle to execute in each of the pipeline stages. The + // two source operands are read during the decode stage. + InstrItinData< IIC_BRc, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]>], // one cycle in execute stage + [ 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Branch and link instruction with one destination register and one source + // operand register. The instruction takes one cycle to execute in each of + // the pipeline stages. The source operand is read during the decode stage + // and the destination register is ready after the execute stage. + InstrItinData< IIC_BRl, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]>], // one cycle in execute stage + [ 2 // result ready after two cycles + , 1 ]>, // first operand read after one cycle + + // Cache control instruction with two source operand registers. The + // instruction takes one cycle to execute in each of the pipeline stages + // except the memory access stage, which takes two cycles. The source + // operands are read during the decode stage. + InstrItinData< IIC_WDC, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<2,[EX]>], // two cycles in execute stage + [ 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Floating point instruction with one destination register and two source + // operand registers. The instruction takes one cycle to execute in each of + // the pipeline stages except the execute stage, which takes six cycles. The + // source operands are read during the decode stage and the results are ready + // after the execute stage. + InstrItinData< IIC_FPU, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<6,[EX]>], // six cycles in execute stage + [ 7 // result ready after seven cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Floating point divide instruction with one destination register and two + // source operand registers. The instruction takes one cycle to execute in + // each of the pipeline stages except the execute stage, which takes 30 + // cycles. The source operands are read during the decode stage and the + // results are ready after the execute stage. + InstrItinData< IIC_FPUd, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<30,[EX]>], // one cycle in execute stage + [ 31 // result ready after 31 cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Convert floating point to integer instruction with one destination + // register and one source operand register. The instruction takes one cycle + // to execute in each of the pipeline stages except the execute stage, + // which takes seven cycles. The source operands are read during the decode + // stage and the results are ready after the execute stage. + InstrItinData< IIC_FPUi, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<7,[EX]>], // seven cycles in execute stage + [ 8 // result ready after eight cycles + , 1 ]>, // first operand read after one cycle + + // Convert integer to floating point instruction with one destination + // register and one source operand register. The instruction takes one cycle + // to execute in each of the pipeline stages except the execute stage, + // which takes six cycles. The source operands are read during the decode + // stage and the results are ready after the execute stage. + InstrItinData< IIC_FPUf, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<6,[EX]>], // six cycles in execute stage + [ 7 // result ready after seven cycles + , 1 ]>, // first operand read after one cycle + + // Floating point square root instruction with one destination register and + // one source operand register. The instruction takes one cycle to execute in + // each of the pipeline stages except the execute stage, which takes 29 + // cycles. The source operands are read during the decode stage and the + // results are ready after the execute stage. + InstrItinData< IIC_FPUs, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<29,[EX]>], // 29 cycles in execute stage + [ 30 // result ready after 30 cycles + , 1 ]>, // first operand read after one cycle + + // Floating point comparison instruction with one destination register and + // two source operand registers. The instruction takes one cycle to execute + // in each of the pipeline stages except the execute stage, which takes three + // cycles. The source operands are read during the decode stage and the + // results are ready after the execute stage. + InstrItinData< IIC_FPUc, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<3,[EX]>], // three cycles in execute stage + [ 4 // result ready after four cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // FSL get instruction with one register or immediate source operand and one + // destination register. The instruction takes one cycle to execute in each + // of the pipeline stages except the execute stage, which takes two cycles. + // The one source operand is read during the decode stage and the result is + // ready after the execute stage. + InstrItinData< IIC_FSLg, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<2,[EX]>], // two cycles in execute stage + [ 3 // result ready after two cycles + , 1 ]>, // first operand read after one cycle + + // FSL put instruction with either two register source operands or one + // register source operand and one immediate operand. There is no result + // produced by the instruction. The instruction takes one cycle to execute in + // each of the pipeline stages except the execute stage, which takes two + // cycles. The two source operands are read during the decode stage. + InstrItinData< IIC_FSLp, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<2,[EX]>], // two cycles in execute stage + [ 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Memory store instruction with either three register source operands or two + // register source operands and one immediate operand. There is no result + // produced by the instruction. The instruction takes one cycle to execute in + // each of the pipeline stages except the execute stage, which takes two + // cycles. All of the source operands are read during the decode stage. + InstrItinData< IIC_MEMs, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<2,[EX]>], // two cycles in execute stage + [ 1 // first operand read after one cycle + , 1 // second operand read after one cycle + , 1 ]>, // third operand read after one cycle + + // Memory load instruction with one destination register and either two + // register source operands or one register source operand and one immediate + // operand. The instruction takes one cycle to execute in each of the + // pipeline stages except the execute stage, which takes two cycles. All of + // the source operands are read during the decode stage and the result is + // ready after the execute stage. + InstrItinData< IIC_MEMl, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<2,[EX]>], // two cycles in execute stage + [ 3 // result ready after four cycles + , 1 // second operand read after one cycle + , 1 ]> // third operand read after one cycle +]>; diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeSchedule5.td b/contrib/llvm/lib/Target/MBlaze/MBlazeSchedule5.td new file mode 100644 index 0000000..ab53b42 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeSchedule5.td @@ -0,0 +1,267 @@ +//===-- MBlazeSchedule5.td - MBlaze Scheduling Definitions -*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MBlaze instruction itineraries for the five stage pipeline. +//===----------------------------------------------------------------------===// +def MBlazePipe5Itineraries : ProcessorItineraries< + [IF,ID,EX,MA,WB], [], [ + + // ALU instruction with one destination register and either two register + // source operands or one register source operand and one immediate operand. + // The instruction takes one cycle to execute in each of the stages. The + // two source operands are read during the decode stage and the result is + // ready after the execute stage. + InstrItinData< IIC_ALU, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<1,[MA]> // one cycle in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 2 // result ready after two cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // ALU multiply instruction with one destination register and either two + // register source operands or one register source operand and one immediate + // operand. The instruction takes one cycle to execute in each of the + // pipeline stages. The two source operands are read during the decode stage + // and the result is ready after the execute stage. + InstrItinData< IIC_ALUm, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<1,[MA]> // one cycle in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 2 // result ready after two cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // ALU divide instruction with one destination register two register source + // operands. The instruction takes one cycle to execute in each the pipeline + // stages except the memory access stage, which takes 31 cycles. The two + // source operands are read during the decode stage and the result is ready + // after the memory access stage. + InstrItinData< IIC_ALUd, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<31,[MA]> // 31 cycles in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 33 // result ready after 33 cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Shift instruction with one destination register and either two register + // source operands or one register source operand and one immediate operand. + // The instruction takes one cycle to execute in each of the pipeline stages. + // The two source operands are read during the decode stage and the result is + // ready after the memory access stage. + InstrItinData< IIC_SHT, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<1,[MA]> // one cycle in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 3 // result ready after three cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Branch instruction with one source operand register. The instruction takes + // one cycle to execute in each of the pipeline stages. The source operand is + // read during the decode stage. + InstrItinData< IIC_BR, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<1,[MA]> // one cycle in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 1 ]>, // first operand read after one cycle + + // Conditional branch instruction with two source operand registers. The + // instruction takes one cycle to execute in each of the pipeline stages. The + // two source operands are read during the decode stage. + InstrItinData< IIC_BRc, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<1,[MA]> // one cycle in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Branch and link instruction with one destination register and one source + // operand register. The instruction takes one cycle to execute in each of + // the pipeline stages. The source operand is read during the decode stage + // and the destination register is ready after the writeback stage. + InstrItinData< IIC_BRl, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<1,[MA]> // one cycle in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 4 // result ready after four cycles + , 1 ]>, // first operand read after one cycle + + // Cache control instruction with two source operand registers. The + // instruction takes one cycle to execute in each of the pipeline stages + // except the memory access stage, which takes two cycles. The source + // operands are read during the decode stage. + InstrItinData< IIC_WDC, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<2,[MA]> // two cycles in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Floating point instruction with one destination register and two source + // operand registers. The instruction takes one cycle to execute in each of + // the pipeline stages except the memory access stage, which takes two + // cycles. The source operands are read during the decode stage and the + // results are ready after the writeback stage. + InstrItinData< IIC_FPU, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<2,[MA]> // two cycles in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 5 // result ready after five cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Floating point divide instruction with one destination register and two + // source operand registers. The instruction takes one cycle to execute in + // each of the pipeline stages except the memory access stage, which takes 26 + // cycles. The source operands are read during the decode stage and the + // results are ready after the writeback stage. + InstrItinData< IIC_FPUd, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<26,[MA]> // 26 cycles in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 29 // result ready after 29 cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Convert floating point to integer instruction with one destination + // register and one source operand register. The instruction takes one cycle + // to execute in each of the pipeline stages except the memory access stage, + // which takes three cycles. The source operands are read during the decode + // stage and the results are ready after the writeback stage. + InstrItinData< IIC_FPUi, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<3,[MA]> // three cycles in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 6 // result ready after six cycles + , 1 ]>, // first operand read after one cycle + + // Convert integer to floating point instruction with one destination + // register and one source operand register. The instruction takes one cycle + // to execute in each of the pipeline stages except the memory access stage, + // which takes two cycles. The source operands are read during the decode + // stage and the results are ready after the writeback stage. + InstrItinData< IIC_FPUf, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<2,[MA]> // two cycles in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 5 // result ready after five cycles + , 1 ]>, // first operand read after one cycle + + // Floating point square root instruction with one destination register and + // one source operand register. The instruction takes one cycle to execute in + // each of the pipeline stages except the memory access stage, which takes 25 + // cycles. The source operands are read during the decode stage and the + // results are ready after the writeback stage. + InstrItinData< IIC_FPUs, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<25,[MA]> // 25 cycles in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 28 // result ready after 28 cycles + , 1 ]>, // first operand read after one cycle + + // Floating point comparison instruction with one destination register and + // two source operand registers. The instruction takes one cycle to execute + // in each of the pipeline stages. The source operands are read during the + // decode stage and the results are ready after the execute stage. + InstrItinData< IIC_FPUc, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<1,[MA]> // one cycle in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 2 // result ready after two cycles + , 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // FSL get instruction with one register or immediate source operand and one + // destination register. The instruction takes one cycle to execute in each + // of the pipeline stages. The one source operand is read during the decode + // stage and the result is ready after the execute stage. + InstrItinData< IIC_FSLg, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<1,[MA]> // one cycle in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 2 // result ready after two cycles + , 1 ]>, // first operand read after one cycle + + // FSL put instruction with either two register source operands or one + // register source operand and one immediate operand. There is no result + // produced by the instruction. The instruction takes one cycle to execute in + // each of the pipeline stages. The two source operands are read during the + // decode stage. + InstrItinData< IIC_FSLp, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<1,[MA]> // one cycle in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 1 // first operand read after one cycle + , 1 ]>, // second operand read after one cycle + + // Memory store instruction with either three register source operands or two + // register source operands and one immediate operand. There is no result + // produced by the instruction. The instruction takes one cycle to execute in + // each of the pipeline stages. All of the source operands are read during + // the decode stage. + InstrItinData< IIC_MEMs, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<1,[MA]> // one cycle in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 1 // first operand read after one cycle + , 1 // second operand read after one cycle + , 1 ]>, // third operand read after one cycle + + // Memory load instruction with one destination register and either two + // register source operands or one register source operand and one immediate + // operand. The instruction takes one cycle to execute in each of the + // pipeline stages. All of the source operands are read during the decode + // stage and the result is ready after the writeback stage. + InstrItinData< IIC_MEMl, + [ InstrStage<1,[IF]> // one cycle in fetch stage + , InstrStage<1,[ID]> // one cycle in decode stage + , InstrStage<1,[EX]> // one cycle in execute stage + , InstrStage<1,[MA]> // one cycle in memory access stage + , InstrStage<1,[WB]>], // one cycle in write back stage + [ 4 // result ready after four cycles + , 1 // second operand read after one cycle + , 1 ]> // third operand read after one cycle +]>; diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeSelectionDAGInfo.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeSelectionDAGInfo.cpp new file mode 100644 index 0000000..6a115b2 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeSelectionDAGInfo.cpp @@ -0,0 +1,23 @@ +//===-- MBlazeSelectionDAGInfo.cpp - MBlaze SelectionDAG Info -------------===// +// +// 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 MBlazeSelectionDAGInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mblaze-selectiondag-info" +#include "MBlazeTargetMachine.h" +using namespace llvm; + +MBlazeSelectionDAGInfo::MBlazeSelectionDAGInfo(const MBlazeTargetMachine &TM) + : TargetSelectionDAGInfo(TM) { +} + +MBlazeSelectionDAGInfo::~MBlazeSelectionDAGInfo() { +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeSelectionDAGInfo.h b/contrib/llvm/lib/Target/MBlaze/MBlazeSelectionDAGInfo.h new file mode 100644 index 0000000..9f8e2aa --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeSelectionDAGInfo.h @@ -0,0 +1,31 @@ +//===-- MBlazeSelectionDAGInfo.h - MBlaze SelectionDAG Info -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MBlaze subclass for TargetSelectionDAGInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZESELECTIONDAGINFO_H +#define MBLAZESELECTIONDAGINFO_H + +#include "llvm/Target/TargetSelectionDAGInfo.h" + +namespace llvm { + +class MBlazeTargetMachine; + +class MBlazeSelectionDAGInfo : public TargetSelectionDAGInfo { +public: + explicit MBlazeSelectionDAGInfo(const MBlazeTargetMachine &TM); + ~MBlazeSelectionDAGInfo(); +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeSubtarget.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeSubtarget.cpp new file mode 100644 index 0000000..dc2ad29 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeSubtarget.cpp @@ -0,0 +1,56 @@ +//===-- MBlazeSubtarget.cpp - MBlaze Subtarget Information ----------------===// +// +// 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 MBlaze specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeSubtarget.h" +#include "MBlaze.h" +#include "MBlazeRegisterInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/TargetRegistry.h" + +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "MBlazeGenSubtargetInfo.inc" + +using namespace llvm; + +MBlazeSubtarget::MBlazeSubtarget(const std::string &TT, + const std::string &CPU, + const std::string &FS): + MBlazeGenSubtargetInfo(TT, CPU, FS), + HasBarrel(false), HasDiv(false), HasMul(false), HasPatCmp(false), + HasFPU(false), HasMul64(false), HasSqrt(false) +{ + // Parse features string. + std::string CPUName = CPU; + if (CPUName.empty()) + CPUName = "mblaze"; + ParseSubtargetFeatures(CPUName, FS); + + // Only use instruction scheduling if the selected CPU has an instruction + // itinerary (the default CPU is the only one that doesn't). + HasItin = CPUName != "mblaze"; + DEBUG(dbgs() << "CPU " << CPUName << "(" << HasItin << ")\n"); + + // Initialize scheduling itinerary for the specified CPU. + InstrItins = getInstrItineraryForCPU(CPUName); +} + +bool MBlazeSubtarget:: +enablePostRAScheduler(CodeGenOpt::Level OptLevel, + TargetSubtargetInfo::AntiDepBreakMode& Mode, + RegClassVector& CriticalPathRCs) const { + Mode = TargetSubtargetInfo::ANTIDEP_CRITICAL; + CriticalPathRCs.clear(); + CriticalPathRCs.push_back(&MBlaze::GPRRegClass); + return HasItin && OptLevel >= CodeGenOpt::Default; +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeSubtarget.h b/contrib/llvm/lib/Target/MBlaze/MBlazeSubtarget.h new file mode 100644 index 0000000..eb37504 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeSubtarget.h @@ -0,0 +1,75 @@ +//===-- MBlazeSubtarget.h - Define Subtarget for the MBlaze ----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the MBlaze specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZESUBTARGET_H +#define MBLAZESUBTARGET_H + +#include "llvm/Target/TargetSubtargetInfo.h" +#include "llvm/MC/MCInstrItineraries.h" +#include <string> + +#define GET_SUBTARGETINFO_HEADER +#include "MBlazeGenSubtargetInfo.inc" + +namespace llvm { +class StringRef; + +class MBlazeSubtarget : public MBlazeGenSubtargetInfo { + +protected: + bool HasBarrel; + bool HasDiv; + bool HasMul; + bool HasPatCmp; + bool HasFPU; + bool HasMul64; + bool HasSqrt; + bool HasItin; + + InstrItineraryData InstrItins; + +public: + + /// This constructor initializes the data members to match that + /// of the specified triple. + MBlazeSubtarget(const std::string &TT, const std::string &CPU, + const std::string &FS); + + /// ParseSubtargetFeatures - Parses features string setting specified + /// subtarget options. Definition of function is auto generated by tblgen. + void ParseSubtargetFeatures(StringRef CPU, StringRef FS); + + /// Compute the number of maximum number of issues per cycle for the + /// MBlaze scheduling itineraries. + void computeIssueWidth(); + + /// enablePostRAScheduler - True at 'More' optimization. + bool enablePostRAScheduler(CodeGenOpt::Level OptLevel, + TargetSubtargetInfo::AntiDepBreakMode& Mode, + RegClassVector& CriticalPathRCs) const; + + /// getInstrItins - Return the instruction itineraies based on subtarget. + const InstrItineraryData &getInstrItineraryData() const { return InstrItins; } + + bool hasItin() const { return HasItin; } + bool hasPCMP() const { return HasPatCmp; } + bool hasFPU() const { return HasFPU; } + bool hasSqrt() const { return HasSqrt; } + bool hasMul() const { return HasMul; } + bool hasMul64() const { return HasMul64; } + bool hasDiv() const { return HasDiv; } + bool hasBarrel() const { return HasBarrel; } +}; +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeTargetMachine.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeTargetMachine.cpp new file mode 100644 index 0000000..5f82f14 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeTargetMachine.cpp @@ -0,0 +1,81 @@ +//===-- MBlazeTargetMachine.cpp - Define TargetMachine for MBlaze ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements the info about MBlaze target spec. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeTargetMachine.h" +#include "MBlaze.h" +#include "llvm/PassManager.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/TargetOptions.h" +using namespace llvm; + +extern "C" void LLVMInitializeMBlazeTarget() { + // Register the target. + RegisterTargetMachine<MBlazeTargetMachine> X(TheMBlazeTarget); +} + +// DataLayout --> Big-endian, 32-bit pointer/ABI/alignment +// The stack is always 8 byte aligned +// On function prologue, the stack is created by decrementing +// its pointer. Once decremented, all references are done with positive +// offset from the stack/frame pointer, using StackGrowsUp enables +// an easier handling. +MBlazeTargetMachine:: +MBlazeTargetMachine(const Target &T, StringRef TT, + StringRef CPU, StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL) + : LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL), + Subtarget(TT, CPU, FS), + DataLayout("E-p:32:32:32-i8:8:8-i16:16:16"), + InstrInfo(*this), + FrameLowering(Subtarget), + TLInfo(*this), TSInfo(*this), ELFWriterInfo(*this), + InstrItins(Subtarget.getInstrItineraryData()) { +} + +namespace { +/// MBlaze Code Generator Pass Configuration Options. +class MBlazePassConfig : public TargetPassConfig { +public: + MBlazePassConfig(MBlazeTargetMachine *TM, PassManagerBase &PM) + : TargetPassConfig(TM, PM) {} + + MBlazeTargetMachine &getMBlazeTargetMachine() const { + return getTM<MBlazeTargetMachine>(); + } + + virtual bool addInstSelector(); + virtual bool addPreEmitPass(); +}; +} // namespace + +TargetPassConfig *MBlazeTargetMachine::createPassConfig(PassManagerBase &PM) { + return new MBlazePassConfig(this, PM); +} + +// Install an instruction selector pass using +// the ISelDag to gen MBlaze code. +bool MBlazePassConfig::addInstSelector() { + addPass(createMBlazeISelDag(getMBlazeTargetMachine())); + return false; +} + +// Implemented by targets that want to run passes immediately before +// machine code is emitted. return true if -print-machineinstrs should +// print out the code after the passes. +bool MBlazePassConfig::addPreEmitPass() { + addPass(createMBlazeDelaySlotFillerPass(getMBlazeTargetMachine())); + return true; +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeTargetMachine.h b/contrib/llvm/lib/Target/MBlaze/MBlazeTargetMachine.h new file mode 100644 index 0000000..1647a21 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeTargetMachine.h @@ -0,0 +1,86 @@ +//===-- MBlazeTargetMachine.h - Define TargetMachine for MBlaze -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the MBlaze specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZE_TARGETMACHINE_H +#define MBLAZE_TARGETMACHINE_H + +#include "MBlazeSubtarget.h" +#include "MBlazeInstrInfo.h" +#include "MBlazeISelLowering.h" +#include "MBlazeSelectionDAGInfo.h" +#include "MBlazeIntrinsicInfo.h" +#include "MBlazeFrameLowering.h" +#include "MBlazeELFWriterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetFrameLowering.h" + +namespace llvm { + class formatted_raw_ostream; + + class MBlazeTargetMachine : public LLVMTargetMachine { + MBlazeSubtarget Subtarget; + const TargetData DataLayout; // Calculates type size & alignment + MBlazeInstrInfo InstrInfo; + MBlazeFrameLowering FrameLowering; + MBlazeTargetLowering TLInfo; + MBlazeSelectionDAGInfo TSInfo; + MBlazeIntrinsicInfo IntrinsicInfo; + MBlazeELFWriterInfo ELFWriterInfo; + InstrItineraryData InstrItins; + + public: + MBlazeTargetMachine(const Target &T, StringRef TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL); + + virtual const MBlazeInstrInfo *getInstrInfo() const + { return &InstrInfo; } + + virtual const InstrItineraryData *getInstrItineraryData() const + { return &InstrItins; } + + virtual const TargetFrameLowering *getFrameLowering() const + { return &FrameLowering; } + + virtual const MBlazeSubtarget *getSubtargetImpl() const + { return &Subtarget; } + + virtual const TargetData *getTargetData() const + { return &DataLayout;} + + virtual const MBlazeRegisterInfo *getRegisterInfo() const + { return &InstrInfo.getRegisterInfo(); } + + virtual const MBlazeTargetLowering *getTargetLowering() const + { return &TLInfo; } + + virtual const MBlazeSelectionDAGInfo* getSelectionDAGInfo() const + { return &TSInfo; } + + const TargetIntrinsicInfo *getIntrinsicInfo() const + { return &IntrinsicInfo; } + + virtual const MBlazeELFWriterInfo *getELFWriterInfo() const { + return &ELFWriterInfo; + } + + // Pass Pipeline Configuration + virtual TargetPassConfig *createPassConfig(PassManagerBase &PM); + }; +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeTargetObjectFile.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeTargetObjectFile.cpp new file mode 100644 index 0000000..f66ea30 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeTargetObjectFile.cpp @@ -0,0 +1,90 @@ +//===-- MBlazeTargetObjectFile.cpp - MBlaze object files ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeTargetObjectFile.h" +#include "MBlazeSubtarget.h" +#include "llvm/DerivedTypes.h" +#include "llvm/GlobalVariable.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ELF.h" +using namespace llvm; + +void MBlazeTargetObjectFile:: +Initialize(MCContext &Ctx, const TargetMachine &TM) { + TargetLoweringObjectFileELF::Initialize(Ctx, TM); + + SmallDataSection = + getContext().getELFSection(".sdata", ELF::SHT_PROGBITS, + ELF::SHF_WRITE |ELF::SHF_ALLOC, + SectionKind::getDataRel()); + + SmallBSSSection = + getContext().getELFSection(".sbss", ELF::SHT_NOBITS, + ELF::SHF_WRITE |ELF::SHF_ALLOC, + SectionKind::getBSS()); + +} + +// A address must be loaded from a small section if its size is less than the +// small section size threshold. Data in this section must be addressed using +// gp_rel operator. +static bool IsInSmallSection(uint64_t Size) { + return Size > 0 && Size <= 8; +} + +bool MBlazeTargetObjectFile:: +IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM) const { + if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage()) + return false; + + return IsGlobalInSmallSection(GV, TM, getKindForGlobal(GV, TM)); +} + +/// IsGlobalInSmallSection - Return true if this global address should be +/// placed into small data/bss section. +bool MBlazeTargetObjectFile:: +IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM, + SectionKind Kind) const { + // Only global variables, not functions. + const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GV); + if (!GVA) + return false; + + // We can only do this for datarel or BSS objects for now. + if (!Kind.isBSS() && !Kind.isDataRel()) + return false; + + // If this is a internal constant string, there is a special + // section for it, but not in small data/bss. + if (Kind.isMergeable1ByteCString()) + return false; + + Type *Ty = GV->getType()->getElementType(); + return IsInSmallSection(TM.getTargetData()->getTypeAllocSize(Ty)); +} + +const MCSection *MBlazeTargetObjectFile:: +SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, + Mangler *Mang, const TargetMachine &TM) const { + // TODO: Could also support "weak" symbols as well with ".gnu.linkonce.s.*" + // sections? + + // Handle Small Section classification here. + if (Kind.isBSS() && IsGlobalInSmallSection(GV, TM, Kind)) + return SmallBSSSection; + if (Kind.isDataNoRel() && IsGlobalInSmallSection(GV, TM, Kind)) + return SmallDataSection; + + // Otherwise, we work the same as ELF. + return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind, Mang,TM); +} diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeTargetObjectFile.h b/contrib/llvm/lib/Target/MBlaze/MBlazeTargetObjectFile.h new file mode 100644 index 0000000..c313722 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeTargetObjectFile.h @@ -0,0 +1,40 @@ +//===-- llvm/Target/MBlazeTargetObjectFile.h - MBlaze Obj. Info -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_MBLAZE_TARGETOBJECTFILE_H +#define LLVM_TARGET_MBLAZE_TARGETOBJECTFILE_H + +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" + +namespace llvm { + + class MBlazeTargetObjectFile : public TargetLoweringObjectFileELF { + const MCSection *SmallDataSection; + const MCSection *SmallBSSSection; + public: + + void Initialize(MCContext &Ctx, const TargetMachine &TM); + + /// IsGlobalInSmallSection - Return true if this global address should be + /// placed into small data/bss section. + bool IsGlobalInSmallSection(const GlobalValue *GV, + const TargetMachine &TM, + SectionKind Kind) const; + + bool IsGlobalInSmallSection(const GlobalValue *GV, + const TargetMachine &TM) const; + + const MCSection *SelectSectionForGlobal(const GlobalValue *GV, + SectionKind Kind, + Mangler *Mang, + const TargetMachine &TM) const; + }; +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeAsmBackend.cpp b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeAsmBackend.cpp new file mode 100644 index 0000000..f383fec --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeAsmBackend.cpp @@ -0,0 +1,170 @@ +//===-- MBlazeAsmBackend.cpp - MBlaze Assembler Backend -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MBlazeMCTargetDesc.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCELFSymbolFlags.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCValue.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +static unsigned getFixupKindSize(unsigned Kind) { + switch (Kind) { + default: llvm_unreachable("invalid fixup kind!"); + case FK_Data_1: return 1; + case FK_PCRel_2: + case FK_Data_2: return 2; + case FK_PCRel_4: + case FK_Data_4: return 4; + case FK_Data_8: return 8; + } +} + + +namespace { + +class MBlazeAsmBackend : public MCAsmBackend { +public: + MBlazeAsmBackend(const Target &T) + : MCAsmBackend() { + } + + unsigned getNumFixupKinds() const { + return 2; + } + + bool mayNeedRelaxation(const MCInst &Inst) const; + + bool fixupNeedsRelaxation(const MCFixup &Fixup, + uint64_t Value, + const MCInstFragment *DF, + const MCAsmLayout &Layout) const; + + void relaxInstruction(const MCInst &Inst, MCInst &Res) const; + + bool writeNopData(uint64_t Count, MCObjectWriter *OW) const; + + unsigned getPointerSize() const { + return 4; + } +}; + +static unsigned getRelaxedOpcode(unsigned Op) { + switch (Op) { + default: return Op; + case MBlaze::ADDIK: return MBlaze::ADDIK32; + case MBlaze::ORI: return MBlaze::ORI32; + case MBlaze::BRLID: return MBlaze::BRLID32; + } +} + +bool MBlazeAsmBackend::mayNeedRelaxation(const MCInst &Inst) const { + if (getRelaxedOpcode(Inst.getOpcode()) == Inst.getOpcode()) + return false; + + bool hasExprOrImm = false; + for (unsigned i = 0; i < Inst.getNumOperands(); ++i) + hasExprOrImm |= Inst.getOperand(i).isExpr(); + + return hasExprOrImm; +} + +bool MBlazeAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, + uint64_t Value, + const MCInstFragment *DF, + const MCAsmLayout &Layout) const { + // FIXME: Is this right? It's what the "generic" code was doing before, + // but is X86 specific. Is it actually true for MBlaze also, or was it + // just close enough to not be a big deal? + // + // Relax if the value is too big for a (signed) i8. + return int64_t(Value) != int64_t(int8_t(Value)); +} + +void MBlazeAsmBackend::relaxInstruction(const MCInst &Inst, MCInst &Res) const { + Res = Inst; + Res.setOpcode(getRelaxedOpcode(Inst.getOpcode())); +} + +bool MBlazeAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const { + if ((Count % 4) != 0) + return false; + + for (uint64_t i = 0; i < Count; i += 4) + OW->Write32(0x00000000); + + return true; +} +} // end anonymous namespace + +namespace { +class ELFMBlazeAsmBackend : public MBlazeAsmBackend { +public: + uint8_t OSABI; + ELFMBlazeAsmBackend(const Target &T, uint8_t _OSABI) + : MBlazeAsmBackend(T), OSABI(_OSABI) { } + + void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + uint64_t Value) const; + + MCObjectWriter *createObjectWriter(raw_ostream &OS) const { + return createMBlazeELFObjectWriter(OS, OSABI); + } +}; + +void ELFMBlazeAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, + unsigned DataSize, uint64_t Value) const { + unsigned Size = getFixupKindSize(Fixup.getKind()); + + assert(Fixup.getOffset() + Size <= DataSize && + "Invalid fixup offset!"); + + char *data = Data + Fixup.getOffset(); + switch (Size) { + default: llvm_unreachable("Cannot fixup unknown value."); + case 1: llvm_unreachable("Cannot fixup 1 byte value."); + case 8: llvm_unreachable("Cannot fixup 8 byte value."); + + case 4: + *(data+7) = uint8_t(Value); + *(data+6) = uint8_t(Value >> 8); + *(data+3) = uint8_t(Value >> 16); + *(data+2) = uint8_t(Value >> 24); + break; + + case 2: + *(data+3) = uint8_t(Value >> 0); + *(data+2) = uint8_t(Value >> 8); + } +} +} // end anonymous namespace + +MCAsmBackend *llvm::createMBlazeAsmBackend(const Target &T, StringRef TT) { + Triple TheTriple(TT); + + if (TheTriple.isOSDarwin()) + assert(0 && "Mac not supported on MBlaze"); + + if (TheTriple.isOSWindows()) + assert(0 && "Windows not supported on MBlaze"); + + uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS()); + return new ELFMBlazeAsmBackend(T, OSABI); +} diff --git a/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeBaseInfo.h b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeBaseInfo.h new file mode 100644 index 0000000..437026e --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeBaseInfo.h @@ -0,0 +1,237 @@ +//===-- MBlazeBaseInfo.h - Top level definitions for MBlaze -- --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains small standalone helper functions and enum definitions for +// the MBlaze target useful for the compiler back-end and the MC libraries. +// As such, it deliberately does not include references to LLVM core +// code gen types, passes, etc.. +// +//===----------------------------------------------------------------------===// + +#ifndef MBlazeBASEINFO_H +#define MBlazeBASEINFO_H + +#include "MBlazeMCTargetDesc.h" +#include "llvm/Support/ErrorHandling.h" + +namespace llvm { + +/// MBlazeII - This namespace holds all of the target specific flags that +/// instruction info tracks. +/// +namespace MBlazeII { + enum { + // PseudoFrm - This represents an instruction that is a pseudo instruction + // or one that has not been implemented yet. It is illegal to code generate + // it, but tolerated for intermediate implementation stages. + FPseudo = 0, + FRRR, + FRRI, + FCRR, + FCRI, + FRCR, + FRCI, + FCCR, + FCCI, + FRRCI, + FRRC, + FRCX, + FRCS, + FCRCS, + FCRCX, + FCX, + FCR, + FRIR, + FRRRR, + FRI, + FC, + FRR, + FormMask = 63 + + //===------------------------------------------------------------------===// + // MBlaze Specific MachineOperand flags. + // MO_NO_FLAG, + + /// MO_GOT - Represents the offset into the global offset table at which + /// the address the relocation entry symbol resides during execution. + // MO_GOT, + + /// MO_GOT_CALL - Represents the offset into the global offset table at + /// which the address of a call site relocation entry symbol resides + /// during execution. This is different from the above since this flag + /// can only be present in call instructions. + // MO_GOT_CALL, + + /// MO_GPREL - Represents the offset from the current gp value to be used + /// for the relocatable object file being produced. + // MO_GPREL, + + /// MO_ABS_HILO - Represents the hi or low part of an absolute symbol + /// address. + // MO_ABS_HILO + + }; +} + +static inline bool isMBlazeRegister(unsigned Reg) { + return Reg <= 31; +} + +static inline bool isSpecialMBlazeRegister(unsigned Reg) { + switch (Reg) { + case 0x0000 : case 0x0001 : case 0x0003 : case 0x0005 : + case 0x0007 : case 0x000B : case 0x000D : case 0x1000 : + case 0x1001 : case 0x1002 : case 0x1003 : case 0x1004 : + case 0x2000 : case 0x2001 : case 0x2002 : case 0x2003 : + case 0x2004 : case 0x2005 : case 0x2006 : case 0x2007 : + case 0x2008 : case 0x2009 : case 0x200A : case 0x200B : + return true; + + default: + return false; + } +} + +/// getMBlazeRegisterNumbering - Given the enum value for some register, e.g. +/// MBlaze::R0, return the number that it corresponds to (e.g. 0). +static inline unsigned getMBlazeRegisterNumbering(unsigned RegEnum) { + switch (RegEnum) { + case MBlaze::R0 : return 0; + case MBlaze::R1 : return 1; + case MBlaze::R2 : return 2; + case MBlaze::R3 : return 3; + case MBlaze::R4 : return 4; + case MBlaze::R5 : return 5; + case MBlaze::R6 : return 6; + case MBlaze::R7 : return 7; + case MBlaze::R8 : return 8; + case MBlaze::R9 : return 9; + case MBlaze::R10 : return 10; + case MBlaze::R11 : return 11; + case MBlaze::R12 : return 12; + case MBlaze::R13 : return 13; + case MBlaze::R14 : return 14; + case MBlaze::R15 : return 15; + case MBlaze::R16 : return 16; + case MBlaze::R17 : return 17; + case MBlaze::R18 : return 18; + case MBlaze::R19 : return 19; + case MBlaze::R20 : return 20; + case MBlaze::R21 : return 21; + case MBlaze::R22 : return 22; + case MBlaze::R23 : return 23; + case MBlaze::R24 : return 24; + case MBlaze::R25 : return 25; + case MBlaze::R26 : return 26; + case MBlaze::R27 : return 27; + case MBlaze::R28 : return 28; + case MBlaze::R29 : return 29; + case MBlaze::R30 : return 30; + case MBlaze::R31 : return 31; + case MBlaze::RPC : return 0x0000; + case MBlaze::RMSR : return 0x0001; + case MBlaze::REAR : return 0x0003; + case MBlaze::RESR : return 0x0005; + case MBlaze::RFSR : return 0x0007; + case MBlaze::RBTR : return 0x000B; + case MBlaze::REDR : return 0x000D; + case MBlaze::RPID : return 0x1000; + case MBlaze::RZPR : return 0x1001; + case MBlaze::RTLBX : return 0x1002; + case MBlaze::RTLBLO : return 0x1003; + case MBlaze::RTLBHI : return 0x1004; + case MBlaze::RPVR0 : return 0x2000; + case MBlaze::RPVR1 : return 0x2001; + case MBlaze::RPVR2 : return 0x2002; + case MBlaze::RPVR3 : return 0x2003; + case MBlaze::RPVR4 : return 0x2004; + case MBlaze::RPVR5 : return 0x2005; + case MBlaze::RPVR6 : return 0x2006; + case MBlaze::RPVR7 : return 0x2007; + case MBlaze::RPVR8 : return 0x2008; + case MBlaze::RPVR9 : return 0x2009; + case MBlaze::RPVR10 : return 0x200A; + case MBlaze::RPVR11 : return 0x200B; + default: llvm_unreachable("Unknown register number!"); + } +} + +/// getRegisterFromNumbering - Given the enum value for some register, e.g. +/// MBlaze::R0, return the number that it corresponds to (e.g. 0). +static inline unsigned getMBlazeRegisterFromNumbering(unsigned Reg) { + switch (Reg) { + case 0 : return MBlaze::R0; + case 1 : return MBlaze::R1; + case 2 : return MBlaze::R2; + case 3 : return MBlaze::R3; + case 4 : return MBlaze::R4; + case 5 : return MBlaze::R5; + case 6 : return MBlaze::R6; + case 7 : return MBlaze::R7; + case 8 : return MBlaze::R8; + case 9 : return MBlaze::R9; + case 10 : return MBlaze::R10; + case 11 : return MBlaze::R11; + case 12 : return MBlaze::R12; + case 13 : return MBlaze::R13; + case 14 : return MBlaze::R14; + case 15 : return MBlaze::R15; + case 16 : return MBlaze::R16; + case 17 : return MBlaze::R17; + case 18 : return MBlaze::R18; + case 19 : return MBlaze::R19; + case 20 : return MBlaze::R20; + case 21 : return MBlaze::R21; + case 22 : return MBlaze::R22; + case 23 : return MBlaze::R23; + case 24 : return MBlaze::R24; + case 25 : return MBlaze::R25; + case 26 : return MBlaze::R26; + case 27 : return MBlaze::R27; + case 28 : return MBlaze::R28; + case 29 : return MBlaze::R29; + case 30 : return MBlaze::R30; + case 31 : return MBlaze::R31; + default: llvm_unreachable("Unknown register number!"); + } +} + +static inline unsigned getSpecialMBlazeRegisterFromNumbering(unsigned Reg) { + switch (Reg) { + case 0x0000 : return MBlaze::RPC; + case 0x0001 : return MBlaze::RMSR; + case 0x0003 : return MBlaze::REAR; + case 0x0005 : return MBlaze::RESR; + case 0x0007 : return MBlaze::RFSR; + case 0x000B : return MBlaze::RBTR; + case 0x000D : return MBlaze::REDR; + case 0x1000 : return MBlaze::RPID; + case 0x1001 : return MBlaze::RZPR; + case 0x1002 : return MBlaze::RTLBX; + case 0x1003 : return MBlaze::RTLBLO; + case 0x1004 : return MBlaze::RTLBHI; + case 0x2000 : return MBlaze::RPVR0; + case 0x2001 : return MBlaze::RPVR1; + case 0x2002 : return MBlaze::RPVR2; + case 0x2003 : return MBlaze::RPVR3; + case 0x2004 : return MBlaze::RPVR4; + case 0x2005 : return MBlaze::RPVR5; + case 0x2006 : return MBlaze::RPVR6; + case 0x2007 : return MBlaze::RPVR7; + case 0x2008 : return MBlaze::RPVR8; + case 0x2009 : return MBlaze::RPVR9; + case 0x200A : return MBlaze::RPVR10; + case 0x200B : return MBlaze::RPVR11; + default: llvm_unreachable("Unknown register number!"); + } +} + +} // end namespace llvm; + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeELFObjectWriter.cpp b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeELFObjectWriter.cpp new file mode 100644 index 0000000..2824b3c --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeELFObjectWriter.cpp @@ -0,0 +1,77 @@ +//===-- MBlazeELFObjectWriter.cpp - MBlaze ELF Writer ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MBlazeMCTargetDesc.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +namespace { + class MBlazeELFObjectWriter : public MCELFObjectTargetWriter { + public: + MBlazeELFObjectWriter(uint8_t OSABI); + + virtual ~MBlazeELFObjectWriter(); + protected: + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend) const; + }; +} + +MBlazeELFObjectWriter::MBlazeELFObjectWriter(uint8_t OSABI) + : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI, ELF::EM_MBLAZE, + /*HasRelocationAddend*/ false) {} + +MBlazeELFObjectWriter::~MBlazeELFObjectWriter() { +} + +unsigned MBlazeELFObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel, + bool IsRelocWithSymbol, + int64_t Addend) const { + // determine the type of the relocation + unsigned Type; + if (IsPCRel) { + switch ((unsigned)Fixup.getKind()) { + default: + llvm_unreachable("Unimplemented"); + case FK_PCRel_4: + Type = ELF::R_MICROBLAZE_64_PCREL; + break; + case FK_PCRel_2: + Type = ELF::R_MICROBLAZE_32_PCREL; + break; + } + } else { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + case FK_Data_4: + Type = ((IsRelocWithSymbol || Addend !=0) + ? ELF::R_MICROBLAZE_32 + : ELF::R_MICROBLAZE_64); + break; + case FK_Data_2: + Type = ELF::R_MICROBLAZE_32; + break; + } + } + return Type; +} + + + +MCObjectWriter *llvm::createMBlazeELFObjectWriter(raw_ostream &OS, + uint8_t OSABI) { + MCELFObjectTargetWriter *MOTW = new MBlazeELFObjectWriter(OSABI); + return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/ false); +} diff --git a/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCAsmInfo.cpp b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCAsmInfo.cpp new file mode 100644 index 0000000..8231f07 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCAsmInfo.cpp @@ -0,0 +1,26 @@ +//===-- MBlazeMCAsmInfo.cpp - MBlaze asm properties -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the MBlazeMCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeMCAsmInfo.h" +using namespace llvm; + +void MBlazeMCAsmInfo::anchor() { } + +MBlazeMCAsmInfo::MBlazeMCAsmInfo() { + IsLittleEndian = false; + StackGrowsUp = false; + SupportsDebugInformation = true; + AlignmentIsInBytes = false; + PrivateGlobalPrefix = "$"; + GPRel32Directive = "\t.gpword\t"; +} diff --git a/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCAsmInfo.h b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCAsmInfo.h new file mode 100644 index 0000000..977f9a6 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCAsmInfo.h @@ -0,0 +1,30 @@ +//===-- MBlazeMCAsmInfo.h - MBlaze asm properties --------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the MBlazeMCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZETARGETASMINFO_H +#define MBLAZETARGETASMINFO_H + +#include "llvm/MC/MCAsmInfo.h" + +namespace llvm { + class Target; + + class MBlazeMCAsmInfo : public MCAsmInfo { + virtual void anchor(); + public: + explicit MBlazeMCAsmInfo(); + }; + +} // namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCCodeEmitter.cpp b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCCodeEmitter.cpp new file mode 100644 index 0000000..bfd11a0 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCCodeEmitter.cpp @@ -0,0 +1,222 @@ +//===-- MBlazeMCCodeEmitter.cpp - Convert MBlaze code to machine code -----===// +// +// 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 MBlazeMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mccodeemitter" +#include "MCTargetDesc/MBlazeBaseInfo.h" +#include "MCTargetDesc/MBlazeMCTargetDesc.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +STATISTIC(MCNumEmitted, "Number of MC instructions emitted"); + +namespace { +class MBlazeMCCodeEmitter : public MCCodeEmitter { + MBlazeMCCodeEmitter(const MBlazeMCCodeEmitter &); // DO NOT IMPLEMENT + void operator=(const MBlazeMCCodeEmitter &); // DO NOT IMPLEMENT + const MCInstrInfo &MCII; + +public: + MBlazeMCCodeEmitter(const MCInstrInfo &mcii, const MCSubtargetInfo &sti, + MCContext &ctx) + : MCII(mcii) { + } + + ~MBlazeMCCodeEmitter() {} + + // getBinaryCodeForInstr - TableGen'erated function for getting the + // binary encoding for an instruction. + uint64_t getBinaryCodeForInstr(const MCInst &MI) 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) const; + unsigned getMachineOpValue(const MCInst &MI, unsigned OpIdx) const { + return getMachineOpValue(MI, MI.getOperand(OpIdx)); + } + + static unsigned GetMBlazeRegNum(const MCOperand &MO) { + // FIXME: getMBlazeRegisterNumbering() is sufficient? + llvm_unreachable("MBlazeMCCodeEmitter::GetMBlazeRegNum() not yet " + "implemented."); + } + + void EmitByte(unsigned char C, unsigned &CurByte, raw_ostream &OS) const { + // The MicroBlaze uses a bit reversed format so we need to reverse the + // order of the bits. Taken from: + // http://graphics.stanford.edu/~seander/bithacks.html + C = ((C * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32; + + OS << (char)C; + ++CurByte; + } + + void EmitRawByte(unsigned char C, unsigned &CurByte, raw_ostream &OS) const { + OS << (char)C; + ++CurByte; + } + + void EmitConstant(uint64_t Val, unsigned Size, unsigned &CurByte, + raw_ostream &OS) const { + assert(Size <= 8 && "size too big in emit constant"); + + for (unsigned i = 0; i != Size; ++i) { + EmitByte(Val & 255, CurByte, OS); + Val >>= 8; + } + } + + void EmitIMM(const MCOperand &imm, unsigned &CurByte, raw_ostream &OS) const; + void EmitIMM(const MCInst &MI, unsigned &CurByte, raw_ostream &OS) const; + + void EmitImmediate(const MCInst &MI, unsigned opNo, bool pcrel, + unsigned &CurByte, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups) const; + + void EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups) const; +}; + +} // end anonymous namespace + + +MCCodeEmitter *llvm::createMBlazeMCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new MBlazeMCCodeEmitter(MCII, STI, Ctx); +} + +/// getMachineOpValue - Return binary encoding of operand. If the machine +/// operand requires relocation, record the relocation and return zero. +unsigned MBlazeMCCodeEmitter::getMachineOpValue(const MCInst &MI, + const MCOperand &MO) const { + if (MO.isReg()) + return getMBlazeRegisterNumbering(MO.getReg()); + if (MO.isImm()) + return static_cast<unsigned>(MO.getImm()); + if (MO.isExpr()) + return 0; // The relocation has already been recorded at this point. +#ifndef NDEBUG + errs() << MO; +#endif + llvm_unreachable(0); +} + +void MBlazeMCCodeEmitter:: +EmitIMM(const MCOperand &imm, unsigned &CurByte, raw_ostream &OS) const { + int32_t val = (int32_t)imm.getImm(); + if (val > 32767 || val < -32768) { + EmitByte(0x0D, CurByte, OS); + EmitByte(0x00, CurByte, OS); + EmitRawByte((val >> 24) & 0xFF, CurByte, OS); + EmitRawByte((val >> 16) & 0xFF, CurByte, OS); + } +} + +void MBlazeMCCodeEmitter:: +EmitIMM(const MCInst &MI, unsigned &CurByte,raw_ostream &OS) const { + switch (MI.getOpcode()) { + default: break; + + case MBlaze::ADDIK32: + case MBlaze::ORI32: + case MBlaze::BRLID32: + EmitByte(0x0D, CurByte, OS); + EmitByte(0x00, CurByte, OS); + EmitRawByte(0, CurByte, OS); + EmitRawByte(0, CurByte, OS); + } +} + +void MBlazeMCCodeEmitter:: +EmitImmediate(const MCInst &MI, unsigned opNo, bool pcrel, unsigned &CurByte, + raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups) const { + assert(MI.getNumOperands()>opNo && "Not enought operands for instruction"); + + MCOperand oper = MI.getOperand(opNo); + + if (oper.isImm()) { + EmitIMM(oper, CurByte, OS); + } else if (oper.isExpr()) { + MCFixupKind FixupKind; + switch (MI.getOpcode()) { + default: + FixupKind = pcrel ? FK_PCRel_2 : FK_Data_2; + Fixups.push_back(MCFixup::Create(0,oper.getExpr(),FixupKind)); + break; + case MBlaze::ORI32: + case MBlaze::ADDIK32: + case MBlaze::BRLID32: + FixupKind = pcrel ? FK_PCRel_4 : FK_Data_4; + Fixups.push_back(MCFixup::Create(0,oper.getExpr(),FixupKind)); + break; + } + } +} + + + +void MBlazeMCCodeEmitter:: +EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups) const { + unsigned Opcode = MI.getOpcode(); + const MCInstrDesc &Desc = MCII.get(Opcode); + uint64_t TSFlags = Desc.TSFlags; + // Keep track of the current byte being emitted. + unsigned CurByte = 0; + + // Emit an IMM instruction if the instruction we are encoding requires it + EmitIMM(MI,CurByte,OS); + + switch ((TSFlags & MBlazeII::FormMask)) { + default: break; + case MBlazeII::FPseudo: + // Pseudo instructions don't get encoded. + return; + case MBlazeII::FRRI: + EmitImmediate(MI, 2, false, CurByte, OS, Fixups); + break; + case MBlazeII::FRIR: + EmitImmediate(MI, 1, false, CurByte, OS, Fixups); + break; + case MBlazeII::FCRI: + EmitImmediate(MI, 1, true, CurByte, OS, Fixups); + break; + case MBlazeII::FRCI: + EmitImmediate(MI, 1, true, CurByte, OS, Fixups); + case MBlazeII::FCCI: + EmitImmediate(MI, 0, true, CurByte, OS, Fixups); + break; + } + + ++MCNumEmitted; // Keep track of the # of mi's emitted + unsigned Value = getBinaryCodeForInstr(MI); + EmitConstant(Value, 4, CurByte, OS); +} + +// FIXME: These #defines shouldn't be necessary. Instead, tblgen should +// be able to generate code emitter helpers for either variant, like it +// does for the AsmWriter. +#define MBlazeCodeEmitter MBlazeMCCodeEmitter +#define MachineInstr MCInst +#include "MBlazeGenCodeEmitter.inc" +#undef MBlazeCodeEmitter +#undef MachineInstr diff --git a/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCTargetDesc.cpp b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCTargetDesc.cpp new file mode 100644 index 0000000..9a7549b --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCTargetDesc.cpp @@ -0,0 +1,141 @@ +//===-- MBlazeMCTargetDesc.cpp - MBlaze Target Descriptions ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides MBlaze specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#include "MBlazeMCTargetDesc.h" +#include "MBlazeMCAsmInfo.h" +#include "InstPrinter/MBlazeInstPrinter.h" +#include "llvm/MC/MCCodeGenInfo.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +#define GET_INSTRINFO_MC_DESC +#include "MBlazeGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "MBlazeGenSubtargetInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "MBlazeGenRegisterInfo.inc" + +using namespace llvm; + + +static MCInstrInfo *createMBlazeMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitMBlazeMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createMBlazeMCRegisterInfo(StringRef TT) { + MCRegisterInfo *X = new MCRegisterInfo(); + InitMBlazeMCRegisterInfo(X, MBlaze::R15); + return X; +} + +static MCSubtargetInfo *createMBlazeMCSubtargetInfo(StringRef TT, StringRef CPU, + StringRef FS) { + MCSubtargetInfo *X = new MCSubtargetInfo(); + InitMBlazeMCSubtargetInfo(X, TT, CPU, FS); + return X; +} + +static MCAsmInfo *createMCAsmInfo(const Target &T, StringRef TT) { + Triple TheTriple(TT); + switch (TheTriple.getOS()) { + default: + return new MBlazeMCAsmInfo(); + } +} + +static MCCodeGenInfo *createMBlazeMCCodeGenInfo(StringRef TT, Reloc::Model RM, + CodeModel::Model CM, + CodeGenOpt::Level OL) { + MCCodeGenInfo *X = new MCCodeGenInfo(); + if (RM == Reloc::Default) + RM = Reloc::Static; + if (CM == CodeModel::Default) + CM = CodeModel::Small; + X->InitMCCodeGenInfo(RM, CM, OL); + return X; +} + +static MCStreamer *createMCStreamer(const Target &T, StringRef TT, + MCContext &Ctx, MCAsmBackend &MAB, + raw_ostream &_OS, + MCCodeEmitter *_Emitter, + bool RelaxAll, + bool NoExecStack) { + Triple TheTriple(TT); + + if (TheTriple.isOSDarwin()) { + llvm_unreachable("MBlaze does not support Darwin MACH-O format"); + } + + if (TheTriple.isOSWindows()) { + llvm_unreachable("MBlaze does not support Windows COFF format"); + } + + return createELFStreamer(Ctx, MAB, _OS, _Emitter, RelaxAll, NoExecStack); +} + +static MCInstPrinter *createMBlazeMCInstPrinter(const Target &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI) { + if (SyntaxVariant == 0) + return new MBlazeInstPrinter(MAI, MII, MRI); + return 0; +} + +// Force static initialization. +extern "C" void LLVMInitializeMBlazeTargetMC() { + // Register the MC asm info. + RegisterMCAsmInfoFn X(TheMBlazeTarget, createMCAsmInfo); + + // Register the MC codegen info. + TargetRegistry::RegisterMCCodeGenInfo(TheMBlazeTarget, + createMBlazeMCCodeGenInfo); + + // Register the MC instruction info. + TargetRegistry::RegisterMCInstrInfo(TheMBlazeTarget, createMBlazeMCInstrInfo); + + // Register the MC register info. + TargetRegistry::RegisterMCRegInfo(TheMBlazeTarget, + createMBlazeMCRegisterInfo); + + // Register the MC subtarget info. + TargetRegistry::RegisterMCSubtargetInfo(TheMBlazeTarget, + createMBlazeMCSubtargetInfo); + + // Register the MC code emitter + TargetRegistry::RegisterMCCodeEmitter(TheMBlazeTarget, + llvm::createMBlazeMCCodeEmitter); + + // Register the asm backend + TargetRegistry::RegisterMCAsmBackend(TheMBlazeTarget, + createMBlazeAsmBackend); + + // Register the object streamer + TargetRegistry::RegisterMCObjectStreamer(TheMBlazeTarget, + createMCStreamer); + + // Register the MCInstPrinter. + TargetRegistry::RegisterMCInstPrinter(TheMBlazeTarget, + createMBlazeMCInstPrinter); +} diff --git a/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCTargetDesc.h b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCTargetDesc.h new file mode 100644 index 0000000..7cc96c6 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MCTargetDesc/MBlazeMCTargetDesc.h @@ -0,0 +1,55 @@ +//===-- MBlazeMCTargetDesc.h - MBlaze Target Descriptions -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides MBlaze specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#ifndef MBLAZEMCTARGETDESC_H +#define MBLAZEMCTARGETDESC_H + +#include "llvm/Support/DataTypes.h" + +namespace llvm { +class MCAsmBackend; +class MCContext; +class MCCodeEmitter; +class MCInstrInfo; +class MCObjectWriter; +class MCRegisterInfo; +class MCSubtargetInfo; +class Target; +class StringRef; +class raw_ostream; + +extern Target TheMBlazeTarget; + +MCCodeEmitter *createMBlazeMCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI, + MCContext &Ctx); + +MCAsmBackend *createMBlazeAsmBackend(const Target &T, StringRef TT); + +MCObjectWriter *createMBlazeELFObjectWriter(raw_ostream &OS, uint8_t OSABI); +} // End llvm namespace + +// Defines symbolic names for MBlaze registers. This defines a mapping from +// register name to register number. +#define GET_REGINFO_ENUM +#include "MBlazeGenRegisterInfo.inc" + +// Defines symbolic names for the MBlaze instructions. +#define GET_INSTRINFO_ENUM +#include "MBlazeGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "MBlazeGenSubtargetInfo.inc" + +#endif diff --git a/contrib/llvm/lib/Target/MBlaze/TargetInfo/MBlazeTargetInfo.cpp b/contrib/llvm/lib/Target/MBlaze/TargetInfo/MBlazeTargetInfo.cpp new file mode 100644 index 0000000..71210d8 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/TargetInfo/MBlazeTargetInfo.cpp @@ -0,0 +1,19 @@ +//===-- MBlazeTargetInfo.cpp - MBlaze Target Implementation ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MBlaze.h" +#include "llvm/Module.h" +#include "llvm/Support/TargetRegistry.h" +using namespace llvm; + +Target llvm::TheMBlazeTarget; + +extern "C" void LLVMInitializeMBlazeTargetInfo() { + RegisterTarget<Triple::mblaze> X(TheMBlazeTarget, "mblaze", "MBlaze"); +} |