diff options
Diffstat (limited to 'contrib/llvm/lib/Target/Mips')
96 files changed, 39547 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp new file mode 100644 index 000000000000..cdae6c2f37e5 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -0,0 +1,2509 @@ +//===-- MipsAsmParser.cpp - Parse Mips assembly to MCInst instructions ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "MipsRegisterInfo.h" +#include "MipsTargetStreamer.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/ADT/APInt.h" + +using namespace llvm; + +namespace llvm { +class MCInstrInfo; +} + +namespace { +class MipsAssemblerOptions { +public: + MipsAssemblerOptions() : aTReg(1), reorder(true), macro(true) {} + + unsigned getATRegNum() { return aTReg; } + bool setATReg(unsigned Reg); + + bool isReorder() { return reorder; } + void setReorder() { reorder = true; } + void setNoreorder() { reorder = false; } + + bool isMacro() { return macro; } + void setMacro() { macro = true; } + void setNomacro() { macro = false; } + +private: + unsigned aTReg; + bool reorder; + bool macro; +}; +} + +namespace { +class MipsAsmParser : public MCTargetAsmParser { + + MipsTargetStreamer &getTargetStreamer() { + MCTargetStreamer &TS = Parser.getStreamer().getTargetStreamer(); + return static_cast<MipsTargetStreamer &>(TS); + } + + MCSubtargetInfo &STI; + MCAsmParser &Parser; + MipsAssemblerOptions Options; + bool hasConsumedDollar; + +#define GET_ASSEMBLER_HEADER +#include "MipsGenAsmMatcher.inc" + + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + SmallVectorImpl<MCParsedAsmOperand *> &Operands, + MCStreamer &Out, unsigned &ErrorInfo, + bool MatchingInlineAsm); + + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc); + + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, + SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + bool ParseDirective(AsmToken DirectiveID); + + MipsAsmParser::OperandMatchResultTy + parseRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands, int RegKind); + + MipsAsmParser::OperandMatchResultTy + parseMSARegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands, int RegKind); + + MipsAsmParser::OperandMatchResultTy + parseMSACtrlRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands, + int RegKind); + + MipsAsmParser::OperandMatchResultTy + parseMemOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + bool parsePtrReg(SmallVectorImpl<MCParsedAsmOperand *> &Operands, + int RegKind); + + MipsAsmParser::OperandMatchResultTy + parsePtrReg(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseGPR32(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseGPR64(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseHWRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseCCRRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseAFGR64Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseFGR64Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseFGR32Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseFGRH32Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseFCCRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseACC64DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseLO32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseHI32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseCOP2(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseMSA128BRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseMSA128HRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseMSA128WRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseMSA128DRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseMSA128CtrlRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseInvNum(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + MipsAsmParser::OperandMatchResultTy + parseLSAImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands); + + bool searchSymbolAlias(SmallVectorImpl<MCParsedAsmOperand*> &Operands, + unsigned RegKind); + + bool ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &, + StringRef Mnemonic); + + int tryParseRegister(bool is64BitReg); + + bool tryParseRegisterOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands, + bool is64BitReg); + + bool needsExpansion(MCInst &Inst); + + void expandInstruction(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + void expandLoadImm(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + void expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + void expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + void expandMemInst(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions, bool isLoad, + bool isImmOpnd); + bool reportParseError(StringRef ErrorMsg); + + bool parseMemOffset(const MCExpr *&Res, bool isParenExpr); + bool parseRelocOperand(const MCExpr *&Res); + + const MCExpr *evaluateRelocExpr(const MCExpr *Expr, StringRef RelocStr); + + bool isEvaluated(const MCExpr *Expr); + bool parseDirectiveSet(); + bool parseDirectiveMipsHackStocg(); + bool parseDirectiveMipsHackELFFlags(); + + bool parseSetAtDirective(); + bool parseSetNoAtDirective(); + bool parseSetMacroDirective(); + bool parseSetNoMacroDirective(); + bool parseSetReorderDirective(); + bool parseSetNoReorderDirective(); + + bool parseSetAssignment(); + + bool parseDirectiveWord(unsigned Size, SMLoc L); + bool parseDirectiveGpWord(); + + MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol); + + bool isMips64() const { + return (STI.getFeatureBits() & Mips::FeatureMips64) != 0; + } + + bool isFP64() const { + return (STI.getFeatureBits() & Mips::FeatureFP64Bit) != 0; + } + + bool isN64() const { return STI.getFeatureBits() & Mips::FeatureN64; } + + int matchRegisterName(StringRef Symbol, bool is64BitReg); + + int matchCPURegisterName(StringRef Symbol); + + int matchRegisterByNumber(unsigned RegNum, unsigned RegClass); + + int matchFPURegisterName(StringRef Name); + + int matchFCCRegisterName(StringRef Name); + + int matchACRegisterName(StringRef Name); + + int matchMSA128RegisterName(StringRef Name); + + int matchMSA128CtrlRegisterName(StringRef Name); + + int regKindToRegClass(int RegKind); + + unsigned getReg(int RC, int RegNo); + + int getATReg(); + + bool processInstruction(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions); + + // Helper function that checks if the value of a vector index is within the + // boundaries of accepted values for each RegisterKind + // Example: INSERT.B $w0[n], $1 => 16 > n >= 0 + bool validateMSAIndex(int Val, int RegKind); + +public: + MipsAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser, + const MCInstrInfo &MII) + : MCTargetAsmParser(), STI(sti), Parser(parser), + hasConsumedDollar(false) { + // Initialize the set of available features. + setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + } + + MCAsmParser &getParser() const { return Parser; } + MCAsmLexer &getLexer() const { return Parser.getLexer(); } +}; +} + +namespace { + +/// MipsOperand - Instances of this class represent a parsed Mips machine +/// instruction. +class MipsOperand : public MCParsedAsmOperand { + +public: + enum RegisterKind { + Kind_None, + Kind_GPR32, + Kind_GPR64, + Kind_HWRegs, + Kind_FGR32Regs, + Kind_FGRH32Regs, + Kind_FGR64Regs, + Kind_AFGR64Regs, + Kind_CCRRegs, + Kind_FCCRegs, + Kind_ACC64DSP, + Kind_LO32DSP, + Kind_HI32DSP, + Kind_COP2, + Kind_MSA128BRegs, + Kind_MSA128HRegs, + Kind_MSA128WRegs, + Kind_MSA128DRegs, + Kind_MSA128CtrlRegs + }; + +private: + enum KindTy { + k_CondCode, + k_CoprocNum, + k_Immediate, + k_Memory, + k_PostIndexRegister, + k_Register, + k_PtrReg, + k_Token, + k_LSAImm + } Kind; + + MipsOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} + + struct Token { + const char *Data; + unsigned Length; + }; + + struct RegOp { + unsigned RegNum; + RegisterKind Kind; + }; + + struct ImmOp { + const MCExpr *Val; + }; + + struct MemOp { + unsigned Base; + const MCExpr *Off; + }; + + union { + struct Token Tok; + struct RegOp Reg; + struct ImmOp Imm; + struct MemOp Mem; + }; + + SMLoc StartLoc, EndLoc; + +public: + void addRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getReg())); + } + + void addPtrRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getPtrReg())); + } + + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + // Add as immediate 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 addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCExpr *Expr = getImm(); + addExpr(Inst, Expr); + } + + void addMemOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::CreateReg(getMemBase())); + + const MCExpr *Expr = getMemOff(); + addExpr(Inst, Expr); + } + + bool isReg() const { return Kind == k_Register; } + bool isImm() const { return Kind == k_Immediate; } + bool isToken() const { return Kind == k_Token; } + bool isMem() const { return Kind == k_Memory; } + bool isPtrReg() const { return Kind == k_PtrReg; } + bool isInvNum() const { return Kind == k_Immediate; } + bool isLSAImm() const { return Kind == k_LSAImm; } + + StringRef getToken() const { + assert(Kind == k_Token && "Invalid access!"); + return StringRef(Tok.Data, Tok.Length); + } + + unsigned getReg() const { + assert((Kind == k_Register) && "Invalid access!"); + return Reg.RegNum; + } + + unsigned getPtrReg() const { + assert((Kind == k_PtrReg) && "Invalid access!"); + return Reg.RegNum; + } + + void setRegKind(RegisterKind RegKind) { + assert((Kind == k_Register || Kind == k_PtrReg) && "Invalid access!"); + Reg.Kind = RegKind; + } + + const MCExpr *getImm() const { + assert((Kind == k_Immediate || Kind == k_LSAImm) && "Invalid access!"); + return Imm.Val; + } + + unsigned getMemBase() const { + assert((Kind == k_Memory) && "Invalid access!"); + return Mem.Base; + } + + const MCExpr *getMemOff() const { + assert((Kind == k_Memory) && "Invalid access!"); + return Mem.Off; + } + + static MipsOperand *CreateToken(StringRef Str, SMLoc S) { + MipsOperand *Op = new MipsOperand(k_Token); + Op->Tok.Data = Str.data(); + Op->Tok.Length = Str.size(); + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static MipsOperand *CreateReg(unsigned RegNum, SMLoc S, SMLoc E) { + MipsOperand *Op = new MipsOperand(k_Register); + Op->Reg.RegNum = RegNum; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static MipsOperand *CreatePtrReg(unsigned RegNum, SMLoc S, SMLoc E) { + MipsOperand *Op = new MipsOperand(k_PtrReg); + Op->Reg.RegNum = RegNum; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static MipsOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) { + MipsOperand *Op = new MipsOperand(k_Immediate); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static MipsOperand *CreateLSAImm(const MCExpr *Val, SMLoc S, SMLoc E) { + MipsOperand *Op = new MipsOperand(k_LSAImm); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static MipsOperand *CreateMem(unsigned Base, const MCExpr *Off, + SMLoc S, SMLoc E) { + MipsOperand *Op = new MipsOperand(k_Memory); + Op->Mem.Base = Base; + Op->Mem.Off = Off; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + bool isGPR32Asm() const { + return Kind == k_Register && Reg.Kind == Kind_GPR32; + } + void addRegAsmOperands(MCInst &Inst, unsigned N) const { + Inst.addOperand(MCOperand::CreateReg(Reg.RegNum)); + } + + bool isGPR64Asm() const { + return Kind == k_Register && Reg.Kind == Kind_GPR64; + } + + bool isHWRegsAsm() const { + assert((Kind == k_Register) && "Invalid access!"); + return Reg.Kind == Kind_HWRegs; + } + + bool isCCRAsm() const { + assert((Kind == k_Register) && "Invalid access!"); + return Reg.Kind == Kind_CCRRegs; + } + + bool isAFGR64Asm() const { + return Kind == k_Register && Reg.Kind == Kind_AFGR64Regs; + } + + bool isFGR64Asm() const { + return Kind == k_Register && Reg.Kind == Kind_FGR64Regs; + } + + bool isFGR32Asm() const { + return (Kind == k_Register) && Reg.Kind == Kind_FGR32Regs; + } + + bool isFGRH32Asm() const { + return (Kind == k_Register) && Reg.Kind == Kind_FGRH32Regs; + } + + bool isFCCRegsAsm() const { + return (Kind == k_Register) && Reg.Kind == Kind_FCCRegs; + } + + bool isACC64DSPAsm() const { + return Kind == k_Register && Reg.Kind == Kind_ACC64DSP; + } + + bool isLO32DSPAsm() const { + return Kind == k_Register && Reg.Kind == Kind_LO32DSP; + } + + bool isHI32DSPAsm() const { + return Kind == k_Register && Reg.Kind == Kind_HI32DSP; + } + + bool isCOP2Asm() const { return Kind == k_Register && Reg.Kind == Kind_COP2; } + + bool isMSA128BAsm() const { + return Kind == k_Register && Reg.Kind == Kind_MSA128BRegs; + } + + bool isMSA128HAsm() const { + return Kind == k_Register && Reg.Kind == Kind_MSA128HRegs; + } + + bool isMSA128WAsm() const { + return Kind == k_Register && Reg.Kind == Kind_MSA128WRegs; + } + + bool isMSA128DAsm() const { + return Kind == k_Register && Reg.Kind == Kind_MSA128DRegs; + } + + bool isMSA128CRAsm() const { + return Kind == k_Register && Reg.Kind == Kind_MSA128CtrlRegs; + } + + /// 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; } + + virtual void print(raw_ostream &OS) const { + llvm_unreachable("unimplemented!"); + } +}; // class MipsOperand +} // namespace + +namespace llvm { +extern const MCInstrDesc MipsInsts[]; +} +static const MCInstrDesc &getInstDesc(unsigned Opcode) { + return MipsInsts[Opcode]; +} + +bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); + Inst.setLoc(IDLoc); + if (MCID.hasDelaySlot() && Options.isReorder()) { + // If this instruction has a delay slot and .set reorder is active, + // emit a NOP after it. + Instructions.push_back(Inst); + MCInst NopInst; + NopInst.setOpcode(Mips::SLL); + NopInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); + NopInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); + NopInst.addOperand(MCOperand::CreateImm(0)); + Instructions.push_back(NopInst); + return false; + } + + if (MCID.mayLoad() || MCID.mayStore()) { + // Check the offset of memory operand, if it is a symbol + // reference or immediate we may have to expand instructions. + for (unsigned i = 0; i < MCID.getNumOperands(); i++) { + const MCOperandInfo &OpInfo = MCID.OpInfo[i]; + if ((OpInfo.OperandType == MCOI::OPERAND_MEMORY) || + (OpInfo.OperandType == MCOI::OPERAND_UNKNOWN)) { + MCOperand &Op = Inst.getOperand(i); + if (Op.isImm()) { + int MemOffset = Op.getImm(); + if (MemOffset < -32768 || MemOffset > 32767) { + // Offset can't exceed 16bit value. + expandMemInst(Inst, IDLoc, Instructions, MCID.mayLoad(), true); + return false; + } + } else if (Op.isExpr()) { + const MCExpr *Expr = Op.getExpr(); + if (Expr->getKind() == MCExpr::SymbolRef) { + const MCSymbolRefExpr *SR = + static_cast<const MCSymbolRefExpr *>(Expr); + if (SR->getKind() == MCSymbolRefExpr::VK_None) { + // Expand symbol. + expandMemInst(Inst, IDLoc, Instructions, MCID.mayLoad(), false); + return false; + } + } else if (!isEvaluated(Expr)) { + expandMemInst(Inst, IDLoc, Instructions, MCID.mayLoad(), false); + return false; + } + } + } + } // for + } // if load/store + + if (needsExpansion(Inst)) + expandInstruction(Inst, IDLoc, Instructions); + else + Instructions.push_back(Inst); + + return false; +} + +bool MipsAsmParser::needsExpansion(MCInst &Inst) { + + switch (Inst.getOpcode()) { + case Mips::LoadImm32Reg: + case Mips::LoadAddr32Imm: + case Mips::LoadAddr32Reg: + return true; + default: + return false; + } +} + +void MipsAsmParser::expandInstruction(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + switch (Inst.getOpcode()) { + case Mips::LoadImm32Reg: + return expandLoadImm(Inst, IDLoc, Instructions); + case Mips::LoadAddr32Imm: + return expandLoadAddressImm(Inst, IDLoc, Instructions); + case Mips::LoadAddr32Reg: + return expandLoadAddressReg(Inst, IDLoc, Instructions); + } +} + +void MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + MCInst tmpInst; + const MCOperand &ImmOp = Inst.getOperand(1); + assert(ImmOp.isImm() && "expected immediate operand kind"); + const MCOperand &RegOp = Inst.getOperand(0); + assert(RegOp.isReg() && "expected register operand kind"); + + int ImmValue = ImmOp.getImm(); + tmpInst.setLoc(IDLoc); + if (0 <= ImmValue && ImmValue <= 65535) { + // For 0 <= j <= 65535. + // li d,j => ori d,$zero,j + tmpInst.setOpcode(Mips::ORi); + tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); + tmpInst.addOperand(MCOperand::CreateImm(ImmValue)); + Instructions.push_back(tmpInst); + } else if (ImmValue < 0 && ImmValue >= -32768) { + // For -32768 <= j < 0. + // li d,j => addiu d,$zero,j + tmpInst.setOpcode(Mips::ADDiu); + tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); + tmpInst.addOperand(MCOperand::CreateImm(ImmValue)); + Instructions.push_back(tmpInst); + } else { + // For any other value of j that is representable as a 32-bit integer. + // li d,j => lui d,hi16(j) + // ori d,d,lo16(j) + tmpInst.setOpcode(Mips::LUi); + tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateImm((ImmValue & 0xffff0000) >> 16)); + Instructions.push_back(tmpInst); + tmpInst.clear(); + tmpInst.setOpcode(Mips::ORi); + tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateImm(ImmValue & 0xffff)); + tmpInst.setLoc(IDLoc); + Instructions.push_back(tmpInst); + } +} + +void +MipsAsmParser::expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + MCInst tmpInst; + const MCOperand &ImmOp = Inst.getOperand(2); + assert(ImmOp.isImm() && "expected immediate operand kind"); + const MCOperand &SrcRegOp = Inst.getOperand(1); + assert(SrcRegOp.isReg() && "expected register operand kind"); + const MCOperand &DstRegOp = Inst.getOperand(0); + assert(DstRegOp.isReg() && "expected register operand kind"); + int ImmValue = ImmOp.getImm(); + if (-32768 <= ImmValue && ImmValue <= 65535) { + // For -32768 <= j <= 65535. + // la d,j(s) => addiu d,s,j + tmpInst.setOpcode(Mips::ADDiu); + tmpInst.addOperand(MCOperand::CreateReg(DstRegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateReg(SrcRegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateImm(ImmValue)); + Instructions.push_back(tmpInst); + } else { + // For any other value of j that is representable as a 32-bit integer. + // la d,j(s) => lui d,hi16(j) + // ori d,d,lo16(j) + // addu d,d,s + tmpInst.setOpcode(Mips::LUi); + tmpInst.addOperand(MCOperand::CreateReg(DstRegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateImm((ImmValue & 0xffff0000) >> 16)); + Instructions.push_back(tmpInst); + tmpInst.clear(); + tmpInst.setOpcode(Mips::ORi); + tmpInst.addOperand(MCOperand::CreateReg(DstRegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateReg(DstRegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateImm(ImmValue & 0xffff)); + Instructions.push_back(tmpInst); + tmpInst.clear(); + tmpInst.setOpcode(Mips::ADDu); + tmpInst.addOperand(MCOperand::CreateReg(DstRegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateReg(DstRegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateReg(SrcRegOp.getReg())); + Instructions.push_back(tmpInst); + } +} + +void +MipsAsmParser::expandLoadAddressImm(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions) { + MCInst tmpInst; + const MCOperand &ImmOp = Inst.getOperand(1); + assert(ImmOp.isImm() && "expected immediate operand kind"); + const MCOperand &RegOp = Inst.getOperand(0); + assert(RegOp.isReg() && "expected register operand kind"); + int ImmValue = ImmOp.getImm(); + if (-32768 <= ImmValue && ImmValue <= 65535) { + // For -32768 <= j <= 65535. + // la d,j => addiu d,$zero,j + tmpInst.setOpcode(Mips::ADDiu); + tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateReg(Mips::ZERO)); + tmpInst.addOperand(MCOperand::CreateImm(ImmValue)); + Instructions.push_back(tmpInst); + } else { + // For any other value of j that is representable as a 32-bit integer. + // la d,j => lui d,hi16(j) + // ori d,d,lo16(j) + tmpInst.setOpcode(Mips::LUi); + tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateImm((ImmValue & 0xffff0000) >> 16)); + Instructions.push_back(tmpInst); + tmpInst.clear(); + tmpInst.setOpcode(Mips::ORi); + tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateReg(RegOp.getReg())); + tmpInst.addOperand(MCOperand::CreateImm(ImmValue & 0xffff)); + Instructions.push_back(tmpInst); + } +} + +void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl<MCInst> &Instructions, + bool isLoad, bool isImmOpnd) { + const MCSymbolRefExpr *SR; + MCInst TempInst; + unsigned ImmOffset, HiOffset, LoOffset; + const MCExpr *ExprOffset; + unsigned TmpRegNum; + unsigned AtRegNum = getReg( + (isMips64()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, getATReg()); + // 1st operand is either the source or destination register. + assert(Inst.getOperand(0).isReg() && "expected register operand kind"); + unsigned RegOpNum = Inst.getOperand(0).getReg(); + // 2nd operand is the base register. + assert(Inst.getOperand(1).isReg() && "expected register operand kind"); + unsigned BaseRegNum = Inst.getOperand(1).getReg(); + // 3rd operand is either an immediate or expression. + if (isImmOpnd) { + assert(Inst.getOperand(2).isImm() && "expected immediate operand kind"); + ImmOffset = Inst.getOperand(2).getImm(); + LoOffset = ImmOffset & 0x0000ffff; + HiOffset = (ImmOffset & 0xffff0000) >> 16; + // If msb of LoOffset is 1(negative number) we must increment HiOffset. + if (LoOffset & 0x8000) + HiOffset++; + } else + ExprOffset = Inst.getOperand(2).getExpr(); + // All instructions will have the same location. + TempInst.setLoc(IDLoc); + // 1st instruction in expansion is LUi. For load instruction we can use + // the dst register as a temporary if base and dst are different, + // but for stores we must use $at. + TmpRegNum = (isLoad && (BaseRegNum != RegOpNum)) ? RegOpNum : AtRegNum; + TempInst.setOpcode(Mips::LUi); + TempInst.addOperand(MCOperand::CreateReg(TmpRegNum)); + if (isImmOpnd) + TempInst.addOperand(MCOperand::CreateImm(HiOffset)); + else { + if (ExprOffset->getKind() == MCExpr::SymbolRef) { + SR = static_cast<const MCSymbolRefExpr *>(ExprOffset); + const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::Create( + SR->getSymbol().getName(), MCSymbolRefExpr::VK_Mips_ABS_HI, + getContext()); + TempInst.addOperand(MCOperand::CreateExpr(HiExpr)); + } else { + const MCExpr *HiExpr = evaluateRelocExpr(ExprOffset, "hi"); + TempInst.addOperand(MCOperand::CreateExpr(HiExpr)); + } + } + // Add the instruction to the list. + Instructions.push_back(TempInst); + // Prepare TempInst for next instruction. + TempInst.clear(); + // Add temp register to base. + TempInst.setOpcode(Mips::ADDu); + TempInst.addOperand(MCOperand::CreateReg(TmpRegNum)); + TempInst.addOperand(MCOperand::CreateReg(TmpRegNum)); + TempInst.addOperand(MCOperand::CreateReg(BaseRegNum)); + Instructions.push_back(TempInst); + TempInst.clear(); + // And finaly, create original instruction with low part + // of offset and new base. + TempInst.setOpcode(Inst.getOpcode()); + TempInst.addOperand(MCOperand::CreateReg(RegOpNum)); + TempInst.addOperand(MCOperand::CreateReg(TmpRegNum)); + if (isImmOpnd) + TempInst.addOperand(MCOperand::CreateImm(LoOffset)); + else { + if (ExprOffset->getKind() == MCExpr::SymbolRef) { + const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::Create( + SR->getSymbol().getName(), MCSymbolRefExpr::VK_Mips_ABS_LO, + getContext()); + TempInst.addOperand(MCOperand::CreateExpr(LoExpr)); + } else { + const MCExpr *LoExpr = evaluateRelocExpr(ExprOffset, "lo"); + TempInst.addOperand(MCOperand::CreateExpr(LoExpr)); + } + } + Instructions.push_back(TempInst); + TempInst.clear(); +} + +bool MipsAsmParser::MatchAndEmitInstruction( + SMLoc IDLoc, unsigned &Opcode, + SmallVectorImpl<MCParsedAsmOperand *> &Operands, MCStreamer &Out, + unsigned &ErrorInfo, bool MatchingInlineAsm) { + MCInst Inst; + SmallVector<MCInst, 8> Instructions; + unsigned MatchResult = + MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); + + switch (MatchResult) { + default: + break; + case Match_Success: { + if (processInstruction(Inst, IDLoc, Instructions)) + return true; + for (unsigned i = 0; i < Instructions.size(); i++) + Out.EmitInstruction(Instructions[i]); + return false; + } + case Match_MissingFeature: + Error(IDLoc, "instruction requires a CPU feature not currently enabled"); + return true; + case Match_InvalidOperand: { + SMLoc ErrorLoc = IDLoc; + if (ErrorInfo != ~0U) { + if (ErrorInfo >= Operands.size()) + return Error(IDLoc, "too few operands for instruction"); + + ErrorLoc = ((MipsOperand *)Operands[ErrorInfo])->getStartLoc(); + if (ErrorLoc == SMLoc()) + ErrorLoc = IDLoc; + } + + return Error(ErrorLoc, "invalid operand for instruction"); + } + case Match_MnemonicFail: + return Error(IDLoc, "invalid instruction"); + } + return true; +} + +int MipsAsmParser::matchCPURegisterName(StringRef Name) { + int CC; + + if (Name == "at") + return getATReg(); + + CC = StringSwitch<unsigned>(Name) + .Case("zero", 0) + .Case("a0", 4) + .Case("a1", 5) + .Case("a2", 6) + .Case("a3", 7) + .Case("v0", 2) + .Case("v1", 3) + .Case("s0", 16) + .Case("s1", 17) + .Case("s2", 18) + .Case("s3", 19) + .Case("s4", 20) + .Case("s5", 21) + .Case("s6", 22) + .Case("s7", 23) + .Case("k0", 26) + .Case("k1", 27) + .Case("sp", 29) + .Case("fp", 30) + .Case("gp", 28) + .Case("ra", 31) + .Case("t0", 8) + .Case("t1", 9) + .Case("t2", 10) + .Case("t3", 11) + .Case("t4", 12) + .Case("t5", 13) + .Case("t6", 14) + .Case("t7", 15) + .Case("t8", 24) + .Case("t9", 25) + .Default(-1); + + // Although SGI documentation just cuts out t0-t3 for n32/n64, + // GNU pushes the values of t0-t3 to override the o32/o64 values for t4-t7 + // We are supporting both cases, so for t0-t3 we'll just push them to t4-t7. + if (isMips64() && 8 <= CC && CC <= 11) + CC += 4; + + if (CC == -1 && isMips64()) + CC = StringSwitch<unsigned>(Name) + .Case("a4", 8) + .Case("a5", 9) + .Case("a6", 10) + .Case("a7", 11) + .Case("kt0", 26) + .Case("kt1", 27) + .Case("s8", 30) + .Default(-1); + + return CC; +} + +int MipsAsmParser::matchFPURegisterName(StringRef Name) { + + if (Name[0] == 'f') { + StringRef NumString = Name.substr(1); + unsigned IntVal; + if (NumString.getAsInteger(10, IntVal)) + return -1; // This is not an integer. + if (IntVal > 31) // Maximum index for fpu register. + return -1; + return IntVal; + } + return -1; +} + +int MipsAsmParser::matchFCCRegisterName(StringRef Name) { + + if (Name.startswith("fcc")) { + StringRef NumString = Name.substr(3); + unsigned IntVal; + if (NumString.getAsInteger(10, IntVal)) + return -1; // This is not an integer. + if (IntVal > 7) // There are only 8 fcc registers. + return -1; + return IntVal; + } + return -1; +} + +int MipsAsmParser::matchACRegisterName(StringRef Name) { + + if (Name.startswith("ac")) { + StringRef NumString = Name.substr(2); + unsigned IntVal; + if (NumString.getAsInteger(10, IntVal)) + return -1; // This is not an integer. + if (IntVal > 3) // There are only 3 acc registers. + return -1; + return IntVal; + } + return -1; +} + +int MipsAsmParser::matchMSA128RegisterName(StringRef Name) { + unsigned IntVal; + + if (Name.front() != 'w' || Name.drop_front(1).getAsInteger(10, IntVal)) + return -1; + + if (IntVal > 31) + return -1; + + return IntVal; +} + +int MipsAsmParser::matchMSA128CtrlRegisterName(StringRef Name) { + int CC; + + CC = StringSwitch<unsigned>(Name) + .Case("msair", 0) + .Case("msacsr", 1) + .Case("msaaccess", 2) + .Case("msasave", 3) + .Case("msamodify", 4) + .Case("msarequest", 5) + .Case("msamap", 6) + .Case("msaunmap", 7) + .Default(-1); + + return CC; +} + +int MipsAsmParser::matchRegisterName(StringRef Name, bool is64BitReg) { + + int CC; + CC = matchCPURegisterName(Name); + if (CC != -1) + return matchRegisterByNumber(CC, is64BitReg ? Mips::GPR64RegClassID + : Mips::GPR32RegClassID); + CC = matchFPURegisterName(Name); + // TODO: decide about fpu register class + if (CC != -1) + return matchRegisterByNumber(CC, isFP64() ? Mips::FGR64RegClassID + : Mips::FGR32RegClassID); + return matchMSA128RegisterName(Name); +} + +int MipsAsmParser::regKindToRegClass(int RegKind) { + + switch (RegKind) { + case MipsOperand::Kind_GPR32: + return Mips::GPR32RegClassID; + case MipsOperand::Kind_GPR64: + return Mips::GPR64RegClassID; + case MipsOperand::Kind_HWRegs: + return Mips::HWRegsRegClassID; + case MipsOperand::Kind_FGR32Regs: + return Mips::FGR32RegClassID; + case MipsOperand::Kind_FGRH32Regs: + return Mips::FGRH32RegClassID; + case MipsOperand::Kind_FGR64Regs: + return Mips::FGR64RegClassID; + case MipsOperand::Kind_AFGR64Regs: + return Mips::AFGR64RegClassID; + case MipsOperand::Kind_CCRRegs: + return Mips::CCRRegClassID; + case MipsOperand::Kind_ACC64DSP: + return Mips::ACC64DSPRegClassID; + case MipsOperand::Kind_FCCRegs: + return Mips::FCCRegClassID; + case MipsOperand::Kind_MSA128BRegs: + return Mips::MSA128BRegClassID; + case MipsOperand::Kind_MSA128HRegs: + return Mips::MSA128HRegClassID; + case MipsOperand::Kind_MSA128WRegs: + return Mips::MSA128WRegClassID; + case MipsOperand::Kind_MSA128DRegs: + return Mips::MSA128DRegClassID; + case MipsOperand::Kind_MSA128CtrlRegs: + return Mips::MSACtrlRegClassID; + default: + return -1; + } +} + +bool MipsAssemblerOptions::setATReg(unsigned Reg) { + if (Reg > 31) + return false; + + aTReg = Reg; + return true; +} + +int MipsAsmParser::getATReg() { return Options.getATRegNum(); } + +unsigned MipsAsmParser::getReg(int RC, int RegNo) { + return *(getContext().getRegisterInfo()->getRegClass(RC).begin() + RegNo); +} + +int MipsAsmParser::matchRegisterByNumber(unsigned RegNum, unsigned RegClass) { + if (RegNum > + getContext().getRegisterInfo()->getRegClass(RegClass).getNumRegs()) + return -1; + + return getReg(RegClass, RegNum); +} + +int MipsAsmParser::tryParseRegister(bool is64BitReg) { + const AsmToken &Tok = Parser.getTok(); + int RegNum = -1; + + if (Tok.is(AsmToken::Identifier)) { + std::string lowerCase = Tok.getString().lower(); + RegNum = matchRegisterName(lowerCase, is64BitReg); + } else if (Tok.is(AsmToken::Integer)) + RegNum = matchRegisterByNumber(static_cast<unsigned>(Tok.getIntVal()), + is64BitReg ? Mips::GPR64RegClassID + : Mips::GPR32RegClassID); + return RegNum; +} + +bool MipsAsmParser::tryParseRegisterOperand( + SmallVectorImpl<MCParsedAsmOperand *> &Operands, bool is64BitReg) { + + SMLoc S = Parser.getTok().getLoc(); + int RegNo = -1; + + RegNo = tryParseRegister(is64BitReg); + if (RegNo == -1) + return true; + + Operands.push_back( + MipsOperand::CreateReg(RegNo, S, Parser.getTok().getLoc())); + Parser.Lex(); // Eat register token. + return false; +} + +bool +MipsAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand *> &Operands, + StringRef Mnemonic) { + // Check if the current operand has a custom associated parser, if so, try to + // custom parse the operand, or fallback to the general approach. + OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic); + if (ResTy == MatchOperand_Success) + return false; + // If there wasn't a custom match, try the generic matcher below. Otherwise, + // there was a match, but an error occurred, in which case, just return that + // the operand parsing failed. + if (ResTy == MatchOperand_ParseFail) + return true; + + switch (getLexer().getKind()) { + default: + Error(Parser.getTok().getLoc(), "unexpected token in operand"); + return true; + case AsmToken::Dollar: { + // Parse the register. + SMLoc S = Parser.getTok().getLoc(); + Parser.Lex(); // Eat dollar token. + // Parse the register operand. + if (!tryParseRegisterOperand(Operands, isMips64())) { + if (getLexer().is(AsmToken::LParen)) { + // Check if it is indexed addressing operand. + Operands.push_back(MipsOperand::CreateToken("(", S)); + Parser.Lex(); // Eat the parenthesis. + if (getLexer().isNot(AsmToken::Dollar)) + return true; + + Parser.Lex(); // Eat the dollar + if (tryParseRegisterOperand(Operands, isMips64())) + return true; + + if (!getLexer().is(AsmToken::RParen)) + return true; + + S = Parser.getTok().getLoc(); + Operands.push_back(MipsOperand::CreateToken(")", S)); + Parser.Lex(); + } + return false; + } + // Maybe it is a symbol reference. + StringRef Identifier; + if (Parser.parseIdentifier(Identifier)) + return true; + + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + MCSymbol *Sym = getContext().GetOrCreateSymbol("$" + Identifier); + // Otherwise create a symbol reference. + const MCExpr *Res = + MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None, getContext()); + + Operands.push_back(MipsOperand::CreateImm(Res, S, E)); + return false; + } + case AsmToken::Identifier: + // For instruction aliases like "bc1f $Label" dedicated parser will + // eat the '$' sign before failing. So in order to look for appropriate + // label we must check first if we have already consumed '$'. + if (hasConsumedDollar) { + hasConsumedDollar = false; + SMLoc S = Parser.getTok().getLoc(); + StringRef Identifier; + if (Parser.parseIdentifier(Identifier)) + return true; + SMLoc E = + SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + MCSymbol *Sym = getContext().GetOrCreateSymbol("$" + Identifier); + // Create a symbol reference. + const MCExpr *Res = + MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None, getContext()); + + Operands.push_back(MipsOperand::CreateImm(Res, S, E)); + return false; + } + // Look for the existing symbol, we should check if + // we need to assigne the propper RegisterKind. + if (searchSymbolAlias(Operands, MipsOperand::Kind_None)) + return false; + // Else drop to expression parsing. + case AsmToken::LParen: + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Integer: + case AsmToken::String: { + // Quoted label names. + const MCExpr *IdVal; + SMLoc S = Parser.getTok().getLoc(); + if (getParser().parseExpression(IdVal)) + return true; + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(MipsOperand::CreateImm(IdVal, S, E)); + return false; + } + case AsmToken::Percent: { + // It is a symbol reference or constant expression. + const MCExpr *IdVal; + SMLoc S = Parser.getTok().getLoc(); // Start location of the operand. + if (parseRelocOperand(IdVal)) + return true; + + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + Operands.push_back(MipsOperand::CreateImm(IdVal, S, E)); + return false; + } // case AsmToken::Percent + } // switch(getLexer().getKind()) + return true; +} + +const MCExpr *MipsAsmParser::evaluateRelocExpr(const MCExpr *Expr, + StringRef RelocStr) { + const MCExpr *Res; + // Check the type of the expression. + if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Expr)) { + // It's a constant, evaluate lo or hi value. + if (RelocStr == "lo") { + short Val = MCE->getValue(); + Res = MCConstantExpr::Create(Val, getContext()); + } else if (RelocStr == "hi") { + int Val = MCE->getValue(); + int LoSign = Val & 0x8000; + Val = (Val & 0xffff0000) >> 16; + // Lower part is treated as a signed int, so if it is negative + // we must add 1 to the hi part to compensate. + if (LoSign) + Val++; + Res = MCConstantExpr::Create(Val, getContext()); + } else { + llvm_unreachable("Invalid RelocStr value"); + } + return Res; + } + + if (const MCSymbolRefExpr *MSRE = dyn_cast<MCSymbolRefExpr>(Expr)) { + // It's a symbol, create a symbolic expression from the symbol. + StringRef Symbol = MSRE->getSymbol().getName(); + MCSymbolRefExpr::VariantKind VK = getVariantKind(RelocStr); + Res = MCSymbolRefExpr::Create(Symbol, VK, getContext()); + return Res; + } + + if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr)) { + const MCExpr *LExp = evaluateRelocExpr(BE->getLHS(), RelocStr); + const MCExpr *RExp = evaluateRelocExpr(BE->getRHS(), RelocStr); + Res = MCBinaryExpr::Create(BE->getOpcode(), LExp, RExp, getContext()); + return Res; + } + + if (const MCUnaryExpr *UN = dyn_cast<MCUnaryExpr>(Expr)) { + const MCExpr *UnExp = evaluateRelocExpr(UN->getSubExpr(), RelocStr); + Res = MCUnaryExpr::Create(UN->getOpcode(), UnExp, getContext()); + return Res; + } + // Just return the original expression. + return Expr; +} + +bool MipsAsmParser::isEvaluated(const MCExpr *Expr) { + + switch (Expr->getKind()) { + case MCExpr::Constant: + return true; + case MCExpr::SymbolRef: + return (cast<MCSymbolRefExpr>(Expr)->getKind() != MCSymbolRefExpr::VK_None); + case MCExpr::Binary: + if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr)) { + if (!isEvaluated(BE->getLHS())) + return false; + return isEvaluated(BE->getRHS()); + } + case MCExpr::Unary: + return isEvaluated(cast<MCUnaryExpr>(Expr)->getSubExpr()); + default: + return false; + } + return false; +} + +bool MipsAsmParser::parseRelocOperand(const MCExpr *&Res) { + Parser.Lex(); // Eat the % token. + const AsmToken &Tok = Parser.getTok(); // Get next token, operation. + if (Tok.isNot(AsmToken::Identifier)) + return true; + + std::string Str = Tok.getIdentifier().str(); + + Parser.Lex(); // Eat the identifier. + // Now make an expression from the rest of the operand. + const MCExpr *IdVal; + SMLoc EndLoc; + + if (getLexer().getKind() == AsmToken::LParen) { + while (1) { + Parser.Lex(); // Eat the '(' token. + if (getLexer().getKind() == AsmToken::Percent) { + Parser.Lex(); // Eat the % token. + const AsmToken &nextTok = Parser.getTok(); + if (nextTok.isNot(AsmToken::Identifier)) + return true; + Str += "(%"; + Str += nextTok.getIdentifier(); + Parser.Lex(); // Eat the identifier. + if (getLexer().getKind() != AsmToken::LParen) + return true; + } else + break; + } + if (getParser().parseParenExpression(IdVal, EndLoc)) + return true; + + while (getLexer().getKind() == AsmToken::RParen) + Parser.Lex(); // Eat the ')' token. + + } else + return true; // Parenthesis must follow the relocation operand. + + Res = evaluateRelocExpr(IdVal, Str); + return false; +} + +bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) { + StartLoc = Parser.getTok().getLoc(); + RegNo = tryParseRegister(isMips64()); + EndLoc = Parser.getTok().getLoc(); + return (RegNo == (unsigned)-1); +} + +bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) { + SMLoc S; + bool Result = true; + + while (getLexer().getKind() == AsmToken::LParen) + Parser.Lex(); + + switch (getLexer().getKind()) { + default: + return true; + case AsmToken::Identifier: + case AsmToken::LParen: + case AsmToken::Integer: + case AsmToken::Minus: + case AsmToken::Plus: + if (isParenExpr) + Result = getParser().parseParenExpression(Res, S); + else + Result = (getParser().parseExpression(Res)); + while (getLexer().getKind() == AsmToken::RParen) + Parser.Lex(); + break; + case AsmToken::Percent: + Result = parseRelocOperand(Res); + } + return Result; +} + +MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMemOperand( + SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + + const MCExpr *IdVal = 0; + SMLoc S; + bool isParenExpr = false; + MipsAsmParser::OperandMatchResultTy Res = MatchOperand_NoMatch; + // First operand is the offset. + S = Parser.getTok().getLoc(); + + if (getLexer().getKind() == AsmToken::LParen) { + Parser.Lex(); + isParenExpr = true; + } + + if (getLexer().getKind() != AsmToken::Dollar) { + if (parseMemOffset(IdVal, isParenExpr)) + return MatchOperand_ParseFail; + + const AsmToken &Tok = Parser.getTok(); // Get the next token. + if (Tok.isNot(AsmToken::LParen)) { + MipsOperand *Mnemonic = static_cast<MipsOperand *>(Operands[0]); + if (Mnemonic->getToken() == "la") { + SMLoc E = + SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(MipsOperand::CreateImm(IdVal, S, E)); + return MatchOperand_Success; + } + if (Tok.is(AsmToken::EndOfStatement)) { + SMLoc E = + SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + // Zero register assumed, add a memory operand with ZERO as its base. + Operands.push_back(MipsOperand::CreateMem( + isMips64() ? Mips::ZERO_64 : Mips::ZERO, IdVal, S, E)); + return MatchOperand_Success; + } + Error(Parser.getTok().getLoc(), "'(' expected"); + return MatchOperand_ParseFail; + } + + Parser.Lex(); // Eat the '(' token. + } + + Res = parseRegs(Operands, isMips64() ? (int)MipsOperand::Kind_GPR64 + : (int)MipsOperand::Kind_GPR32); + if (Res != MatchOperand_Success) + return Res; + + if (Parser.getTok().isNot(AsmToken::RParen)) { + Error(Parser.getTok().getLoc(), "')' expected"); + return MatchOperand_ParseFail; + } + + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + + Parser.Lex(); // Eat the ')' token. + + if (IdVal == 0) + IdVal = MCConstantExpr::Create(0, getContext()); + + // Replace the register operand with the memory operand. + MipsOperand *op = static_cast<MipsOperand *>(Operands.back()); + int RegNo = op->getReg(); + // Remove the register from the operands. + Operands.pop_back(); + // Add the memory operand. + if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(IdVal)) { + int64_t Imm; + if (IdVal->EvaluateAsAbsolute(Imm)) + IdVal = MCConstantExpr::Create(Imm, getContext()); + else if (BE->getLHS()->getKind() != MCExpr::SymbolRef) + IdVal = MCBinaryExpr::Create(BE->getOpcode(), BE->getRHS(), BE->getLHS(), + getContext()); + } + + Operands.push_back(MipsOperand::CreateMem(RegNo, IdVal, S, E)); + delete op; + return MatchOperand_Success; +} + +bool MipsAsmParser::parsePtrReg(SmallVectorImpl<MCParsedAsmOperand *> &Operands, + int RegKind) { + // If the first token is not '$' we have an error. + if (Parser.getTok().isNot(AsmToken::Dollar)) + return false; + + SMLoc S = Parser.getTok().getLoc(); + Parser.Lex(); + AsmToken::TokenKind TkKind = getLexer().getKind(); + int Reg; + + if (TkKind == AsmToken::Integer) { + Reg = matchRegisterByNumber(Parser.getTok().getIntVal(), + regKindToRegClass(RegKind)); + if (Reg == -1) + return false; + } else if (TkKind == AsmToken::Identifier) { + if ((Reg = matchCPURegisterName(Parser.getTok().getString().lower())) == -1) + return false; + Reg = getReg(regKindToRegClass(RegKind), Reg); + } else { + return false; + } + + MipsOperand *Op = MipsOperand::CreatePtrReg(Reg, S, Parser.getTok().getLoc()); + Op->setRegKind((MipsOperand::RegisterKind)RegKind); + Operands.push_back(Op); + Parser.Lex(); + return true; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parsePtrReg(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + MipsOperand::RegisterKind RegKind = + isN64() ? MipsOperand::Kind_GPR64 : MipsOperand::Kind_GPR32; + + // Parse index register. + if (!parsePtrReg(Operands, RegKind)) + return MatchOperand_NoMatch; + + // Parse '('. + if (Parser.getTok().isNot(AsmToken::LParen)) + return MatchOperand_NoMatch; + + Operands.push_back(MipsOperand::CreateToken("(", getLexer().getLoc())); + Parser.Lex(); + + // Parse base register. + if (!parsePtrReg(Operands, RegKind)) + return MatchOperand_NoMatch; + + // Parse ')'. + if (Parser.getTok().isNot(AsmToken::RParen)) + return MatchOperand_NoMatch; + + Operands.push_back(MipsOperand::CreateToken(")", getLexer().getLoc())); + Parser.Lex(); + + return MatchOperand_Success; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands, + int RegKind) { + MipsOperand::RegisterKind Kind = (MipsOperand::RegisterKind)RegKind; + if (getLexer().getKind() == AsmToken::Identifier && !hasConsumedDollar) { + if (searchSymbolAlias(Operands, Kind)) + return MatchOperand_Success; + return MatchOperand_NoMatch; + } + SMLoc S = Parser.getTok().getLoc(); + // If the first token is not '$', we have an error. + if (Parser.getTok().isNot(AsmToken::Dollar) && !hasConsumedDollar) + return MatchOperand_NoMatch; + if (!hasConsumedDollar) { + Parser.Lex(); // Eat the '$' + hasConsumedDollar = true; + } + if (getLexer().getKind() == AsmToken::Identifier) { + int RegNum = -1; + std::string RegName = Parser.getTok().getString().lower(); + // Match register by name + switch (RegKind) { + case MipsOperand::Kind_GPR32: + case MipsOperand::Kind_GPR64: + RegNum = matchCPURegisterName(RegName); + break; + case MipsOperand::Kind_AFGR64Regs: + case MipsOperand::Kind_FGR64Regs: + case MipsOperand::Kind_FGR32Regs: + case MipsOperand::Kind_FGRH32Regs: + RegNum = matchFPURegisterName(RegName); + if (RegKind == MipsOperand::Kind_AFGR64Regs) + RegNum /= 2; + else if (RegKind == MipsOperand::Kind_FGRH32Regs && !isFP64()) + if (RegNum != -1 && RegNum % 2 != 0) + Warning(S, "Float register should be even."); + break; + case MipsOperand::Kind_FCCRegs: + RegNum = matchFCCRegisterName(RegName); + break; + case MipsOperand::Kind_ACC64DSP: + RegNum = matchACRegisterName(RegName); + break; + default: + break; // No match, value is set to -1. + } + // No match found, return _NoMatch to give a chance to other round. + if (RegNum < 0) + return MatchOperand_NoMatch; + + int RegVal = getReg(regKindToRegClass(Kind), RegNum); + if (RegVal == -1) + return MatchOperand_NoMatch; + + MipsOperand *Op = + MipsOperand::CreateReg(RegVal, S, Parser.getTok().getLoc()); + Op->setRegKind(Kind); + Operands.push_back(Op); + hasConsumedDollar = false; + Parser.Lex(); // Eat the register name. + return MatchOperand_Success; + } else if (getLexer().getKind() == AsmToken::Integer) { + unsigned RegNum = Parser.getTok().getIntVal(); + if (Kind == MipsOperand::Kind_HWRegs) { + if (RegNum != 29) + return MatchOperand_NoMatch; + // Only hwreg 29 is supported, found at index 0. + RegNum = 0; + } + int Reg = matchRegisterByNumber(RegNum, regKindToRegClass(Kind)); + if (Reg == -1) + return MatchOperand_NoMatch; + MipsOperand *Op = MipsOperand::CreateReg(Reg, S, Parser.getTok().getLoc()); + Op->setRegKind(Kind); + Operands.push_back(Op); + hasConsumedDollar = false; + Parser.Lex(); // Eat the register number. + if ((RegKind == MipsOperand::Kind_GPR32) && + (getLexer().is(AsmToken::LParen))) { + // Check if it is indexed addressing operand. + Operands.push_back(MipsOperand::CreateToken("(", getLexer().getLoc())); + Parser.Lex(); // Eat the parenthesis. + if (parseRegs(Operands, RegKind) != MatchOperand_Success) + return MatchOperand_NoMatch; + if (getLexer().isNot(AsmToken::RParen)) + return MatchOperand_NoMatch; + Operands.push_back(MipsOperand::CreateToken(")", getLexer().getLoc())); + Parser.Lex(); + } + return MatchOperand_Success; + } + return MatchOperand_NoMatch; +} + +bool MipsAsmParser::validateMSAIndex(int Val, int RegKind) { + MipsOperand::RegisterKind Kind = (MipsOperand::RegisterKind)RegKind; + + if (Val < 0) + return false; + + switch (Kind) { + default: + return false; + case MipsOperand::Kind_MSA128BRegs: + return Val < 16; + case MipsOperand::Kind_MSA128HRegs: + return Val < 8; + case MipsOperand::Kind_MSA128WRegs: + return Val < 4; + case MipsOperand::Kind_MSA128DRegs: + return Val < 2; + } +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseMSARegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands, + int RegKind) { + MipsOperand::RegisterKind Kind = (MipsOperand::RegisterKind)RegKind; + SMLoc S = Parser.getTok().getLoc(); + std::string RegName; + + if (Parser.getTok().isNot(AsmToken::Dollar)) + return MatchOperand_NoMatch; + + switch (RegKind) { + default: + return MatchOperand_ParseFail; + case MipsOperand::Kind_MSA128BRegs: + case MipsOperand::Kind_MSA128HRegs: + case MipsOperand::Kind_MSA128WRegs: + case MipsOperand::Kind_MSA128DRegs: + break; + } + + Parser.Lex(); // Eat the '$'. + if (getLexer().getKind() == AsmToken::Identifier) + RegName = Parser.getTok().getString().lower(); + else + return MatchOperand_ParseFail; + + int RegNum = matchMSA128RegisterName(RegName); + + if (RegNum < 0 || RegNum > 31) + return MatchOperand_ParseFail; + + int RegVal = getReg(regKindToRegClass(Kind), RegNum); + if (RegVal == -1) + return MatchOperand_ParseFail; + + MipsOperand *Op = MipsOperand::CreateReg(RegVal, S, Parser.getTok().getLoc()); + Op->setRegKind(Kind); + Operands.push_back(Op); + + Parser.Lex(); // Eat the register identifier. + + // MSA registers may be suffixed with an index in the form of: + // 1) Immediate expression. + // 2) General Purpose Register. + // Examples: + // 1) copy_s.b $29,$w0[0] + // 2) sld.b $w0,$w1[$1] + + if (Parser.getTok().isNot(AsmToken::LBrac)) + return MatchOperand_Success; + + MipsOperand *Mnemonic = static_cast<MipsOperand *>(Operands[0]); + + Operands.push_back(MipsOperand::CreateToken("[", Parser.getTok().getLoc())); + Parser.Lex(); // Parse the '[' token. + + if (Parser.getTok().is(AsmToken::Dollar)) { + // This must be a GPR. + MipsOperand *RegOp; + SMLoc VIdx = Parser.getTok().getLoc(); + Parser.Lex(); // Parse the '$' token. + + // GPR have aliases and we must account for that. Example: $30 == $fp + if (getLexer().getKind() == AsmToken::Integer) { + unsigned RegNum = Parser.getTok().getIntVal(); + int Reg = matchRegisterByNumber( + RegNum, regKindToRegClass(MipsOperand::Kind_GPR32)); + if (Reg == -1) { + Error(VIdx, "invalid general purpose register"); + return MatchOperand_ParseFail; + } + + RegOp = MipsOperand::CreateReg(Reg, VIdx, Parser.getTok().getLoc()); + } else if (getLexer().getKind() == AsmToken::Identifier) { + int RegNum = -1; + std::string RegName = Parser.getTok().getString().lower(); + + RegNum = matchCPURegisterName(RegName); + if (RegNum == -1) { + Error(VIdx, "general purpose register expected"); + return MatchOperand_ParseFail; + } + RegNum = getReg(regKindToRegClass(MipsOperand::Kind_GPR32), RegNum); + RegOp = MipsOperand::CreateReg(RegNum, VIdx, Parser.getTok().getLoc()); + } else + return MatchOperand_ParseFail; + + RegOp->setRegKind(MipsOperand::Kind_GPR32); + Operands.push_back(RegOp); + Parser.Lex(); // Eat the register identifier. + + if (Parser.getTok().isNot(AsmToken::RBrac)) + return MatchOperand_ParseFail; + + Operands.push_back(MipsOperand::CreateToken("]", Parser.getTok().getLoc())); + Parser.Lex(); // Parse the ']' token. + + return MatchOperand_Success; + } + + // The index must be a constant expression then. + SMLoc VIdx = Parser.getTok().getLoc(); + const MCExpr *ImmVal; + + if (getParser().parseExpression(ImmVal)) + return MatchOperand_ParseFail; + + const MCConstantExpr *expr = dyn_cast<MCConstantExpr>(ImmVal); + if (!expr || !validateMSAIndex((int)expr->getValue(), Kind)) { + Error(VIdx, "invalid immediate value"); + return MatchOperand_ParseFail; + } + + SMLoc E = Parser.getTok().getEndLoc(); + + if (Parser.getTok().isNot(AsmToken::RBrac)) + return MatchOperand_ParseFail; + + bool insve = + Mnemonic->getToken() == "insve.b" || Mnemonic->getToken() == "insve.h" || + Mnemonic->getToken() == "insve.w" || Mnemonic->getToken() == "insve.d"; + + // The second vector index of insve instructions is always 0. + if (insve && Operands.size() > 6) { + if (expr->getValue() != 0) { + Error(VIdx, "immediate value must be 0"); + return MatchOperand_ParseFail; + } + Operands.push_back(MipsOperand::CreateToken("0", VIdx)); + } else + Operands.push_back(MipsOperand::CreateImm(expr, VIdx, E)); + + Operands.push_back(MipsOperand::CreateToken("]", Parser.getTok().getLoc())); + + Parser.Lex(); // Parse the ']' token. + + return MatchOperand_Success; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseMSACtrlRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands, + int RegKind) { + MipsOperand::RegisterKind Kind = (MipsOperand::RegisterKind)RegKind; + + if (Kind != MipsOperand::Kind_MSA128CtrlRegs) + return MatchOperand_NoMatch; + + if (Parser.getTok().isNot(AsmToken::Dollar)) + return MatchOperand_ParseFail; + + SMLoc S = Parser.getTok().getLoc(); + + Parser.Lex(); // Eat the '$' symbol. + + int RegNum = -1; + if (getLexer().getKind() == AsmToken::Identifier) + RegNum = matchMSA128CtrlRegisterName(Parser.getTok().getString().lower()); + else if (getLexer().getKind() == AsmToken::Integer) + RegNum = Parser.getTok().getIntVal(); + else + return MatchOperand_ParseFail; + + if (RegNum < 0 || RegNum > 7) + return MatchOperand_ParseFail; + + int RegVal = getReg(regKindToRegClass(Kind), RegNum); + if (RegVal == -1) + return MatchOperand_ParseFail; + + MipsOperand *RegOp = + MipsOperand::CreateReg(RegVal, S, Parser.getTok().getLoc()); + RegOp->setRegKind(MipsOperand::Kind_MSA128CtrlRegs); + Operands.push_back(RegOp); + Parser.Lex(); // Eat the register identifier. + + return MatchOperand_Success; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseGPR64(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + + if (!isMips64()) + return MatchOperand_NoMatch; + return parseRegs(Operands, (int)MipsOperand::Kind_GPR64); +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseGPR32(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + return parseRegs(Operands, (int)MipsOperand::Kind_GPR32); +} + +MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseAFGR64Regs( + SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + + if (isFP64()) + return MatchOperand_NoMatch; + return parseRegs(Operands, (int)MipsOperand::Kind_AFGR64Regs); +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseFGR64Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + if (!isFP64()) + return MatchOperand_NoMatch; + return parseRegs(Operands, (int)MipsOperand::Kind_FGR64Regs); +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseFGR32Regs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + return parseRegs(Operands, (int)MipsOperand::Kind_FGR32Regs); +} + +MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseFGRH32Regs( + SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + return parseRegs(Operands, (int)MipsOperand::Kind_FGRH32Regs); +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseFCCRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + return parseRegs(Operands, (int)MipsOperand::Kind_FCCRegs); +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseACC64DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + return parseRegs(Operands, (int)MipsOperand::Kind_ACC64DSP); +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseLO32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + // If the first token is not '$' we have an error. + if (Parser.getTok().isNot(AsmToken::Dollar)) + return MatchOperand_NoMatch; + + SMLoc S = Parser.getTok().getLoc(); + Parser.Lex(); // Eat the '$' + + const AsmToken &Tok = Parser.getTok(); // Get next token. + + if (Tok.isNot(AsmToken::Identifier)) + return MatchOperand_NoMatch; + + if (!Tok.getIdentifier().startswith("ac")) + return MatchOperand_NoMatch; + + StringRef NumString = Tok.getIdentifier().substr(2); + + unsigned IntVal; + if (NumString.getAsInteger(10, IntVal)) + return MatchOperand_NoMatch; + + unsigned Reg = matchRegisterByNumber(IntVal, Mips::LO32DSPRegClassID); + + MipsOperand *Op = MipsOperand::CreateReg(Reg, S, Parser.getTok().getLoc()); + Op->setRegKind(MipsOperand::Kind_LO32DSP); + Operands.push_back(Op); + + Parser.Lex(); // Eat the register number. + return MatchOperand_Success; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseHI32DSP(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + // If the first token is not '$' we have an error. + if (Parser.getTok().isNot(AsmToken::Dollar)) + return MatchOperand_NoMatch; + + SMLoc S = Parser.getTok().getLoc(); + Parser.Lex(); // Eat the '$' + + const AsmToken &Tok = Parser.getTok(); // Get next token. + + if (Tok.isNot(AsmToken::Identifier)) + return MatchOperand_NoMatch; + + if (!Tok.getIdentifier().startswith("ac")) + return MatchOperand_NoMatch; + + StringRef NumString = Tok.getIdentifier().substr(2); + + unsigned IntVal; + if (NumString.getAsInteger(10, IntVal)) + return MatchOperand_NoMatch; + + unsigned Reg = matchRegisterByNumber(IntVal, Mips::HI32DSPRegClassID); + + MipsOperand *Op = MipsOperand::CreateReg(Reg, S, Parser.getTok().getLoc()); + Op->setRegKind(MipsOperand::Kind_HI32DSP); + Operands.push_back(Op); + + Parser.Lex(); // Eat the register number. + return MatchOperand_Success; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseCOP2(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + // If the first token is not '$' we have an error. + if (Parser.getTok().isNot(AsmToken::Dollar)) + return MatchOperand_NoMatch; + + SMLoc S = Parser.getTok().getLoc(); + Parser.Lex(); // Eat the '$' + + const AsmToken &Tok = Parser.getTok(); // Get next token. + + if (Tok.isNot(AsmToken::Integer)) + return MatchOperand_NoMatch; + + unsigned IntVal = Tok.getIntVal(); + + unsigned Reg = matchRegisterByNumber(IntVal, Mips::COP2RegClassID); + + MipsOperand *Op = MipsOperand::CreateReg(Reg, S, Parser.getTok().getLoc()); + Op->setRegKind(MipsOperand::Kind_COP2); + Operands.push_back(Op); + + Parser.Lex(); // Eat the register number. + return MatchOperand_Success; +} + +MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128BRegs( + SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128BRegs); +} + +MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128HRegs( + SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128HRegs); +} + +MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128WRegs( + SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128WRegs); +} + +MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128DRegs( + SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + return parseMSARegs(Operands, (int)MipsOperand::Kind_MSA128DRegs); +} + +MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseMSA128CtrlRegs( + SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + return parseMSACtrlRegs(Operands, (int)MipsOperand::Kind_MSA128CtrlRegs); +} + +bool MipsAsmParser::searchSymbolAlias( + SmallVectorImpl<MCParsedAsmOperand *> &Operands, unsigned RegKind) { + + MCSymbol *Sym = getContext().LookupSymbol(Parser.getTok().getIdentifier()); + if (Sym) { + SMLoc S = Parser.getTok().getLoc(); + const MCExpr *Expr; + if (Sym->isVariable()) + Expr = Sym->getVariableValue(); + else + return false; + if (Expr->getKind() == MCExpr::SymbolRef) { + MipsOperand::RegisterKind Kind = (MipsOperand::RegisterKind)RegKind; + const MCSymbolRefExpr *Ref = static_cast<const MCSymbolRefExpr *>(Expr); + const StringRef DefSymbol = Ref->getSymbol().getName(); + if (DefSymbol.startswith("$")) { + int RegNum = -1; + APInt IntVal(32, -1); + if (!DefSymbol.substr(1).getAsInteger(10, IntVal)) + RegNum = matchRegisterByNumber(IntVal.getZExtValue(), + isMips64() ? Mips::GPR64RegClassID + : Mips::GPR32RegClassID); + else { + // Lookup for the register with the corresponding name. + switch (Kind) { + case MipsOperand::Kind_AFGR64Regs: + case MipsOperand::Kind_FGR64Regs: + RegNum = matchFPURegisterName(DefSymbol.substr(1)); + break; + case MipsOperand::Kind_FGR32Regs: + RegNum = matchFPURegisterName(DefSymbol.substr(1)); + break; + case MipsOperand::Kind_GPR64: + case MipsOperand::Kind_GPR32: + default: + RegNum = matchCPURegisterName(DefSymbol.substr(1)); + break; + } + if (RegNum > -1) + RegNum = getReg(regKindToRegClass(Kind), RegNum); + } + if (RegNum > -1) { + Parser.Lex(); + MipsOperand *op = + MipsOperand::CreateReg(RegNum, S, Parser.getTok().getLoc()); + op->setRegKind(Kind); + Operands.push_back(op); + return true; + } + } + } else if (Expr->getKind() == MCExpr::Constant) { + Parser.Lex(); + const MCConstantExpr *Const = static_cast<const MCConstantExpr *>(Expr); + MipsOperand *op = + MipsOperand::CreateImm(Const, S, Parser.getTok().getLoc()); + Operands.push_back(op); + return true; + } + } + return false; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseHWRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + return parseRegs(Operands, (int)MipsOperand::Kind_HWRegs); +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseCCRRegs(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + return parseRegs(Operands, (int)MipsOperand::Kind_CCRRegs); +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseInvNum(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + const MCExpr *IdVal; + // If the first token is '$' we may have register operand. + if (Parser.getTok().is(AsmToken::Dollar)) + return MatchOperand_NoMatch; + SMLoc S = Parser.getTok().getLoc(); + if (getParser().parseExpression(IdVal)) + return MatchOperand_ParseFail; + const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(IdVal); + assert(MCE && "Unexpected MCExpr type."); + int64_t Val = MCE->getValue(); + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(MipsOperand::CreateImm( + MCConstantExpr::Create(0 - Val, getContext()), S, E)); + return MatchOperand_Success; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseLSAImm(SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + case AsmToken::LParen: + case AsmToken::Plus: + case AsmToken::Minus: + case AsmToken::Integer: + break; + } + + const MCExpr *Expr; + SMLoc S = Parser.getTok().getLoc(); + + if (getParser().parseExpression(Expr)) + return MatchOperand_ParseFail; + + int64_t Val; + if (!Expr->EvaluateAsAbsolute(Val)) { + Error(S, "expected immediate value"); + return MatchOperand_ParseFail; + } + + // The LSA instruction allows a 2-bit unsigned immediate. For this reason + // and because the CPU always adds one to the immediate field, the allowed + // range becomes 1..4. We'll only check the range here and will deal + // with the addition/subtraction when actually decoding/encoding + // the instruction. + if (Val < 1 || Val > 4) { + Error(S, "immediate not in range (1..4)"); + return MatchOperand_ParseFail; + } + + Operands.push_back(MipsOperand::CreateLSAImm(Expr, S, + Parser.getTok().getLoc())); + return MatchOperand_Success; +} + +MCSymbolRefExpr::VariantKind MipsAsmParser::getVariantKind(StringRef Symbol) { + + MCSymbolRefExpr::VariantKind VK = + StringSwitch<MCSymbolRefExpr::VariantKind>(Symbol) + .Case("hi", MCSymbolRefExpr::VK_Mips_ABS_HI) + .Case("lo", MCSymbolRefExpr::VK_Mips_ABS_LO) + .Case("gp_rel", MCSymbolRefExpr::VK_Mips_GPREL) + .Case("call16", MCSymbolRefExpr::VK_Mips_GOT_CALL) + .Case("got", MCSymbolRefExpr::VK_Mips_GOT) + .Case("tlsgd", MCSymbolRefExpr::VK_Mips_TLSGD) + .Case("tlsldm", MCSymbolRefExpr::VK_Mips_TLSLDM) + .Case("dtprel_hi", MCSymbolRefExpr::VK_Mips_DTPREL_HI) + .Case("dtprel_lo", MCSymbolRefExpr::VK_Mips_DTPREL_LO) + .Case("gottprel", MCSymbolRefExpr::VK_Mips_GOTTPREL) + .Case("tprel_hi", MCSymbolRefExpr::VK_Mips_TPREL_HI) + .Case("tprel_lo", MCSymbolRefExpr::VK_Mips_TPREL_LO) + .Case("got_disp", MCSymbolRefExpr::VK_Mips_GOT_DISP) + .Case("got_page", MCSymbolRefExpr::VK_Mips_GOT_PAGE) + .Case("got_ofst", MCSymbolRefExpr::VK_Mips_GOT_OFST) + .Case("hi(%neg(%gp_rel", MCSymbolRefExpr::VK_Mips_GPOFF_HI) + .Case("lo(%neg(%gp_rel", MCSymbolRefExpr::VK_Mips_GPOFF_LO) + .Default(MCSymbolRefExpr::VK_None); + + return VK; +} + +bool MipsAsmParser::ParseInstruction( + ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, + SmallVectorImpl<MCParsedAsmOperand *> &Operands) { + // Check if we have valid mnemonic + if (!mnemonicIsValid(Name, 0)) { + Parser.eatToEndOfStatement(); + return Error(NameLoc, "Unknown instruction"); + } + // First operand in MCInst is instruction mnemonic. + Operands.push_back(MipsOperand::CreateToken(Name, NameLoc)); + + // Read the remaining operands. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + // Read the first operand. + if (ParseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + + while (getLexer().is(AsmToken::Comma)) { + Parser.Lex(); // Eat the comma. + // Parse and remember the operand. + if (ParseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + } + } + if (getLexer().isNot(AsmToken::EndOfStatement)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::reportParseError(StringRef ErrorMsg) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, ErrorMsg); +} + +bool MipsAsmParser::parseSetNoAtDirective() { + // Line should look like: ".set noat". + // set at reg to 0. + Options.setATReg(0); + // eat noat + Parser.Lex(); + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token in statement"); + return false; + } + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetAtDirective() { + // Line can be .set at - defaults to $1 + // or .set at=$reg + int AtRegNo; + getParser().Lex(); + if (getLexer().is(AsmToken::EndOfStatement)) { + Options.setATReg(1); + Parser.Lex(); // Consume the EndOfStatement. + return false; + } else if (getLexer().is(AsmToken::Equal)) { + getParser().Lex(); // Eat the '='. + if (getLexer().isNot(AsmToken::Dollar)) { + reportParseError("unexpected token in statement"); + return false; + } + Parser.Lex(); // Eat the '$'. + const AsmToken &Reg = Parser.getTok(); + if (Reg.is(AsmToken::Identifier)) { + AtRegNo = matchCPURegisterName(Reg.getIdentifier()); + } else if (Reg.is(AsmToken::Integer)) { + AtRegNo = Reg.getIntVal(); + } else { + reportParseError("unexpected token in statement"); + return false; + } + + if (AtRegNo < 1 || AtRegNo > 31) { + reportParseError("unexpected token in statement"); + return false; + } + + if (!Options.setATReg(AtRegNo)) { + reportParseError("unexpected token in statement"); + return false; + } + getParser().Lex(); // Eat the register. + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token in statement"); + return false; + } + Parser.Lex(); // Consume the EndOfStatement. + return false; + } else { + reportParseError("unexpected token in statement"); + return false; + } +} + +bool MipsAsmParser::parseSetReorderDirective() { + Parser.Lex(); + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token in statement"); + return false; + } + Options.setReorder(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetNoReorderDirective() { + Parser.Lex(); + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token in statement"); + return false; + } + Options.setNoreorder(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetMacroDirective() { + Parser.Lex(); + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token in statement"); + return false; + } + Options.setMacro(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetNoMacroDirective() { + Parser.Lex(); + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("`noreorder' must be set before `nomacro'"); + return false; + } + if (Options.isReorder()) { + reportParseError("`noreorder' must be set before `nomacro'"); + return false; + } + Options.setNomacro(); + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool MipsAsmParser::parseSetAssignment() { + StringRef Name; + const MCExpr *Value; + + if (Parser.parseIdentifier(Name)) + reportParseError("expected identifier after .set"); + + if (getLexer().isNot(AsmToken::Comma)) + return reportParseError("unexpected token in .set directive"); + Lex(); // Eat comma + + if (getLexer().is(AsmToken::Dollar)) { + MCSymbol *Symbol; + SMLoc DollarLoc = getLexer().getLoc(); + // Consume the dollar sign, and check for a following identifier. + Parser.Lex(); + // We have a '$' followed by something, make sure they are adjacent. + if (DollarLoc.getPointer() + 1 != getTok().getLoc().getPointer()) + return true; + StringRef Res = + StringRef(DollarLoc.getPointer(), + getTok().getEndLoc().getPointer() - DollarLoc.getPointer()); + Symbol = getContext().GetOrCreateSymbol(Res); + Parser.Lex(); + Value = + MCSymbolRefExpr::Create(Symbol, MCSymbolRefExpr::VK_None, getContext()); + } else if (Parser.parseExpression(Value)) + return reportParseError("expected valid expression after comma"); + + // Check if the Name already exists as a symbol. + MCSymbol *Sym = getContext().LookupSymbol(Name); + if (Sym) + return reportParseError("symbol already defined"); + Sym = getContext().GetOrCreateSymbol(Name); + Sym->setVariableValue(Value); + + return false; +} + +bool MipsAsmParser::parseDirectiveSet() { + + // Get the next token. + const AsmToken &Tok = Parser.getTok(); + + if (Tok.getString() == "noat") { + return parseSetNoAtDirective(); + } else if (Tok.getString() == "at") { + return parseSetAtDirective(); + } else if (Tok.getString() == "reorder") { + return parseSetReorderDirective(); + } else if (Tok.getString() == "noreorder") { + return parseSetNoReorderDirective(); + } else if (Tok.getString() == "macro") { + return parseSetMacroDirective(); + } else if (Tok.getString() == "nomacro") { + return parseSetNoMacroDirective(); + } else if (Tok.getString() == "nomips16") { + // Ignore this directive for now. + Parser.eatToEndOfStatement(); + return false; + } else if (Tok.getString() == "nomicromips") { + // Ignore this directive for now. + Parser.eatToEndOfStatement(); + return false; + } else { + // It is just an identifier, look for an assignment. + parseSetAssignment(); + return false; + } + + return true; +} + +bool MipsAsmParser::parseDirectiveMipsHackStocg() { + MCAsmParser &Parser = getParser(); + StringRef Name; + if (Parser.parseIdentifier(Name)) + reportParseError("expected identifier"); + + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token"); + Lex(); + + int64_t Flags = 0; + if (Parser.parseAbsoluteExpression(Flags)) + return TokError("unexpected token"); + + getTargetStreamer().emitMipsHackSTOCG(Sym, Flags); + return false; +} + +bool MipsAsmParser::parseDirectiveMipsHackELFFlags() { + int64_t Flags = 0; + if (Parser.parseAbsoluteExpression(Flags)) + return TokError("unexpected token"); + + getTargetStreamer().emitMipsHackELFFlags(Flags); + return false; +} + +/// parseDirectiveWord +/// ::= .word [ expression (, expression)* ] +bool MipsAsmParser::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); + + 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; +} + +/// parseDirectiveGpWord +/// ::= .gpword local_sym +bool MipsAsmParser::parseDirectiveGpWord() { + const MCExpr *Value; + // EmitGPRel32Value requires an expression, so we are using base class + // method to evaluate the expression. + if (getParser().parseExpression(Value)) + return true; + getParser().getStreamer().EmitGPRel32Value(Value); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), "unexpected token in directive"); + Parser.Lex(); // Eat EndOfStatement token. + return false; +} + +bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { + + StringRef IDVal = DirectiveID.getString(); + + if (IDVal == ".ent") { + // Ignore this directive for now. + Parser.Lex(); + return false; + } + + if (IDVal == ".end") { + // Ignore this directive for now. + Parser.Lex(); + return false; + } + + if (IDVal == ".frame") { + // Ignore this directive for now. + Parser.eatToEndOfStatement(); + return false; + } + + if (IDVal == ".set") { + return parseDirectiveSet(); + } + + if (IDVal == ".fmask") { + // Ignore this directive for now. + Parser.eatToEndOfStatement(); + return false; + } + + if (IDVal == ".mask") { + // Ignore this directive for now. + Parser.eatToEndOfStatement(); + return false; + } + + if (IDVal == ".gpword") { + // Ignore this directive for now. + parseDirectiveGpWord(); + return false; + } + + if (IDVal == ".word") { + parseDirectiveWord(4, DirectiveID.getLoc()); + return false; + } + + if (IDVal == ".mips_hack_stocg") + return parseDirectiveMipsHackStocg(); + + if (IDVal == ".mips_hack_elf_flags") + return parseDirectiveMipsHackELFFlags(); + + return true; +} + +extern "C" void LLVMInitializeMipsAsmParser() { + RegisterMCAsmParser<MipsAsmParser> X(TheMipsTarget); + RegisterMCAsmParser<MipsAsmParser> Y(TheMipselTarget); + RegisterMCAsmParser<MipsAsmParser> A(TheMips64Target); + RegisterMCAsmParser<MipsAsmParser> B(TheMips64elTarget); +} + +#define GET_REGISTER_MATCHER +#define GET_MATCHER_IMPLEMENTATION +#include "MipsGenAsmMatcher.inc" diff --git a/contrib/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp b/contrib/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp new file mode 100644 index 000000000000..60508a8c4fcb --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp @@ -0,0 +1,822 @@ +//===- MipsDisassembler.cpp - Disassembler for Mips -------------*- 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 Mips Disassembler. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "MipsRegisterInfo.h" +#include "MipsSubtarget.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCFixedLenDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +typedef MCDisassembler::DecodeStatus DecodeStatus; + +namespace { + +/// MipsDisassemblerBase - a disasembler class for Mips. +class MipsDisassemblerBase : public MCDisassembler { +public: + /// Constructor - Initializes the disassembler. + /// + MipsDisassemblerBase(const MCSubtargetInfo &STI, const MCRegisterInfo *Info, + bool bigEndian) : + MCDisassembler(STI), RegInfo(Info), + IsN64(STI.getFeatureBits() & Mips::FeatureN64), isBigEndian(bigEndian) {} + + virtual ~MipsDisassemblerBase() {} + + const MCRegisterInfo *getRegInfo() const { return RegInfo.get(); } + + bool isN64() const { return IsN64; } + +private: + OwningPtr<const MCRegisterInfo> RegInfo; + bool IsN64; +protected: + bool isBigEndian; +}; + +/// MipsDisassembler - a disasembler class for Mips32. +class MipsDisassembler : public MipsDisassemblerBase { + bool IsMicroMips; +public: + /// Constructor - Initializes the disassembler. + /// + MipsDisassembler(const MCSubtargetInfo &STI, const MCRegisterInfo *Info, + bool bigEndian) : + MipsDisassemblerBase(STI, Info, bigEndian) { + IsMicroMips = STI.getFeatureBits() & Mips::FeatureMicroMips; + } + + /// getInstruction - See MCDisassembler. + virtual DecodeStatus getInstruction(MCInst &instr, + uint64_t &size, + const MemoryObject ®ion, + uint64_t address, + raw_ostream &vStream, + raw_ostream &cStream) const; +}; + + +/// Mips64Disassembler - a disasembler class for Mips64. +class Mips64Disassembler : public MipsDisassemblerBase { +public: + /// Constructor - Initializes the disassembler. + /// + Mips64Disassembler(const MCSubtargetInfo &STI, const MCRegisterInfo *Info, + bool bigEndian) : + MipsDisassemblerBase(STI, Info, bigEndian) {} + + /// getInstruction - See MCDisassembler. + virtual DecodeStatus getInstruction(MCInst &instr, + uint64_t &size, + const MemoryObject ®ion, + uint64_t address, + raw_ostream &vStream, + raw_ostream &cStream) const; +}; + +} // end anonymous namespace + +// Forward declare these because the autogenerated code will reference them. +// Definitions are further down. +static DecodeStatus DecodeGPR64RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeCPU16RegsRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeGPR32RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodePtrRegisterClass(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeDSPRRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFGR64RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFGR32RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFGRH32RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeCCRRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFCCRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeHWRegsRegisterClass(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeAFGR64RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeACC64DSPRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeHI32DSPRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeLO32DSPRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMSA128BRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMSA128HRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMSA128WRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMSA128DRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMSACtrlRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeBranchTarget(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeJumpTarget(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +// DecodeBranchTargetMM - Decode microMIPS branch offset, which is +// shifted left by 1 bit. +static DecodeStatus DecodeBranchTargetMM(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder); + +// DecodeJumpTargetMM - Decode microMIPS jump target, which is +// shifted left by 1 bit. +static DecodeStatus DecodeJumpTargetMM(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMem(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMSA128Mem(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +static DecodeStatus DecodeMemMMImm12(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeMemMMImm16(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeFMem(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeSimm16(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +// Decode the immediate field of an LSA instruction which +// is off by one. +static DecodeStatus DecodeLSAImm(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeInsSize(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus DecodeExtSize(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder); + +namespace llvm { +extern Target TheMipselTarget, TheMipsTarget, TheMips64Target, + TheMips64elTarget; +} + +static MCDisassembler *createMipsDisassembler( + const Target &T, + const MCSubtargetInfo &STI) { + return new MipsDisassembler(STI, T.createMCRegInfo(""), true); +} + +static MCDisassembler *createMipselDisassembler( + const Target &T, + const MCSubtargetInfo &STI) { + return new MipsDisassembler(STI, T.createMCRegInfo(""), false); +} + +static MCDisassembler *createMips64Disassembler( + const Target &T, + const MCSubtargetInfo &STI) { + return new Mips64Disassembler(STI, T.createMCRegInfo(""), true); +} + +static MCDisassembler *createMips64elDisassembler( + const Target &T, + const MCSubtargetInfo &STI) { + return new Mips64Disassembler(STI, T.createMCRegInfo(""), false); +} + +extern "C" void LLVMInitializeMipsDisassembler() { + // Register the disassembler. + TargetRegistry::RegisterMCDisassembler(TheMipsTarget, + createMipsDisassembler); + TargetRegistry::RegisterMCDisassembler(TheMipselTarget, + createMipselDisassembler); + TargetRegistry::RegisterMCDisassembler(TheMips64Target, + createMips64Disassembler); + TargetRegistry::RegisterMCDisassembler(TheMips64elTarget, + createMips64elDisassembler); +} + + +#include "MipsGenDisassemblerTables.inc" + + /// readInstruction - read four bytes from the MemoryObject + /// and return 32 bit word sorted according to the given endianess +static DecodeStatus readInstruction32(const MemoryObject ®ion, + uint64_t address, + uint64_t &size, + uint32_t &insn, + bool isBigEndian, + bool IsMicroMips) { + uint8_t Bytes[4]; + + // We want to read exactly 4 Bytes of data. + if (region.readBytes(address, 4, Bytes) == -1) { + size = 0; + return MCDisassembler::Fail; + } + + if (isBigEndian) { + // Encoded as a big-endian 32-bit word in the stream. + insn = (Bytes[3] << 0) | + (Bytes[2] << 8) | + (Bytes[1] << 16) | + (Bytes[0] << 24); + } + else { + // Encoded as a small-endian 32-bit word in the stream. + // Little-endian byte ordering: + // mips32r2: 4 | 3 | 2 | 1 + // microMIPS: 2 | 1 | 4 | 3 + if (IsMicroMips) { + insn = (Bytes[2] << 0) | + (Bytes[3] << 8) | + (Bytes[0] << 16) | + (Bytes[1] << 24); + } else { + insn = (Bytes[0] << 0) | + (Bytes[1] << 8) | + (Bytes[2] << 16) | + (Bytes[3] << 24); + } + } + + return MCDisassembler::Success; +} + +DecodeStatus +MipsDisassembler::getInstruction(MCInst &instr, + uint64_t &Size, + const MemoryObject &Region, + uint64_t Address, + raw_ostream &vStream, + raw_ostream &cStream) const { + uint32_t Insn; + + DecodeStatus Result = readInstruction32(Region, Address, Size, + Insn, isBigEndian, IsMicroMips); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + + if (IsMicroMips) { + // Calling the auto-generated decoder function. + Result = decodeInstruction(DecoderTableMicroMips32, instr, Insn, Address, + this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + return MCDisassembler::Fail; + } + + // Calling the auto-generated decoder function. + Result = decodeInstruction(DecoderTableMips32, instr, Insn, Address, + this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + + return MCDisassembler::Fail; +} + +DecodeStatus +Mips64Disassembler::getInstruction(MCInst &instr, + uint64_t &Size, + const MemoryObject &Region, + uint64_t Address, + raw_ostream &vStream, + raw_ostream &cStream) const { + uint32_t Insn; + + DecodeStatus Result = readInstruction32(Region, Address, Size, + Insn, isBigEndian, false); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + + // Calling the auto-generated decoder function. + Result = decodeInstruction(DecoderTableMips6432, instr, Insn, Address, + this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + // If we fail to decode in Mips64 decoder space we can try in Mips32 + Result = decodeInstruction(DecoderTableMips32, instr, Insn, Address, + this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + + return MCDisassembler::Fail; +} + +static unsigned getReg(const void *D, unsigned RC, unsigned RegNo) { + const MipsDisassemblerBase *Dis = static_cast<const MipsDisassemblerBase*>(D); + return *(Dis->getRegInfo()->getRegClass(RC).begin() + RegNo); +} + +static DecodeStatus DecodeCPU16RegsRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + + return MCDisassembler::Fail; + +} + +static DecodeStatus DecodeGPR64RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::GPR64RegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeGPR32RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + unsigned Reg = getReg(Decoder, Mips::GPR32RegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodePtrRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (static_cast<const MipsDisassembler *>(Decoder)->isN64()) + return DecodeGPR64RegisterClass(Inst, RegNo, Address, Decoder); + + return DecodeGPR32RegisterClass(Inst, RegNo, Address, Decoder); +} + +static DecodeStatus DecodeDSPRRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + return DecodeGPR32RegisterClass(Inst, RegNo, Address, Decoder); +} + +static DecodeStatus DecodeFGR64RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::FGR64RegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeFGR32RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::FGR32RegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeFGRH32RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::FGRH32RegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeCCRRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + unsigned Reg = getReg(Decoder, Mips::CCRRegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeFCCRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 7) + return MCDisassembler::Fail; + unsigned Reg = getReg(Decoder, Mips::FCCRegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMem(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Reg = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + if(Inst.getOpcode() == Mips::SC){ + Inst.addOperand(MCOperand::CreateReg(Reg)); + } + + Inst.addOperand(MCOperand::CreateReg(Reg)); + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMSA128Mem(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + int Offset = SignExtend32<10>(fieldFromInstruction(Insn, 16, 10)); + unsigned Reg = fieldFromInstruction(Insn, 6, 5); + unsigned Base = fieldFromInstruction(Insn, 11, 5); + + Reg = getReg(Decoder, Mips::MSA128BRegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::CreateReg(Reg)); + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMemMMImm12(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<12>(Insn & 0x0fff); + unsigned Reg = fieldFromInstruction(Insn, 21, 5); + unsigned Base = fieldFromInstruction(Insn, 16, 5); + + Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::CreateReg(Reg)); + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMemMMImm16(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Reg = fieldFromInstruction(Insn, 21, 5); + unsigned Base = fieldFromInstruction(Insn, 16, 5); + + Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::CreateReg(Reg)); + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + + return MCDisassembler::Success; +} + +static DecodeStatus DecodeFMem(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Offset = SignExtend32<16>(Insn & 0xffff); + unsigned Reg = fieldFromInstruction(Insn, 16, 5); + unsigned Base = fieldFromInstruction(Insn, 21, 5); + + Reg = getReg(Decoder, Mips::FGR64RegClassID, Reg); + Base = getReg(Decoder, Mips::GPR32RegClassID, Base); + + Inst.addOperand(MCOperand::CreateReg(Reg)); + Inst.addOperand(MCOperand::CreateReg(Base)); + Inst.addOperand(MCOperand::CreateImm(Offset)); + + return MCDisassembler::Success; +} + + +static DecodeStatus DecodeHWRegsRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + // Currently only hardware register 29 is supported. + if (RegNo != 29) + return MCDisassembler::Fail; + Inst.addOperand(MCOperand::CreateReg(Mips::HWR29)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeAFGR64RegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 30 || RegNo %2) + return MCDisassembler::Fail; + + ; + unsigned Reg = getReg(Decoder, Mips::AFGR64RegClassID, RegNo /2); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeACC64DSPRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo >= 4) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::ACC64DSPRegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeHI32DSPRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo >= 4) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::HI32DSPRegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeLO32DSPRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo >= 4) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::LO32DSPRegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMSA128BRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::MSA128BRegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMSA128HRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::MSA128HRegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMSA128WRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::MSA128WRegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMSA128DRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::MSA128DRegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeMSACtrlRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 7) + return MCDisassembler::Fail; + + unsigned Reg = getReg(Decoder, Mips::MSACtrlRegClassID, RegNo); + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeBranchTarget(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + unsigned BranchOffset = Offset & 0xffff; + BranchOffset = SignExtend32<18>(BranchOffset << 2) + 4; + Inst.addOperand(MCOperand::CreateImm(BranchOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeJumpTarget(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + + unsigned JumpOffset = fieldFromInstruction(Insn, 0, 26) << 2; + Inst.addOperand(MCOperand::CreateImm(JumpOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeBranchTargetMM(MCInst &Inst, + unsigned Offset, + uint64_t Address, + const void *Decoder) { + unsigned BranchOffset = Offset & 0xffff; + BranchOffset = SignExtend32<18>(BranchOffset << 1); + Inst.addOperand(MCOperand::CreateImm(BranchOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeJumpTargetMM(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + unsigned JumpOffset = fieldFromInstruction(Insn, 0, 26) << 1; + Inst.addOperand(MCOperand::CreateImm(JumpOffset)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeSimm16(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + Inst.addOperand(MCOperand::CreateImm(SignExtend32<16>(Insn))); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeLSAImm(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + // We add one to the immediate field as it was encoded as 'imm - 1'. + Inst.addOperand(MCOperand::CreateImm(Insn + 1)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeInsSize(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + // First we need to grab the pos(lsb) from MCInst. + int Pos = Inst.getOperand(2).getImm(); + int Size = (int) Insn - Pos + 1; + Inst.addOperand(MCOperand::CreateImm(SignExtend32<16>(Size))); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeExtSize(MCInst &Inst, + unsigned Insn, + uint64_t Address, + const void *Decoder) { + int Size = (int) Insn + 1; + Inst.addOperand(MCOperand::CreateImm(SignExtend32<16>(Size))); + return MCDisassembler::Success; +} diff --git a/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp b/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp new file mode 100644 index 000000000000..78845898997c --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp @@ -0,0 +1,288 @@ +//===-- MipsInstPrinter.cpp - Convert Mips 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 Mips MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "MipsInstPrinter.h" +#include "MipsInstrInfo.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define PRINT_ALIAS_INSTR +#include "MipsGenAsmWriter.inc" + +template<unsigned R> +static bool isReg(const MCInst &MI, unsigned OpNo) { + assert(MI.getOperand(OpNo).isReg() && "Register operand expected."); + return MI.getOperand(OpNo).getReg() == R; +} + +const char* Mips::MipsFCCToString(Mips::CondCode CC) { + switch (CC) { + case FCOND_F: + case FCOND_T: return "f"; + case FCOND_UN: + case FCOND_OR: return "un"; + case FCOND_OEQ: + case FCOND_UNE: return "eq"; + case FCOND_UEQ: + case FCOND_ONE: 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 "nge"; + case FCOND_LE: + case FCOND_NLE: return "le"; + case FCOND_NGT: + case FCOND_GT: return "ngt"; + } + llvm_unreachable("Impossible condition code!"); +} + +void MipsInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { + OS << '$' << StringRef(getRegisterName(RegNo)).lower(); +} + +void MipsInstPrinter::printInst(const MCInst *MI, raw_ostream &O, + StringRef Annot) { + switch (MI->getOpcode()) { + default: + break; + case Mips::RDHWR: + case Mips::RDHWR64: + O << "\t.set\tpush\n"; + O << "\t.set\tmips32r2\n"; + } + + // Try to print any aliases first. + if (!printAliasInstr(MI, O) && !printAlias(*MI, O)) + printInstruction(MI, O); + printAnnotation(O, Annot); + + switch (MI->getOpcode()) { + default: + break; + case Mips::RDHWR: + case Mips::RDHWR64: + O << "\n\t.set\tpop"; + } +} + +static void printExpr(const MCExpr *Expr, raw_ostream &OS) { + int Offset = 0; + const MCSymbolRefExpr *SRE; + + if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr)) { + SRE = dyn_cast<MCSymbolRefExpr>(BE->getLHS()); + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(BE->getRHS()); + assert(SRE && CE && "Binary expression must be sym+const."); + Offset = CE->getValue(); + } + else if (!(SRE = dyn_cast<MCSymbolRefExpr>(Expr))) + assert(false && "Unexpected MCExpr type."); + + MCSymbolRefExpr::VariantKind Kind = SRE->getKind(); + + switch (Kind) { + default: llvm_unreachable("Invalid kind!"); + case MCSymbolRefExpr::VK_None: break; + case MCSymbolRefExpr::VK_Mips_GPREL: OS << "%gp_rel("; break; + case MCSymbolRefExpr::VK_Mips_GOT_CALL: OS << "%call16("; break; + case MCSymbolRefExpr::VK_Mips_GOT16: OS << "%got("; break; + case MCSymbolRefExpr::VK_Mips_GOT: OS << "%got("; break; + case MCSymbolRefExpr::VK_Mips_ABS_HI: OS << "%hi("; break; + case MCSymbolRefExpr::VK_Mips_ABS_LO: OS << "%lo("; break; + case MCSymbolRefExpr::VK_Mips_TLSGD: OS << "%tlsgd("; break; + case MCSymbolRefExpr::VK_Mips_TLSLDM: OS << "%tlsldm("; break; + case MCSymbolRefExpr::VK_Mips_DTPREL_HI: OS << "%dtprel_hi("; break; + case MCSymbolRefExpr::VK_Mips_DTPREL_LO: OS << "%dtprel_lo("; break; + case MCSymbolRefExpr::VK_Mips_GOTTPREL: OS << "%gottprel("; break; + case MCSymbolRefExpr::VK_Mips_TPREL_HI: OS << "%tprel_hi("; break; + case MCSymbolRefExpr::VK_Mips_TPREL_LO: OS << "%tprel_lo("; break; + case MCSymbolRefExpr::VK_Mips_GPOFF_HI: OS << "%hi(%neg(%gp_rel("; break; + case MCSymbolRefExpr::VK_Mips_GPOFF_LO: OS << "%lo(%neg(%gp_rel("; break; + case MCSymbolRefExpr::VK_Mips_GOT_DISP: OS << "%got_disp("; break; + case MCSymbolRefExpr::VK_Mips_GOT_PAGE: OS << "%got_page("; break; + case MCSymbolRefExpr::VK_Mips_GOT_OFST: OS << "%got_ofst("; break; + case MCSymbolRefExpr::VK_Mips_HIGHER: OS << "%higher("; break; + case MCSymbolRefExpr::VK_Mips_HIGHEST: OS << "%highest("; break; + case MCSymbolRefExpr::VK_Mips_GOT_HI16: OS << "%got_hi("; break; + case MCSymbolRefExpr::VK_Mips_GOT_LO16: OS << "%got_lo("; break; + case MCSymbolRefExpr::VK_Mips_CALL_HI16: OS << "%call_hi("; break; + case MCSymbolRefExpr::VK_Mips_CALL_LO16: OS << "%call_lo("; break; + } + + OS << SRE->getSymbol(); + + if (Offset) { + if (Offset > 0) + OS << '+'; + OS << Offset; + } + + if ((Kind == MCSymbolRefExpr::VK_Mips_GPOFF_HI) || + (Kind == MCSymbolRefExpr::VK_Mips_GPOFF_LO)) + OS << ")))"; + else if (Kind != MCSymbolRefExpr::VK_None) + OS << ')'; +} + +void MipsInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) { + printRegName(O, Op.getReg()); + return; + } + + if (Op.isImm()) { + O << Op.getImm(); + return; + } + + assert(Op.isExpr() && "unknown operand kind in printOperand"); + printExpr(Op.getExpr(), O); +} + +void MipsInstPrinter::printUnsignedImm(const MCInst *MI, int opNum, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) + O << (unsigned short int)MO.getImm(); + else + printOperand(MI, opNum, O); +} + +void MipsInstPrinter::printUnsignedImm8(const MCInst *MI, int opNum, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) + O << (unsigned short int)(unsigned char)MO.getImm(); + else + printOperand(MI, opNum, O); +} + +void MipsInstPrinter:: +printMemOperand(const MCInst *MI, int opNum, raw_ostream &O) { + // Load/Store memory operands -- imm($reg) + // If PIC target the target is loaded as the + // pattern lw $25,%call16($28) + printOperand(MI, opNum+1, O); + O << "("; + printOperand(MI, opNum, O); + O << ")"; +} + +void MipsInstPrinter:: +printMemOperandEA(const MCInst *MI, int opNum, raw_ostream &O) { + // when using stack locations for not load/store instructions + // print the same way as all normal 3 operand instructions. + printOperand(MI, opNum, O); + O << ", "; + printOperand(MI, opNum+1, O); + return; +} + +void MipsInstPrinter:: +printFCCOperand(const MCInst *MI, int opNum, raw_ostream &O) { + const MCOperand& MO = MI->getOperand(opNum); + O << MipsFCCToString((Mips::CondCode)MO.getImm()); +} + +void MipsInstPrinter:: +printSHFMask(const MCInst *MI, int opNum, raw_ostream &O) { + llvm_unreachable("TODO"); +} + +bool MipsInstPrinter::printAlias(const char *Str, const MCInst &MI, + unsigned OpNo, raw_ostream &OS) { + OS << "\t" << Str << "\t"; + printOperand(&MI, OpNo, OS); + return true; +} + +bool MipsInstPrinter::printAlias(const char *Str, const MCInst &MI, + unsigned OpNo0, unsigned OpNo1, + raw_ostream &OS) { + printAlias(Str, MI, OpNo0, OS); + OS << ", "; + printOperand(&MI, OpNo1, OS); + return true; +} + +bool MipsInstPrinter::printAlias(const MCInst &MI, raw_ostream &OS) { + switch (MI.getOpcode()) { + case Mips::BEQ: + // beq $zero, $zero, $L2 => b $L2 + // beq $r0, $zero, $L2 => beqz $r0, $L2 + return (isReg<Mips::ZERO>(MI, 0) && isReg<Mips::ZERO>(MI, 1) && + printAlias("b", MI, 2, OS)) || + (isReg<Mips::ZERO>(MI, 1) && printAlias("beqz", MI, 0, 2, OS)); + case Mips::BEQ64: + // beq $r0, $zero, $L2 => beqz $r0, $L2 + return isReg<Mips::ZERO_64>(MI, 1) && printAlias("beqz", MI, 0, 2, OS); + case Mips::BNE: + // bne $r0, $zero, $L2 => bnez $r0, $L2 + return isReg<Mips::ZERO>(MI, 1) && printAlias("bnez", MI, 0, 2, OS); + case Mips::BNE64: + // bne $r0, $zero, $L2 => bnez $r0, $L2 + return isReg<Mips::ZERO_64>(MI, 1) && printAlias("bnez", MI, 0, 2, OS); + case Mips::BGEZAL: + // bgezal $zero, $L1 => bal $L1 + return isReg<Mips::ZERO>(MI, 0) && printAlias("bal", MI, 1, OS); + case Mips::BC1T: + // bc1t $fcc0, $L1 => bc1t $L1 + return isReg<Mips::FCC0>(MI, 0) && printAlias("bc1t", MI, 1, OS); + case Mips::BC1F: + // bc1f $fcc0, $L1 => bc1f $L1 + return isReg<Mips::FCC0>(MI, 0) && printAlias("bc1f", MI, 1, OS); + case Mips::JALR: + // jalr $ra, $r1 => jalr $r1 + return isReg<Mips::RA>(MI, 0) && printAlias("jalr", MI, 1, OS); + case Mips::JALR64: + // jalr $ra, $r1 => jalr $r1 + return isReg<Mips::RA_64>(MI, 0) && printAlias("jalr", MI, 1, OS); + case Mips::NOR: + case Mips::NOR_MM: + // nor $r0, $r1, $zero => not $r0, $r1 + return isReg<Mips::ZERO>(MI, 2) && printAlias("not", MI, 0, 1, OS); + case Mips::NOR64: + // nor $r0, $r1, $zero => not $r0, $r1 + return isReg<Mips::ZERO_64>(MI, 2) && printAlias("not", MI, 0, 1, OS); + case Mips::OR: + // or $r0, $r1, $zero => move $r0, $r1 + return isReg<Mips::ZERO>(MI, 2) && printAlias("move", MI, 0, 1, OS); + default: return false; + } +} diff --git a/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h b/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h new file mode 100644 index 000000000000..f75ae249c3ee --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h @@ -0,0 +1,110 @@ +//=== MipsInstPrinter.h - Convert Mips 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 Mips MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSINSTPRINTER_H +#define MIPSINSTPRINTER_H +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm { +// These enumeration declarations were originally in MipsInstrInfo.h but +// had to be moved here to avoid circular dependencies between +// LLVMMipsCodeGen and LLVMMipsAsmPrinter. +namespace Mips { +// Mips Branch Codes +enum FPBranchCode { + BRANCH_F, + BRANCH_T, + BRANCH_FL, + BRANCH_TL, + BRANCH_INVALID +}; + +// Mips Condition Codes +enum CondCode { + // To be used with float branch True + FCOND_F, + FCOND_UN, + FCOND_OEQ, + 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_UNE, + FCOND_ONE, + FCOND_UGE, + FCOND_OGE, + FCOND_UGT, + FCOND_OGT, + FCOND_ST, + FCOND_GLE, + FCOND_SNE, + FCOND_GL, + FCOND_NLT, + FCOND_GE, + FCOND_NLE, + FCOND_GT +}; + +const char *MipsFCCToString(Mips::CondCode CC); +} // end namespace Mips + +class TargetMachine; + +class MipsInstPrinter : public MCInstPrinter { +public: + MipsInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, + const MCRegisterInfo &MRI) + : MCInstPrinter(MAI, MII, MRI) {} + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); + + virtual void printRegName(raw_ostream &OS, unsigned RegNo) const; + virtual void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot); + + bool printAliasInstr(const MCInst *MI, raw_ostream &OS); + +private: + void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printUnsignedImm(const MCInst *MI, int opNum, raw_ostream &O); + void printUnsignedImm8(const MCInst *MI, int opNum, raw_ostream &O); + void printMemOperand(const MCInst *MI, int opNum, raw_ostream &O); + void printMemOperandEA(const MCInst *MI, int opNum, raw_ostream &O); + void printFCCOperand(const MCInst *MI, int opNum, raw_ostream &O); + void printSHFMask(const MCInst *MI, int opNum, raw_ostream &O); + + bool printAlias(const char *Str, const MCInst &MI, unsigned OpNo, + raw_ostream &OS); + bool printAlias(const char *Str, const MCInst &MI, unsigned OpNo0, + unsigned OpNo1, raw_ostream &OS); + bool printAlias(const MCInst &MI, raw_ostream &OS); +}; +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp new file mode 100644 index 000000000000..3e70b23dccc6 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -0,0 +1,312 @@ +//===-- MipsASMBackend.cpp - Mips Asm 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 the MipsAsmBackend and MipsELFObjectWriter classes. +// +//===----------------------------------------------------------------------===// +// + +#include "MipsFixupKinds.h" +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCDirectives.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +// Prepare value for the target space for it +static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { + + // Add/subtract and shift + switch (Kind) { + default: + return 0; + case FK_GPRel_4: + case FK_Data_4: + case FK_Data_8: + case Mips::fixup_Mips_LO16: + case Mips::fixup_Mips_GPREL16: + case Mips::fixup_Mips_GPOFF_HI: + case Mips::fixup_Mips_GPOFF_LO: + case Mips::fixup_Mips_GOT_PAGE: + case Mips::fixup_Mips_GOT_OFST: + case Mips::fixup_Mips_GOT_DISP: + case Mips::fixup_Mips_GOT_LO16: + case Mips::fixup_Mips_CALL_LO16: + case Mips::fixup_MICROMIPS_LO16: + case Mips::fixup_MICROMIPS_GOT_PAGE: + case Mips::fixup_MICROMIPS_GOT_OFST: + case Mips::fixup_MICROMIPS_GOT_DISP: + break; + case Mips::fixup_Mips_PC16: + // So far we are only using this type for branches. + // For branches we start 1 instruction after the branch + // so the displacement will be one instruction size less. + Value -= 4; + // The displacement is then divided by 4 to give us an 18 bit + // address range. + Value >>= 2; + break; + case Mips::fixup_Mips_26: + // So far we are only using this type for jumps. + // The displacement is then divided by 4 to give us an 28 bit + // address range. + Value >>= 2; + break; + case Mips::fixup_Mips_HI16: + case Mips::fixup_Mips_GOT_Local: + case Mips::fixup_Mips_GOT_HI16: + case Mips::fixup_Mips_CALL_HI16: + case Mips::fixup_MICROMIPS_HI16: + // Get the 2nd 16-bits. Also add 1 if bit 15 is 1. + Value = ((Value + 0x8000) >> 16) & 0xffff; + break; + case Mips::fixup_Mips_HIGHER: + // Get the 3rd 16-bits. + Value = ((Value + 0x80008000LL) >> 32) & 0xffff; + break; + case Mips::fixup_Mips_HIGHEST: + // Get the 4th 16-bits. + Value = ((Value + 0x800080008000LL) >> 48) & 0xffff; + break; + case Mips::fixup_MICROMIPS_26_S1: + Value >>= 1; + break; + case Mips::fixup_MICROMIPS_PC16_S1: + Value -= 4; + Value >>= 1; + break; + } + + return Value; +} + +namespace { +class MipsAsmBackend : public MCAsmBackend { + Triple::OSType OSType; + bool IsLittle; // Big or little endian + bool Is64Bit; // 32 or 64 bit words + +public: + MipsAsmBackend(const Target &T, Triple::OSType _OSType, + bool _isLittle, bool _is64Bit) + :MCAsmBackend(), OSType(_OSType), IsLittle(_isLittle), Is64Bit(_is64Bit) {} + + MCObjectWriter *createObjectWriter(raw_ostream &OS) const { + return createMipsELFObjectWriter(OS, + MCELFObjectTargetWriter::getOSABI(OSType), IsLittle, Is64Bit); + } + + /// ApplyFixup - Apply the \p Value for given \p Fixup into the provided + /// data fragment, at the offset specified by the fixup and following the + /// fixup kind as appropriate. + void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + uint64_t Value) const { + MCFixupKind Kind = Fixup.getKind(); + Value = adjustFixupValue((unsigned)Kind, Value); + + if (!Value) + return; // Doesn't change encoding. + + // Where do we start in the object + unsigned Offset = Fixup.getOffset(); + // Number of bytes we need to fixup + unsigned NumBytes = (getFixupKindInfo(Kind).TargetSize + 7) / 8; + // Used to point to big endian bytes + unsigned FullSize; + + switch ((unsigned)Kind) { + case Mips::fixup_Mips_16: + FullSize = 2; + break; + case Mips::fixup_Mips_64: + FullSize = 8; + break; + default: + FullSize = 4; + break; + } + + // Grab current value, if any, from bits. + uint64_t CurVal = 0; + + for (unsigned i = 0; i != NumBytes; ++i) { + unsigned Idx = IsLittle ? i : (FullSize - 1 - i); + CurVal |= (uint64_t)((uint8_t)Data[Offset + Idx]) << (i*8); + } + + uint64_t Mask = ((uint64_t)(-1) >> + (64 - getFixupKindInfo(Kind).TargetSize)); + CurVal |= Value & Mask; + + // Write out the fixed up bytes back to the code/data bits. + for (unsigned i = 0; i != NumBytes; ++i) { + unsigned Idx = IsLittle ? i : (FullSize - 1 - i); + Data[Offset + Idx] = (uint8_t)((CurVal >> (i*8)) & 0xff); + } + } + + unsigned getNumFixupKinds() const { return Mips::NumTargetFixupKinds; } + + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const { + const static MCFixupKindInfo Infos[Mips::NumTargetFixupKinds] = { + // This table *must* be in same the order of fixup_* kinds in + // MipsFixupKinds.h. + // + // name offset bits flags + { "fixup_Mips_16", 0, 16, 0 }, + { "fixup_Mips_32", 0, 32, 0 }, + { "fixup_Mips_REL32", 0, 32, 0 }, + { "fixup_Mips_26", 0, 26, 0 }, + { "fixup_Mips_HI16", 0, 16, 0 }, + { "fixup_Mips_LO16", 0, 16, 0 }, + { "fixup_Mips_GPREL16", 0, 16, 0 }, + { "fixup_Mips_LITERAL", 0, 16, 0 }, + { "fixup_Mips_GOT_Global", 0, 16, 0 }, + { "fixup_Mips_GOT_Local", 0, 16, 0 }, + { "fixup_Mips_PC16", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_Mips_CALL16", 0, 16, 0 }, + { "fixup_Mips_GPREL32", 0, 32, 0 }, + { "fixup_Mips_SHIFT5", 6, 5, 0 }, + { "fixup_Mips_SHIFT6", 6, 5, 0 }, + { "fixup_Mips_64", 0, 64, 0 }, + { "fixup_Mips_TLSGD", 0, 16, 0 }, + { "fixup_Mips_GOTTPREL", 0, 16, 0 }, + { "fixup_Mips_TPREL_HI", 0, 16, 0 }, + { "fixup_Mips_TPREL_LO", 0, 16, 0 }, + { "fixup_Mips_TLSLDM", 0, 16, 0 }, + { "fixup_Mips_DTPREL_HI", 0, 16, 0 }, + { "fixup_Mips_DTPREL_LO", 0, 16, 0 }, + { "fixup_Mips_Branch_PCRel", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_Mips_GPOFF_HI", 0, 16, 0 }, + { "fixup_Mips_GPOFF_LO", 0, 16, 0 }, + { "fixup_Mips_GOT_PAGE", 0, 16, 0 }, + { "fixup_Mips_GOT_OFST", 0, 16, 0 }, + { "fixup_Mips_GOT_DISP", 0, 16, 0 }, + { "fixup_Mips_HIGHER", 0, 16, 0 }, + { "fixup_Mips_HIGHEST", 0, 16, 0 }, + { "fixup_Mips_GOT_HI16", 0, 16, 0 }, + { "fixup_Mips_GOT_LO16", 0, 16, 0 }, + { "fixup_Mips_CALL_HI16", 0, 16, 0 }, + { "fixup_Mips_CALL_LO16", 0, 16, 0 }, + { "fixup_MICROMIPS_26_S1", 0, 26, 0 }, + { "fixup_MICROMIPS_HI16", 0, 16, 0 }, + { "fixup_MICROMIPS_LO16", 0, 16, 0 }, + { "fixup_MICROMIPS_GOT16", 0, 16, 0 }, + { "fixup_MICROMIPS_PC16_S1", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_MICROMIPS_CALL16", 0, 16, 0 }, + { "fixup_MICROMIPS_GOT_DISP", 0, 16, 0 }, + { "fixup_MICROMIPS_GOT_PAGE", 0, 16, 0 }, + { "fixup_MICROMIPS_GOT_OFST", 0, 16, 0 }, + { "fixup_MICROMIPS_TLS_DTPREL_HI16", 0, 16, 0 }, + { "fixup_MICROMIPS_TLS_DTPREL_LO16", 0, 16, 0 }, + { "fixup_MICROMIPS_TLS_TPREL_HI16", 0, 16, 0 }, + { "fixup_MICROMIPS_TLS_TPREL_LO16", 0, 16, 0 } + }; + + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return Infos[Kind - FirstTargetFixupKind]; + } + + /// @name Target Relaxation Interfaces + /// @{ + + /// MayNeedRelaxation - Check whether the given instruction may need + /// relaxation. + /// + /// \param Inst - The instruction to test. + bool mayNeedRelaxation(const MCInst &Inst) const { + return false; + } + + /// fixupNeedsRelaxation - Target specific predicate for whether a given + /// fixup requires the associated instruction to be relaxed. + bool fixupNeedsRelaxation(const MCFixup &Fixup, + uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const { + // FIXME. + assert(0 && "RelaxInstruction() unimplemented"); + return false; + } + + /// RelaxInstruction - Relax the instruction in the given fragment + /// to the next wider instruction. + /// + /// \param Inst - The instruction to relax, which may be the same + /// as the output. + /// \param [out] Res On return, the relaxed instruction. + void relaxInstruction(const MCInst &Inst, MCInst &Res) const { + } + + /// @} + + /// WriteNopData - Write an (optimal) nop sequence of Count bytes + /// to the given output. If the target cannot generate such a sequence, + /// it should return an error. + /// + /// \return - True on success. + bool writeNopData(uint64_t Count, MCObjectWriter *OW) const { + // Check for a less than instruction size number of bytes + // FIXME: 16 bit instructions are not handled yet here. + // We shouldn't be using a hard coded number for instruction size. + if (Count % 4) return false; + + uint64_t NumNops = Count / 4; + for (uint64_t i = 0; i != NumNops; ++i) + OW->Write32(0); + return true; + } +}; // class MipsAsmBackend + +} // namespace + +// MCAsmBackend +MCAsmBackend *llvm::createMipsAsmBackendEL32(const Target &T, + const MCRegisterInfo &MRI, + StringRef TT, + StringRef CPU) { + return new MipsAsmBackend(T, Triple(TT).getOS(), + /*IsLittle*/true, /*Is64Bit*/false); +} + +MCAsmBackend *llvm::createMipsAsmBackendEB32(const Target &T, + const MCRegisterInfo &MRI, + StringRef TT, + StringRef CPU) { + return new MipsAsmBackend(T, Triple(TT).getOS(), + /*IsLittle*/false, /*Is64Bit*/false); +} + +MCAsmBackend *llvm::createMipsAsmBackendEL64(const Target &T, + const MCRegisterInfo &MRI, + StringRef TT, + StringRef CPU) { + return new MipsAsmBackend(T, Triple(TT).getOS(), + /*IsLittle*/true, /*Is64Bit*/true); +} + +MCAsmBackend *llvm::createMipsAsmBackendEB64(const Target &T, + const MCRegisterInfo &MRI, + StringRef TT, + StringRef CPU) { + return new MipsAsmBackend(T, Triple(TT).getOS(), + /*IsLittle*/false, /*Is64Bit*/true); +} + diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h new file mode 100644 index 000000000000..7a55efd5c330 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h @@ -0,0 +1,153 @@ +//===-- MipsBaseInfo.h - Top level definitions for MIPS MC ------*- 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 Mips target useful for the compiler back-end and the MC libraries. +// +//===----------------------------------------------------------------------===// +#ifndef MIPSBASEINFO_H +#define MIPSBASEINFO_H + +#include "MipsFixupKinds.h" +#include "MipsMCTargetDesc.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" + +namespace llvm { + +/// MipsII - This namespace holds all of the target specific flags that +/// instruction info tracks. +/// +namespace MipsII { + /// Target Operand Flag enum. + enum TOF { + //===------------------------------------------------------------------===// + // Mips Specific MachineOperand flags. + + MO_NO_FLAG, + + /// MO_GOT16 - Represents the offset into the global offset table at which + /// the address the relocation entry symbol resides during execution. + MO_GOT16, + 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_HI/LO - Represents the hi or low part of an absolute symbol + /// address. + MO_ABS_HI, + MO_ABS_LO, + + /// MO_TLSGD - Represents the offset into the global offset table at which + // the module ID and TSL block offset reside during execution (General + // Dynamic TLS). + MO_TLSGD, + + /// MO_TLSLDM - Represents the offset into the global offset table at which + // the module ID and TSL block offset reside during execution (Local + // Dynamic TLS). + MO_TLSLDM, + MO_DTPREL_HI, + MO_DTPREL_LO, + + /// MO_GOTTPREL - Represents the offset from the thread pointer (Initial + // Exec TLS). + MO_GOTTPREL, + + /// MO_TPREL_HI/LO - Represents the hi and low part of the offset from + // the thread pointer (Local Exec TLS). + MO_TPREL_HI, + MO_TPREL_LO, + + // N32/64 Flags. + MO_GPOFF_HI, + MO_GPOFF_LO, + MO_GOT_DISP, + MO_GOT_PAGE, + MO_GOT_OFST, + + /// MO_HIGHER/HIGHEST - Represents the highest or higher half word of a + /// 64-bit symbol address. + MO_HIGHER, + MO_HIGHEST, + + /// MO_GOT_HI16/LO16, MO_CALL_HI16/LO16 - Relocations used for large GOTs. + MO_GOT_HI16, + MO_GOT_LO16, + MO_CALL_HI16, + MO_CALL_LO16 + }; + + enum { + //===------------------------------------------------------------------===// + // Instruction encodings. These are the standard/most common forms for + // Mips instructions. + // + + // Pseudo - 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. + Pseudo = 0, + + /// FrmR - This form is for instructions of the format R. + FrmR = 1, + /// FrmI - This form is for instructions of the format I. + FrmI = 2, + /// FrmJ - This form is for instructions of the format J. + FrmJ = 3, + /// FrmFR - This form is for instructions of the format FR. + FrmFR = 4, + /// FrmFI - This form is for instructions of the format FI. + FrmFI = 5, + /// FrmOther - This form is for instructions that have no specific format. + FrmOther = 6, + + FormMask = 15 + }; +} + +inline static std::pair<const MCSymbolRefExpr*, int64_t> +MipsGetSymAndOffset(const MCFixup &Fixup) { + MCFixupKind FixupKind = Fixup.getKind(); + + if ((FixupKind < FirstTargetFixupKind) || + (FixupKind >= MCFixupKind(Mips::LastTargetFixupKind))) + return std::make_pair((const MCSymbolRefExpr*)0, (int64_t)0); + + const MCExpr *Expr = Fixup.getValue(); + MCExpr::ExprKind Kind = Expr->getKind(); + + if (Kind == MCExpr::Binary) { + const MCBinaryExpr *BE = static_cast<const MCBinaryExpr*>(Expr); + const MCExpr *LHS = BE->getLHS(); + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(BE->getRHS()); + + if ((LHS->getKind() != MCExpr::SymbolRef) || !CE) + return std::make_pair((const MCSymbolRefExpr*)0, (int64_t)0); + + return std::make_pair(cast<MCSymbolRefExpr>(LHS), CE->getValue()); + } + + if (Kind != MCExpr::SymbolRef) + return std::make_pair((const MCSymbolRefExpr*)0, (int64_t)0); + + return std::make_pair(cast<MCSymbolRefExpr>(Expr), 0); +} +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp new file mode 100644 index 000000000000..83c7d4bcc3c6 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp @@ -0,0 +1,324 @@ +//===-- MipsELFObjectWriter.cpp - Mips 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/MipsBaseInfo.h" +#include "MCTargetDesc/MipsFixupKinds.h" +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/ErrorHandling.h" +#include <list> + +using namespace llvm; + +namespace { + struct RelEntry { + RelEntry(const ELFRelocationEntry &R, const MCSymbol *S, int64_t O) : + Reloc(R), Sym(S), Offset(O) {} + ELFRelocationEntry Reloc; + const MCSymbol *Sym; + int64_t Offset; + }; + + typedef std::list<RelEntry> RelLs; + typedef RelLs::iterator RelLsIter; + + class MipsELFObjectWriter : public MCELFObjectTargetWriter { + public: + MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI, + bool _isN64, bool IsLittleEndian); + + virtual ~MipsELFObjectWriter(); + + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend) const; + virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + const MCFixup &Fixup, + bool IsPCRel) const; + virtual void sortRelocs(const MCAssembler &Asm, + std::vector<ELFRelocationEntry> &Relocs); + }; +} + +MipsELFObjectWriter::MipsELFObjectWriter(bool _is64Bit, uint8_t OSABI, + bool _isN64, bool IsLittleEndian) + : MCELFObjectTargetWriter(_is64Bit, OSABI, ELF::EM_MIPS, + /*HasRelocationAddend*/ (_isN64) ? true : false, + /*IsN64*/ _isN64) {} + +MipsELFObjectWriter::~MipsELFObjectWriter() {} + +const MCSymbol *MipsELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + const MCFixup &Fixup, + bool IsPCRel) const { + assert(Target.getSymA() && "SymA cannot be 0."); + const MCSymbol &Sym = Target.getSymA()->getSymbol().AliasedSymbol(); + + if (Sym.getSection().getKind().isMergeableCString() || + Sym.getSection().getKind().isMergeableConst()) + return &Sym; + + return NULL; +} + +unsigned MipsELFObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel, + bool IsRelocWithSymbol, + int64_t Addend) const { + // determine the type of the relocation + unsigned Type = (unsigned)ELF::R_MIPS_NONE; + unsigned Kind = (unsigned)Fixup.getKind(); + + switch (Kind) { + default: + llvm_unreachable("invalid fixup kind!"); + case FK_Data_4: + Type = ELF::R_MIPS_32; + break; + case FK_Data_8: + Type = ELF::R_MIPS_64; + break; + case FK_GPRel_4: + if (isN64()) { + Type = setRType((unsigned)ELF::R_MIPS_GPREL32, Type); + Type = setRType2((unsigned)ELF::R_MIPS_64, Type); + Type = setRType3((unsigned)ELF::R_MIPS_NONE, Type); + } + else + Type = ELF::R_MIPS_GPREL32; + break; + case Mips::fixup_Mips_GPREL16: + Type = ELF::R_MIPS_GPREL16; + break; + case Mips::fixup_Mips_26: + Type = ELF::R_MIPS_26; + break; + case Mips::fixup_Mips_CALL16: + Type = ELF::R_MIPS_CALL16; + break; + case Mips::fixup_Mips_GOT_Global: + case Mips::fixup_Mips_GOT_Local: + Type = ELF::R_MIPS_GOT16; + break; + case Mips::fixup_Mips_HI16: + Type = ELF::R_MIPS_HI16; + break; + case Mips::fixup_Mips_LO16: + Type = ELF::R_MIPS_LO16; + break; + case Mips::fixup_Mips_TLSGD: + Type = ELF::R_MIPS_TLS_GD; + break; + case Mips::fixup_Mips_GOTTPREL: + Type = ELF::R_MIPS_TLS_GOTTPREL; + break; + case Mips::fixup_Mips_TPREL_HI: + Type = ELF::R_MIPS_TLS_TPREL_HI16; + break; + case Mips::fixup_Mips_TPREL_LO: + Type = ELF::R_MIPS_TLS_TPREL_LO16; + break; + case Mips::fixup_Mips_TLSLDM: + Type = ELF::R_MIPS_TLS_LDM; + break; + case Mips::fixup_Mips_DTPREL_HI: + Type = ELF::R_MIPS_TLS_DTPREL_HI16; + break; + case Mips::fixup_Mips_DTPREL_LO: + Type = ELF::R_MIPS_TLS_DTPREL_LO16; + break; + case Mips::fixup_Mips_Branch_PCRel: + case Mips::fixup_Mips_PC16: + Type = ELF::R_MIPS_PC16; + break; + case Mips::fixup_Mips_GOT_PAGE: + Type = ELF::R_MIPS_GOT_PAGE; + break; + case Mips::fixup_Mips_GOT_OFST: + Type = ELF::R_MIPS_GOT_OFST; + break; + case Mips::fixup_Mips_GOT_DISP: + Type = ELF::R_MIPS_GOT_DISP; + break; + case Mips::fixup_Mips_GPOFF_HI: + Type = setRType((unsigned)ELF::R_MIPS_GPREL16, Type); + Type = setRType2((unsigned)ELF::R_MIPS_SUB, Type); + Type = setRType3((unsigned)ELF::R_MIPS_HI16, Type); + break; + case Mips::fixup_Mips_GPOFF_LO: + Type = setRType((unsigned)ELF::R_MIPS_GPREL16, Type); + Type = setRType2((unsigned)ELF::R_MIPS_SUB, Type); + Type = setRType3((unsigned)ELF::R_MIPS_LO16, Type); + break; + case Mips::fixup_Mips_HIGHER: + Type = ELF::R_MIPS_HIGHER; + break; + case Mips::fixup_Mips_HIGHEST: + Type = ELF::R_MIPS_HIGHEST; + break; + case Mips::fixup_Mips_GOT_HI16: + Type = ELF::R_MIPS_GOT_HI16; + break; + case Mips::fixup_Mips_GOT_LO16: + Type = ELF::R_MIPS_GOT_LO16; + break; + case Mips::fixup_Mips_CALL_HI16: + Type = ELF::R_MIPS_CALL_HI16; + break; + case Mips::fixup_Mips_CALL_LO16: + Type = ELF::R_MIPS_CALL_LO16; + break; + case Mips::fixup_MICROMIPS_26_S1: + Type = ELF::R_MICROMIPS_26_S1; + break; + case Mips::fixup_MICROMIPS_HI16: + Type = ELF::R_MICROMIPS_HI16; + break; + case Mips::fixup_MICROMIPS_LO16: + Type = ELF::R_MICROMIPS_LO16; + break; + case Mips::fixup_MICROMIPS_GOT16: + Type = ELF::R_MICROMIPS_GOT16; + break; + case Mips::fixup_MICROMIPS_PC16_S1: + Type = ELF::R_MICROMIPS_PC16_S1; + break; + case Mips::fixup_MICROMIPS_CALL16: + Type = ELF::R_MICROMIPS_CALL16; + break; + case Mips::fixup_MICROMIPS_GOT_DISP: + Type = ELF::R_MICROMIPS_GOT_DISP; + break; + case Mips::fixup_MICROMIPS_GOT_PAGE: + Type = ELF::R_MICROMIPS_GOT_PAGE; + break; + case Mips::fixup_MICROMIPS_GOT_OFST: + Type = ELF::R_MICROMIPS_GOT_OFST; + break; + case Mips::fixup_MICROMIPS_TLS_DTPREL_HI16: + Type = ELF::R_MICROMIPS_TLS_DTPREL_HI16; + break; + case Mips::fixup_MICROMIPS_TLS_DTPREL_LO16: + Type = ELF::R_MICROMIPS_TLS_DTPREL_LO16; + break; + case Mips::fixup_MICROMIPS_TLS_TPREL_HI16: + Type = ELF::R_MICROMIPS_TLS_TPREL_HI16; + break; + case Mips::fixup_MICROMIPS_TLS_TPREL_LO16: + Type = ELF::R_MICROMIPS_TLS_TPREL_LO16; + break; + } + return Type; +} + +// Return true if R is either a GOT16 against a local symbol or HI16. +static bool NeedsMatchingLo(const MCAssembler &Asm, const RelEntry &R) { + if (!R.Sym) + return false; + + MCSymbolData &SD = Asm.getSymbolData(R.Sym->AliasedSymbol()); + + return ((R.Reloc.Type == ELF::R_MIPS_GOT16) && !SD.isExternal()) || + (R.Reloc.Type == ELF::R_MIPS_HI16); +} + +static bool HasMatchingLo(const MCAssembler &Asm, RelLsIter I, RelLsIter Last) { + if (I == Last) + return false; + + RelLsIter Hi = I++; + + return (I->Reloc.Type == ELF::R_MIPS_LO16) && (Hi->Sym == I->Sym) && + (Hi->Offset == I->Offset); +} + +static bool HasSameSymbol(const RelEntry &R0, const RelEntry &R1) { + return R0.Sym == R1.Sym; +} + +static int CompareOffset(const RelEntry &R0, const RelEntry &R1) { + return (R0.Offset > R1.Offset) ? 1 : ((R0.Offset == R1.Offset) ? 0 : -1); +} + +void MipsELFObjectWriter::sortRelocs(const MCAssembler &Asm, + std::vector<ELFRelocationEntry> &Relocs) { + // Call the default function first. Relocations are sorted in descending + // order of r_offset. + MCELFObjectTargetWriter::sortRelocs(Asm, Relocs); + + RelLs RelocLs; + std::vector<RelLsIter> Unmatched; + + // Fill RelocLs. Traverse Relocs backwards so that relocations in RelocLs + // are in ascending order of r_offset. + for (std::vector<ELFRelocationEntry>::reverse_iterator R = Relocs.rbegin(); + R != Relocs.rend(); ++R) { + std::pair<const MCSymbolRefExpr*, int64_t> P = + MipsGetSymAndOffset(*R->Fixup); + RelocLs.push_back(RelEntry(*R, P.first ? &P.first->getSymbol() : 0, + P.second)); + } + + // Get list of unmatched HI16 and GOT16. + for (RelLsIter R = RelocLs.begin(); R != RelocLs.end(); ++R) + if (NeedsMatchingLo(Asm, *R) && !HasMatchingLo(Asm, R, --RelocLs.end())) + Unmatched.push_back(R); + + // Insert unmatched HI16 and GOT16 immediately before their matching LO16. + for (std::vector<RelLsIter>::iterator U = Unmatched.begin(); + U != Unmatched.end(); ++U) { + RelLsIter LoPos = RelocLs.end(), HiPos = *U; + bool MatchedLo = false; + + for (RelLsIter R = RelocLs.begin(); R != RelocLs.end(); ++R) { + if ((R->Reloc.Type == ELF::R_MIPS_LO16) && HasSameSymbol(*HiPos, *R) && + (CompareOffset(*R, *HiPos) >= 0) && + ((LoPos == RelocLs.end()) || ((CompareOffset(*R, *LoPos) < 0)) || + (!MatchedLo && !CompareOffset(*R, *LoPos)))) + LoPos = R; + + MatchedLo = NeedsMatchingLo(Asm, *R) && + HasMatchingLo(Asm, R, --RelocLs.end()); + } + + // If a matching LoPos was found, move HiPos and insert it before LoPos. + // Make the offsets of HiPos and LoPos match. + if (LoPos != RelocLs.end()) { + HiPos->Offset = LoPos->Offset; + RelocLs.insert(LoPos, *HiPos); + RelocLs.erase(HiPos); + } + } + + // Put the sorted list back in reverse order. + assert(Relocs.size() == RelocLs.size()); + unsigned I = RelocLs.size(); + + for (RelLsIter R = RelocLs.begin(); R != RelocLs.end(); ++R) + Relocs[--I] = R->Reloc; +} + +MCObjectWriter *llvm::createMipsELFObjectWriter(raw_ostream &OS, + uint8_t OSABI, + bool IsLittleEndian, + bool Is64Bit) { + MCELFObjectTargetWriter *MOTW = new MipsELFObjectWriter(Is64Bit, OSABI, + (Is64Bit) ? true : false, + IsLittleEndian); + return createELFObjectWriter(MOTW, OS, IsLittleEndian); +} diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h new file mode 100644 index 000000000000..6ed44b74cc4b --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h @@ -0,0 +1,178 @@ +//===-- MipsFixupKinds.h - Mips Specific Fixup Entries ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MIPS_MIPSFIXUPKINDS_H +#define LLVM_MIPS_MIPSFIXUPKINDS_H + +#include "llvm/MC/MCFixup.h" + +namespace llvm { +namespace Mips { + // Although most of the current fixup types reflect a unique relocation + // one can have multiple fixup types for a given relocation and thus need + // to be uniquely named. + // + // This table *must* be in the save order of + // MCFixupKindInfo Infos[Mips::NumTargetFixupKinds] + // in MipsAsmBackend.cpp. + // + enum Fixups { + // Branch fixups resulting in R_MIPS_16. + fixup_Mips_16 = FirstTargetFixupKind, + + // Pure 32 bit data fixup resulting in - R_MIPS_32. + fixup_Mips_32, + + // Full 32 bit data relative data fixup resulting in - R_MIPS_REL32. + fixup_Mips_REL32, + + // Jump 26 bit fixup resulting in - R_MIPS_26. + fixup_Mips_26, + + // Pure upper 16 bit fixup resulting in - R_MIPS_HI16. + fixup_Mips_HI16, + + // Pure lower 16 bit fixup resulting in - R_MIPS_LO16. + fixup_Mips_LO16, + + // 16 bit fixup for GP offest resulting in - R_MIPS_GPREL16. + fixup_Mips_GPREL16, + + // 16 bit literal fixup resulting in - R_MIPS_LITERAL. + fixup_Mips_LITERAL, + + // Global symbol fixup resulting in - R_MIPS_GOT16. + fixup_Mips_GOT_Global, + + // Local symbol fixup resulting in - R_MIPS_GOT16. + fixup_Mips_GOT_Local, + + // PC relative branch fixup resulting in - R_MIPS_PC16. + fixup_Mips_PC16, + + // resulting in - R_MIPS_CALL16. + fixup_Mips_CALL16, + + // resulting in - R_MIPS_GPREL32. + fixup_Mips_GPREL32, + + // resulting in - R_MIPS_SHIFT5. + fixup_Mips_SHIFT5, + + // resulting in - R_MIPS_SHIFT6. + fixup_Mips_SHIFT6, + + // Pure 64 bit data fixup resulting in - R_MIPS_64. + fixup_Mips_64, + + // resulting in - R_MIPS_TLS_GD. + fixup_Mips_TLSGD, + + // resulting in - R_MIPS_TLS_GOTTPREL. + fixup_Mips_GOTTPREL, + + // resulting in - R_MIPS_TLS_TPREL_HI16. + fixup_Mips_TPREL_HI, + + // resulting in - R_MIPS_TLS_TPREL_LO16. + fixup_Mips_TPREL_LO, + + // resulting in - R_MIPS_TLS_LDM. + fixup_Mips_TLSLDM, + + // resulting in - R_MIPS_TLS_DTPREL_HI16. + fixup_Mips_DTPREL_HI, + + // resulting in - R_MIPS_TLS_DTPREL_LO16. + fixup_Mips_DTPREL_LO, + + // PC relative branch fixup resulting in - R_MIPS_PC16 + fixup_Mips_Branch_PCRel, + + // resulting in - R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_HI16 + fixup_Mips_GPOFF_HI, + + // resulting in - R_MIPS_GPREL16/R_MIPS_SUB/R_MIPS_LO16 + fixup_Mips_GPOFF_LO, + + // resulting in - R_MIPS_PAGE + fixup_Mips_GOT_PAGE, + + // resulting in - R_MIPS_GOT_OFST + fixup_Mips_GOT_OFST, + + // resulting in - R_MIPS_GOT_DISP + fixup_Mips_GOT_DISP, + + // resulting in - R_MIPS_GOT_HIGHER + fixup_Mips_HIGHER, + + // resulting in - R_MIPS_HIGHEST + fixup_Mips_HIGHEST, + + // resulting in - R_MIPS_GOT_HI16 + fixup_Mips_GOT_HI16, + + // resulting in - R_MIPS_GOT_LO16 + fixup_Mips_GOT_LO16, + + // resulting in - R_MIPS_CALL_HI16 + fixup_Mips_CALL_HI16, + + // resulting in - R_MIPS_CALL_LO16 + fixup_Mips_CALL_LO16, + + // resulting in - R_MICROMIPS_26_S1 + fixup_MICROMIPS_26_S1, + + // resulting in - R_MICROMIPS_HI16 + fixup_MICROMIPS_HI16, + + // resulting in - R_MICROMIPS_LO16 + fixup_MICROMIPS_LO16, + + // resulting in - R_MICROMIPS_GOT16 + fixup_MICROMIPS_GOT16, + + // resulting in - R_MICROMIPS_PC16_S1 + fixup_MICROMIPS_PC16_S1, + + // resulting in - R_MICROMIPS_CALL16 + fixup_MICROMIPS_CALL16, + + // resulting in - R_MICROMIPS_GOT_DISP + fixup_MICROMIPS_GOT_DISP, + + // resulting in - R_MICROMIPS_GOT_PAGE + fixup_MICROMIPS_GOT_PAGE, + + // resulting in - R_MICROMIPS_GOT_OFST + fixup_MICROMIPS_GOT_OFST, + + // resulting in - R_MICROMIPS_TLS_DTPREL_HI16 + fixup_MICROMIPS_TLS_DTPREL_HI16, + + // resulting in - R_MICROMIPS_TLS_DTPREL_LO16 + fixup_MICROMIPS_TLS_DTPREL_LO16, + + // resulting in - R_MICROMIPS_TLS_TPREL_HI16 + fixup_MICROMIPS_TLS_TPREL_HI16, + + // resulting in - R_MICROMIPS_TLS_TPREL_LO16 + fixup_MICROMIPS_TLS_TPREL_LO16, + + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind + }; +} // namespace Mips +} // namespace llvm + + +#endif // LLVM_MIPS_MIPSFIXUPKINDS_H diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp new file mode 100644 index 000000000000..6aa3c762d9db --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp @@ -0,0 +1,46 @@ +//===-- MipsMCAsmInfo.cpp - Mips 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 MipsMCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "MipsMCAsmInfo.h" +#include "llvm/ADT/Triple.h" + +using namespace llvm; + +void MipsMCAsmInfo::anchor() { } + +MipsMCAsmInfo::MipsMCAsmInfo(StringRef TT) { + Triple TheTriple(TT); + if ((TheTriple.getArch() == Triple::mips) || + (TheTriple.getArch() == Triple::mips64)) + IsLittleEndian = false; + + if ((TheTriple.getArch() == Triple::mips64el) || + (TheTriple.getArch() == Triple::mips64)) { + PointerSize = CalleeSaveStackSlotSize = 8; + } + + AlignmentIsInBytes = false; + Data16bitsDirective = "\t.2byte\t"; + Data32bitsDirective = "\t.4byte\t"; + Data64bitsDirective = "\t.8byte\t"; + PrivateGlobalPrefix = "$"; + CommentString = "#"; + ZeroDirective = "\t.space\t"; + GPRel32Directive = "\t.gpword\t"; + GPRel64Directive = "\t.gpdword\t"; + DebugLabelSuffix = "=."; + SupportsDebugInformation = true; + ExceptionsType = ExceptionHandling::DwarfCFI; + HasLEB128 = true; + DwarfRegNumForCFI = true; +} diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h new file mode 100644 index 000000000000..1000113351b4 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.h @@ -0,0 +1,30 @@ +//===-- MipsMCAsmInfo.h - Mips Asm 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 contains the declaration of the MipsMCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSTARGETASMINFO_H +#define MIPSTARGETASMINFO_H + +#include "llvm/MC/MCAsmInfoELF.h" + +namespace llvm { + class StringRef; + + class MipsMCAsmInfo : public MCAsmInfoELF { + virtual void anchor(); + public: + explicit MipsMCAsmInfo(StringRef TT); + }; + +} // namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp new file mode 100644 index 000000000000..66428bdfa747 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -0,0 +1,537 @@ +//===-- MipsMCCodeEmitter.cpp - Convert Mips 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 MipsMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// +// +#define DEBUG_TYPE "mccodeemitter" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MCTargetDesc/MipsFixupKinds.h" +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/raw_ostream.h" + +#define GET_INSTRMAP_INFO +#include "MipsGenInstrInfo.inc" + +using namespace llvm; + +namespace { +class MipsMCCodeEmitter : public MCCodeEmitter { + MipsMCCodeEmitter(const MipsMCCodeEmitter &) LLVM_DELETED_FUNCTION; + void operator=(const MipsMCCodeEmitter &) LLVM_DELETED_FUNCTION; + const MCInstrInfo &MCII; + MCContext &Ctx; + const MCSubtargetInfo &STI; + bool IsLittleEndian; + bool IsMicroMips; + +public: + MipsMCCodeEmitter(const MCInstrInfo &mcii, MCContext &Ctx_, + const MCSubtargetInfo &sti, bool IsLittle) : + MCII(mcii), Ctx(Ctx_), STI (sti), IsLittleEndian(IsLittle) { + IsMicroMips = STI.getFeatureBits() & Mips::FeatureMicroMips; + } + + ~MipsMCCodeEmitter() {} + + void EmitByte(unsigned char C, raw_ostream &OS) const { + OS << (char)C; + } + + void EmitInstruction(uint64_t Val, unsigned Size, raw_ostream &OS) const { + // Output the instruction encoding in little endian byte order. + // Little-endian byte ordering: + // mips32r2: 4 | 3 | 2 | 1 + // microMIPS: 2 | 1 | 4 | 3 + if (IsLittleEndian && Size == 4 && IsMicroMips) { + EmitInstruction(Val>>16, 2, OS); + EmitInstruction(Val, 2, OS); + } else { + for (unsigned i = 0; i < Size; ++i) { + unsigned Shift = IsLittleEndian ? i * 8 : (Size - 1 - i) * 8; + EmitByte((Val >> Shift) & 0xff, OS); + } + } + } + + void EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups) const; + + // getBinaryCodeForInstr - TableGen'erated function for getting the + // binary encoding for an instruction. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl<MCFixup> &Fixups) const; + + // getBranchJumpOpValue - Return binary encoding of the jump + // target operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getJumpTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + + // getBranchJumpOpValueMM - Return binary encoding of the microMIPS jump + // target operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getJumpTargetOpValueMM(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + + // getBranchTargetOpValue - Return binary encoding of the branch + // target operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + + // getBranchTargetOpValue - Return binary encoding of the microMIPS branch + // target operand. If the machine operand requires relocation, + // record the relocation and return zero. + unsigned getBranchTargetOpValueMM(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + + // getMachineOpValue - Return binary encoding of operand. If the machin + // operand requires relocation, record the relocation and return zero. + unsigned getMachineOpValue(const MCInst &MI,const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups) const; + + unsigned getMemEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + unsigned getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + unsigned getSizeExtEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + unsigned getSizeInsEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + + // getLSAImmEncoding - Return binary encoding of LSA immediate. + unsigned getLSAImmEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + + unsigned + getExprOpValue(const MCExpr *Expr,SmallVectorImpl<MCFixup> &Fixups) const; + +}; // class MipsMCCodeEmitter +} // namespace + +MCCodeEmitter *llvm::createMipsMCCodeEmitterEB(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI, + MCContext &Ctx) +{ + return new MipsMCCodeEmitter(MCII, Ctx, STI, false); +} + +MCCodeEmitter *llvm::createMipsMCCodeEmitterEL(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI, + MCContext &Ctx) +{ + return new MipsMCCodeEmitter(MCII, Ctx, STI, true); +} + + +// If the D<shift> instruction has a shift amount that is greater +// than 31 (checked in calling routine), lower it to a D<shift>32 instruction +static void LowerLargeShift(MCInst& Inst) { + + assert(Inst.getNumOperands() == 3 && "Invalid no. of operands for shift!"); + assert(Inst.getOperand(2).isImm()); + + int64_t Shift = Inst.getOperand(2).getImm(); + if (Shift <= 31) + return; // Do nothing + Shift -= 32; + + // saminus32 + Inst.getOperand(2).setImm(Shift); + + switch (Inst.getOpcode()) { + default: + // Calling function is not synchronized + llvm_unreachable("Unexpected shift instruction"); + case Mips::DSLL: + Inst.setOpcode(Mips::DSLL32); + return; + case Mips::DSRL: + Inst.setOpcode(Mips::DSRL32); + return; + case Mips::DSRA: + Inst.setOpcode(Mips::DSRA32); + return; + case Mips::DROTR: + Inst.setOpcode(Mips::DROTR32); + return; + } +} + +// Pick a DEXT or DINS instruction variant based on the pos and size operands +static void LowerDextDins(MCInst& InstIn) { + int Opcode = InstIn.getOpcode(); + + if (Opcode == Mips::DEXT) + assert(InstIn.getNumOperands() == 4 && + "Invalid no. of machine operands for DEXT!"); + else // Only DEXT and DINS are possible + assert(InstIn.getNumOperands() == 5 && + "Invalid no. of machine operands for DINS!"); + + assert(InstIn.getOperand(2).isImm()); + int64_t pos = InstIn.getOperand(2).getImm(); + assert(InstIn.getOperand(3).isImm()); + int64_t size = InstIn.getOperand(3).getImm(); + + if (size <= 32) { + if (pos < 32) // DEXT/DINS, do nothing + return; + // DEXTU/DINSU + InstIn.getOperand(2).setImm(pos - 32); + InstIn.setOpcode((Opcode == Mips::DEXT) ? Mips::DEXTU : Mips::DINSU); + return; + } + // DEXTM/DINSM + assert(pos < 32 && "DEXT/DINS cannot have both size and pos > 32"); + InstIn.getOperand(3).setImm(size - 32); + InstIn.setOpcode((Opcode == Mips::DEXT) ? Mips::DEXTM : Mips::DINSM); + return; +} + +/// EncodeInstruction - Emit the instruction. +/// Size the instruction with Desc.getSize(). +void MipsMCCodeEmitter:: +EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups) const +{ + + // Non-pseudo instructions that get changed for direct object + // only based on operand values. + // If this list of instructions get much longer we will move + // the check to a function call. Until then, this is more efficient. + MCInst TmpInst = MI; + switch (MI.getOpcode()) { + // If shift amount is >= 32 it the inst needs to be lowered further + case Mips::DSLL: + case Mips::DSRL: + case Mips::DSRA: + case Mips::DROTR: + LowerLargeShift(TmpInst); + break; + // Double extract instruction is chosen by pos and size operands + case Mips::DEXT: + case Mips::DINS: + LowerDextDins(TmpInst); + } + + unsigned long N = Fixups.size(); + uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups); + + // Check for unimplemented opcodes. + // Unfortunately in MIPS both NOP and SLL will come in with Binary == 0 + // so we have to special check for them. + unsigned Opcode = TmpInst.getOpcode(); + if ((Opcode != Mips::NOP) && (Opcode != Mips::SLL) && !Binary) + llvm_unreachable("unimplemented opcode in EncodeInstruction()"); + + if (STI.getFeatureBits() & Mips::FeatureMicroMips) { + int NewOpcode = Mips::Std2MicroMips (Opcode, Mips::Arch_micromips); + if (NewOpcode != -1) { + if (Fixups.size() > N) + Fixups.pop_back(); + Opcode = NewOpcode; + TmpInst.setOpcode (NewOpcode); + Binary = getBinaryCodeForInstr(TmpInst, Fixups); + } + } + + const MCInstrDesc &Desc = MCII.get(TmpInst.getOpcode()); + + // Get byte count of instruction + unsigned Size = Desc.getSize(); + if (!Size) + llvm_unreachable("Desc.getSize() returns 0"); + + EmitInstruction(Binary, Size, OS); +} + +/// getBranchTargetOpValue - Return binary encoding of the branch +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + + const MCOperand &MO = MI.getOperand(OpNo); + + // If the destination is an immediate, divide by 4. + if (MO.isImm()) return MO.getImm() >> 2; + + assert(MO.isExpr() && + "getBranchTargetOpValue expects only expressions or immediates"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips::fixup_Mips_PC16))); + return 0; +} + +/// getBranchTargetOpValue - Return binary encoding of the microMIPS branch +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getBranchTargetOpValueMM(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + + const MCOperand &MO = MI.getOperand(OpNo); + + // If the destination is an immediate, divide by 2. + if (MO.isImm()) return MO.getImm() >> 1; + + assert(MO.isExpr() && + "getBranchTargetOpValueMM expects only expressions or immediates"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips:: + fixup_MICROMIPS_PC16_S1))); + return 0; +} + +/// getJumpTargetOpValue - Return binary encoding of the jump +/// target operand. If the machine operand requires relocation, +/// record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getJumpTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + + const MCOperand &MO = MI.getOperand(OpNo); + // If the destination is an immediate, divide by 4. + if (MO.isImm()) return MO.getImm()>>2; + + assert(MO.isExpr() && + "getJumpTargetOpValue expects only expressions or an immediate"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips::fixup_Mips_26))); + return 0; +} + +unsigned MipsMCCodeEmitter:: +getJumpTargetOpValueMM(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + + const MCOperand &MO = MI.getOperand(OpNo); + // If the destination is an immediate, divide by 2. + if (MO.isImm()) return MO.getImm() >> 1; + + assert(MO.isExpr() && + "getJumpTargetOpValueMM expects only expressions or an immediate"); + + const MCExpr *Expr = MO.getExpr(); + Fixups.push_back(MCFixup::Create(0, Expr, + MCFixupKind(Mips::fixup_MICROMIPS_26_S1))); + return 0; +} + +unsigned MipsMCCodeEmitter:: +getExprOpValue(const MCExpr *Expr,SmallVectorImpl<MCFixup> &Fixups) const { + int64_t Res; + + if (Expr->EvaluateAsAbsolute(Res)) + return Res; + + MCExpr::ExprKind Kind = Expr->getKind(); + if (Kind == MCExpr::Constant) { + return cast<MCConstantExpr>(Expr)->getValue(); + } + + if (Kind == MCExpr::Binary) { + unsigned Res = getExprOpValue(cast<MCBinaryExpr>(Expr)->getLHS(), Fixups); + Res += getExprOpValue(cast<MCBinaryExpr>(Expr)->getRHS(), Fixups); + return Res; + } + if (Kind == MCExpr::SymbolRef) { + Mips::Fixups FixupKind = Mips::Fixups(0); + + switch(cast<MCSymbolRefExpr>(Expr)->getKind()) { + default: llvm_unreachable("Unknown fixup kind!"); + break; + case MCSymbolRefExpr::VK_Mips_GPOFF_HI : + FixupKind = Mips::fixup_Mips_GPOFF_HI; + break; + case MCSymbolRefExpr::VK_Mips_GPOFF_LO : + FixupKind = Mips::fixup_Mips_GPOFF_LO; + break; + case MCSymbolRefExpr::VK_Mips_GOT_PAGE : + FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_GOT_PAGE + : Mips::fixup_Mips_GOT_PAGE; + break; + case MCSymbolRefExpr::VK_Mips_GOT_OFST : + FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_GOT_OFST + : Mips::fixup_Mips_GOT_OFST; + break; + case MCSymbolRefExpr::VK_Mips_GOT_DISP : + FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_GOT_DISP + : Mips::fixup_Mips_GOT_DISP; + break; + case MCSymbolRefExpr::VK_Mips_GPREL: + FixupKind = Mips::fixup_Mips_GPREL16; + break; + case MCSymbolRefExpr::VK_Mips_GOT_CALL: + FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_CALL16 + : Mips::fixup_Mips_CALL16; + break; + case MCSymbolRefExpr::VK_Mips_GOT16: + FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_GOT16 + : Mips::fixup_Mips_GOT_Global; + break; + case MCSymbolRefExpr::VK_Mips_GOT: + FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_GOT16 + : Mips::fixup_Mips_GOT_Local; + break; + case MCSymbolRefExpr::VK_Mips_ABS_HI: + FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_HI16 + : Mips::fixup_Mips_HI16; + break; + case MCSymbolRefExpr::VK_Mips_ABS_LO: + FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_LO16 + : Mips::fixup_Mips_LO16; + break; + case MCSymbolRefExpr::VK_Mips_TLSGD: + FixupKind = Mips::fixup_Mips_TLSGD; + break; + case MCSymbolRefExpr::VK_Mips_TLSLDM: + FixupKind = Mips::fixup_Mips_TLSLDM; + break; + case MCSymbolRefExpr::VK_Mips_DTPREL_HI: + FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_TLS_DTPREL_HI16 + : Mips::fixup_Mips_DTPREL_HI; + break; + case MCSymbolRefExpr::VK_Mips_DTPREL_LO: + FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_TLS_DTPREL_LO16 + : Mips::fixup_Mips_DTPREL_LO; + break; + case MCSymbolRefExpr::VK_Mips_GOTTPREL: + FixupKind = Mips::fixup_Mips_GOTTPREL; + break; + case MCSymbolRefExpr::VK_Mips_TPREL_HI: + FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_TLS_TPREL_HI16 + : Mips::fixup_Mips_TPREL_HI; + break; + case MCSymbolRefExpr::VK_Mips_TPREL_LO: + FixupKind = IsMicroMips ? Mips::fixup_MICROMIPS_TLS_TPREL_LO16 + : Mips::fixup_Mips_TPREL_LO; + break; + case MCSymbolRefExpr::VK_Mips_HIGHER: + FixupKind = Mips::fixup_Mips_HIGHER; + break; + case MCSymbolRefExpr::VK_Mips_HIGHEST: + FixupKind = Mips::fixup_Mips_HIGHEST; + break; + case MCSymbolRefExpr::VK_Mips_GOT_HI16: + FixupKind = Mips::fixup_Mips_GOT_HI16; + break; + case MCSymbolRefExpr::VK_Mips_GOT_LO16: + FixupKind = Mips::fixup_Mips_GOT_LO16; + break; + case MCSymbolRefExpr::VK_Mips_CALL_HI16: + FixupKind = Mips::fixup_Mips_CALL_HI16; + break; + case MCSymbolRefExpr::VK_Mips_CALL_LO16: + FixupKind = Mips::fixup_Mips_CALL_LO16; + break; + } // switch + + Fixups.push_back(MCFixup::Create(0, Expr, MCFixupKind(FixupKind))); + return 0; + } + return 0; +} + +/// getMachineOpValue - Return binary encoding of operand. If the machine +/// operand requires relocation, record the relocation and return zero. +unsigned MipsMCCodeEmitter:: +getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups) const { + if (MO.isReg()) { + unsigned Reg = MO.getReg(); + unsigned RegNo = Ctx.getRegisterInfo()->getEncodingValue(Reg); + return RegNo; + } else if (MO.isImm()) { + return static_cast<unsigned>(MO.getImm()); + } else if (MO.isFPImm()) { + return static_cast<unsigned>(APFloat(MO.getFPImm()) + .bitcastToAPInt().getHiBits(32).getLimitedValue()); + } + // MO must be an Expr. + assert(MO.isExpr()); + return getExprOpValue(MO.getExpr(),Fixups); +} + +/// getMemEncoding - Return binary encoding of memory related operand. +/// If the offset operand requires relocation, record the relocation. +unsigned +MipsMCCodeEmitter::getMemEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + // Base register is encoded in bits 20-16, offset is encoded in bits 15-0. + assert(MI.getOperand(OpNo).isReg()); + unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo),Fixups) << 16; + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups); + + return (OffBits & 0xFFFF) | RegBits; +} + +unsigned MipsMCCodeEmitter:: +getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + // Base register is encoded in bits 20-16, offset is encoded in bits 11-0. + assert(MI.getOperand(OpNo).isReg()); + unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups) << 16; + unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups); + + return (OffBits & 0x0FFF) | RegBits; +} + +unsigned +MipsMCCodeEmitter::getSizeExtEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + assert(MI.getOperand(OpNo).isImm()); + unsigned SizeEncoding = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups); + return SizeEncoding - 1; +} + +// FIXME: should be called getMSBEncoding +// +unsigned +MipsMCCodeEmitter::getSizeInsEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + assert(MI.getOperand(OpNo-1).isImm()); + assert(MI.getOperand(OpNo).isImm()); + unsigned Position = getMachineOpValue(MI, MI.getOperand(OpNo-1), Fixups); + unsigned Size = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups); + + return Position + Size - 1; +} + +unsigned +MipsMCCodeEmitter::getLSAImmEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + assert(MI.getOperand(OpNo).isImm()); + // The immediate is encoded as 'immediate - 1'. + return getMachineOpValue(MI, MI.getOperand(OpNo), Fixups) - 1; +} + +#include "MipsGenMCCodeEmitter.inc" + diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp new file mode 100644 index 000000000000..5548aaa9a6d8 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp @@ -0,0 +1,234 @@ +//===-- MipsMCTargetDesc.cpp - Mips 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 Mips specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#include "MipsMCTargetDesc.h" +#include "InstPrinter/MipsInstPrinter.h" +#include "MipsMCAsmInfo.h" +#include "MipsTargetStreamer.h" +#include "llvm/MC/MCCodeGenInfo.h" +#include "llvm/MC/MCELF.h" +#include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MachineLocation.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/TargetRegistry.h" + +#define GET_INSTRINFO_MC_DESC +#include "MipsGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "MipsGenSubtargetInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "MipsGenRegisterInfo.inc" + +using namespace llvm; + +static std::string ParseMipsTriple(StringRef TT, StringRef CPU) { + std::string MipsArchFeature; + size_t DashPosition = 0; + StringRef TheTriple; + + // Let's see if there is a dash, like mips-unknown-linux. + DashPosition = TT.find('-'); + + if (DashPosition == StringRef::npos) { + // No dash, we check the string size. + TheTriple = TT.substr(0); + } else { + // We are only interested in substring before dash. + TheTriple = TT.substr(0,DashPosition); + } + + if (TheTriple == "mips" || TheTriple == "mipsel") { + if (CPU.empty() || CPU == "mips32") { + MipsArchFeature = "+mips32"; + } else if (CPU == "mips32r2") { + MipsArchFeature = "+mips32r2"; + } + } else { + if (CPU.empty() || CPU == "mips64") { + MipsArchFeature = "+mips64"; + } else if (CPU == "mips64r2") { + MipsArchFeature = "+mips64r2"; + } + } + return MipsArchFeature; +} + +static MCInstrInfo *createMipsMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitMipsMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createMipsMCRegisterInfo(StringRef TT) { + MCRegisterInfo *X = new MCRegisterInfo(); + InitMipsMCRegisterInfo(X, Mips::RA); + return X; +} + +static MCSubtargetInfo *createMipsMCSubtargetInfo(StringRef TT, StringRef CPU, + StringRef FS) { + std::string ArchFS = ParseMipsTriple(TT,CPU); + if (!FS.empty()) { + if (!ArchFS.empty()) + ArchFS = ArchFS + "," + FS.str(); + else + ArchFS = FS; + } + MCSubtargetInfo *X = new MCSubtargetInfo(); + InitMipsMCSubtargetInfo(X, TT, CPU, ArchFS); + return X; +} + +static MCAsmInfo *createMipsMCAsmInfo(const MCRegisterInfo &MRI, StringRef TT) { + MCAsmInfo *MAI = new MipsMCAsmInfo(TT); + + unsigned SP = MRI.getDwarfRegNum(Mips::SP, true); + MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(0, SP, 0); + MAI->addInitialFrameState(Inst); + + return MAI; +} + +static MCCodeGenInfo *createMipsMCCodeGenInfo(StringRef TT, Reloc::Model RM, + CodeModel::Model CM, + CodeGenOpt::Level OL) { + MCCodeGenInfo *X = new MCCodeGenInfo(); + if (CM == CodeModel::JITDefault) + RM = Reloc::Static; + else if (RM == Reloc::Default) + RM = Reloc::PIC_; + X->InitMCCodeGenInfo(RM, CM, OL); + return X; +} + +static MCInstPrinter *createMipsMCInstPrinter(const Target &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI) { + return new MipsInstPrinter(MAI, MII, MRI); +} + +static MCStreamer *createMCStreamer(const Target &T, StringRef TT, + MCContext &Context, MCAsmBackend &MAB, + raw_ostream &OS, MCCodeEmitter *Emitter, + bool RelaxAll, bool NoExecStack) { + MipsTargetELFStreamer *S = new MipsTargetELFStreamer(); + return createELFStreamer(Context, S, MAB, OS, Emitter, RelaxAll, NoExecStack); +} + +static MCStreamer * +createMCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS, + bool isVerboseAsm, bool useLoc, bool useCFI, + bool useDwarfDirectory, MCInstPrinter *InstPrint, + MCCodeEmitter *CE, MCAsmBackend *TAB, bool ShowInst) { + MipsTargetAsmStreamer *S = new MipsTargetAsmStreamer(OS); + + return llvm::createAsmStreamer(Ctx, S, OS, isVerboseAsm, useLoc, useCFI, + useDwarfDirectory, InstPrint, CE, TAB, + ShowInst); +} + +extern "C" void LLVMInitializeMipsTargetMC() { + // Register the MC asm info. + RegisterMCAsmInfoFn X(TheMipsTarget, createMipsMCAsmInfo); + RegisterMCAsmInfoFn Y(TheMipselTarget, createMipsMCAsmInfo); + RegisterMCAsmInfoFn A(TheMips64Target, createMipsMCAsmInfo); + RegisterMCAsmInfoFn B(TheMips64elTarget, createMipsMCAsmInfo); + + // Register the MC codegen info. + TargetRegistry::RegisterMCCodeGenInfo(TheMipsTarget, + createMipsMCCodeGenInfo); + TargetRegistry::RegisterMCCodeGenInfo(TheMipselTarget, + createMipsMCCodeGenInfo); + TargetRegistry::RegisterMCCodeGenInfo(TheMips64Target, + createMipsMCCodeGenInfo); + TargetRegistry::RegisterMCCodeGenInfo(TheMips64elTarget, + createMipsMCCodeGenInfo); + + // Register the MC instruction info. + TargetRegistry::RegisterMCInstrInfo(TheMipsTarget, createMipsMCInstrInfo); + TargetRegistry::RegisterMCInstrInfo(TheMipselTarget, createMipsMCInstrInfo); + TargetRegistry::RegisterMCInstrInfo(TheMips64Target, createMipsMCInstrInfo); + TargetRegistry::RegisterMCInstrInfo(TheMips64elTarget, + createMipsMCInstrInfo); + + // Register the MC register info. + TargetRegistry::RegisterMCRegInfo(TheMipsTarget, createMipsMCRegisterInfo); + TargetRegistry::RegisterMCRegInfo(TheMipselTarget, createMipsMCRegisterInfo); + TargetRegistry::RegisterMCRegInfo(TheMips64Target, createMipsMCRegisterInfo); + TargetRegistry::RegisterMCRegInfo(TheMips64elTarget, + createMipsMCRegisterInfo); + + // Register the MC Code Emitter + TargetRegistry::RegisterMCCodeEmitter(TheMipsTarget, + createMipsMCCodeEmitterEB); + TargetRegistry::RegisterMCCodeEmitter(TheMipselTarget, + createMipsMCCodeEmitterEL); + TargetRegistry::RegisterMCCodeEmitter(TheMips64Target, + createMipsMCCodeEmitterEB); + TargetRegistry::RegisterMCCodeEmitter(TheMips64elTarget, + createMipsMCCodeEmitterEL); + + // Register the object streamer. + TargetRegistry::RegisterMCObjectStreamer(TheMipsTarget, createMCStreamer); + TargetRegistry::RegisterMCObjectStreamer(TheMipselTarget, createMCStreamer); + TargetRegistry::RegisterMCObjectStreamer(TheMips64Target, createMCStreamer); + TargetRegistry::RegisterMCObjectStreamer(TheMips64elTarget, + createMCStreamer); + + // Register the asm streamer. + TargetRegistry::RegisterAsmStreamer(TheMipsTarget, createMCAsmStreamer); + TargetRegistry::RegisterAsmStreamer(TheMipselTarget, createMCAsmStreamer); + TargetRegistry::RegisterAsmStreamer(TheMips64Target, createMCAsmStreamer); + TargetRegistry::RegisterAsmStreamer(TheMips64elTarget, createMCAsmStreamer); + + // Register the asm backend. + TargetRegistry::RegisterMCAsmBackend(TheMipsTarget, + createMipsAsmBackendEB32); + TargetRegistry::RegisterMCAsmBackend(TheMipselTarget, + createMipsAsmBackendEL32); + TargetRegistry::RegisterMCAsmBackend(TheMips64Target, + createMipsAsmBackendEB64); + TargetRegistry::RegisterMCAsmBackend(TheMips64elTarget, + createMipsAsmBackendEL64); + + // Register the MC subtarget info. + TargetRegistry::RegisterMCSubtargetInfo(TheMipsTarget, + createMipsMCSubtargetInfo); + TargetRegistry::RegisterMCSubtargetInfo(TheMipselTarget, + createMipsMCSubtargetInfo); + TargetRegistry::RegisterMCSubtargetInfo(TheMips64Target, + createMipsMCSubtargetInfo); + TargetRegistry::RegisterMCSubtargetInfo(TheMips64elTarget, + createMipsMCSubtargetInfo); + + // Register the MCInstPrinter. + TargetRegistry::RegisterMCInstPrinter(TheMipsTarget, + createMipsMCInstPrinter); + TargetRegistry::RegisterMCInstPrinter(TheMipselTarget, + createMipsMCInstPrinter); + TargetRegistry::RegisterMCInstPrinter(TheMips64Target, + createMipsMCInstPrinter); + TargetRegistry::RegisterMCInstPrinter(TheMips64elTarget, + createMipsMCInstPrinter); +} diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h new file mode 100644 index 000000000000..eabebfe1349e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.h @@ -0,0 +1,72 @@ +//===-- MipsMCTargetDesc.h - Mips 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 Mips specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSMCTARGETDESC_H +#define MIPSMCTARGETDESC_H + +#include "llvm/Support/DataTypes.h" + +namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCObjectWriter; +class MCRegisterInfo; +class MCSubtargetInfo; +class StringRef; +class Target; +class raw_ostream; + +extern Target TheMipsTarget; +extern Target TheMipselTarget; +extern Target TheMips64Target; +extern Target TheMips64elTarget; + +MCCodeEmitter *createMipsMCCodeEmitterEB(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI, + MCContext &Ctx); +MCCodeEmitter *createMipsMCCodeEmitterEL(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI, + MCContext &Ctx); + +MCAsmBackend *createMipsAsmBackendEB32(const Target &T, const MCRegisterInfo &MRI, + StringRef TT, StringRef CPU); +MCAsmBackend *createMipsAsmBackendEL32(const Target &T, const MCRegisterInfo &MRI, + StringRef TT, StringRef CPU); +MCAsmBackend *createMipsAsmBackendEB64(const Target &T, const MCRegisterInfo &MRI, + StringRef TT, StringRef CPU); +MCAsmBackend *createMipsAsmBackendEL64(const Target &T, const MCRegisterInfo &MRI, + StringRef TT, StringRef CPU); + +MCObjectWriter *createMipsELFObjectWriter(raw_ostream &OS, + uint8_t OSABI, + bool IsLittleEndian, + bool Is64Bit); +} // End llvm namespace + +// Defines symbolic names for Mips registers. This defines a mapping from +// register name to register number. +#define GET_REGINFO_ENUM +#include "MipsGenRegisterInfo.inc" + +// Defines symbolic names for the Mips instructions. +#define GET_INSTRINFO_ENUM +#include "MipsGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "MipsGenSubtargetInfo.inc" + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsReginfo.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsReginfo.cpp new file mode 100644 index 000000000000..1dc9bcb36a5f --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsReginfo.cpp @@ -0,0 +1,80 @@ +//===-- MipsReginfo.cpp - Registerinfo handling --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// .reginfo +// Elf32_Word ri_gprmask +// Elf32_Word ri_cprmask[4] +// Elf32_Word ri_gp_value +// +// .MIPS.options - N64 +// Elf64_Byte kind (ODK_REGINFO) +// Elf64_Byte size (40 bytes) +// Elf64_Section section (0) +// Elf64_Word info (unused) +// Elf64_Word ri_gprmask () +// Elf64_Word ri_pad () +// Elf64_Word[4] ri_cprmask () +// Elf64_Addr ri_gp_value () +// +// .MIPS.options - N32 +// Elf32_Byte kind (ODK_REGINFO) +// Elf32_Byte size (36 bytes) +// Elf32_Section section (0) +// Elf32_Word info (unused) +// Elf32_Word ri_gprmask () +// Elf32_Word ri_pad () +// Elf32_Word[4] ri_cprmask () +// Elf32_Addr ri_gp_value () +// +//===----------------------------------------------------------------------===// +#include "MCTargetDesc/MipsReginfo.h" +#include "MipsSubtarget.h" +#include "MipsTargetObjectFile.h" +#include "llvm/MC/MCStreamer.h" + +using namespace llvm; + +// Integrated assembler version +void +MipsReginfo::emitMipsReginfoSectionCG(MCStreamer &OS, + const TargetLoweringObjectFile &TLOF, + const MipsSubtarget &MST) const +{ + + if (OS.hasRawTextSupport()) + return; + + const MipsTargetObjectFile &TLOFELF = + static_cast<const MipsTargetObjectFile &>(TLOF); + OS.SwitchSection(TLOFELF.getReginfoSection()); + + // .reginfo + if (MST.isABI_O32()) { + OS.EmitIntValue(0, 4); // ri_gprmask + OS.EmitIntValue(0, 4); // ri_cpr[0]mask + OS.EmitIntValue(0, 4); // ri_cpr[1]mask + OS.EmitIntValue(0, 4); // ri_cpr[2]mask + OS.EmitIntValue(0, 4); // ri_cpr[3]mask + OS.EmitIntValue(0, 4); // ri_gp_value + } + // .MIPS.options + else if (MST.isABI_N64()) { + OS.EmitIntValue(1, 1); // kind + OS.EmitIntValue(40, 1); // size + OS.EmitIntValue(0, 2); // section + OS.EmitIntValue(0, 4); // info + OS.EmitIntValue(0, 4); // ri_gprmask + OS.EmitIntValue(0, 4); // pad + OS.EmitIntValue(0, 4); // ri_cpr[0]mask + OS.EmitIntValue(0, 4); // ri_cpr[1]mask + OS.EmitIntValue(0, 4); // ri_cpr[2]mask + OS.EmitIntValue(0, 4); // ri_cpr[3]mask + OS.EmitIntValue(0, 8); // ri_gp_value + } + else llvm_unreachable("Unsupported abi for reginfo"); +} + diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsReginfo.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsReginfo.h new file mode 100644 index 000000000000..039b8eaaf287 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsReginfo.h @@ -0,0 +1,31 @@ +//=== MipsReginfo.h - MipsReginfo -----------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENCE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSREGINFO_H +#define MIPSREGINFO_H + +namespace llvm { + class MCStreamer; + class TargetLoweringObjectFile; + class MipsSubtarget; + + class MipsReginfo { + void anchor(); + public: + MipsReginfo() {} + + void emitMipsReginfoSectionCG(MCStreamer &OS, + const TargetLoweringObjectFile &TLOF, + const MipsSubtarget &MST) const; + }; + +} // namespace llvm + +#endif + diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp new file mode 100644 index 000000000000..5e90bbc635a5 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -0,0 +1,67 @@ +//===-- MipsTargetStreamer.cpp - Mips Target Streamer Methods -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Mips specific target streamer methods. +// +//===----------------------------------------------------------------------===// + +#include "MipsTargetStreamer.h" +#include "llvm/MC/MCELF.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" + +using namespace llvm; + +static cl::opt<bool> PrintHackDirectives("print-hack-directives", + cl::init(false), cl::Hidden); + +// pin vtable to this file +void MipsTargetStreamer::anchor() {} + +MipsTargetAsmStreamer::MipsTargetAsmStreamer(formatted_raw_ostream &OS) + : OS(OS) {} + +void MipsTargetAsmStreamer::emitMipsHackELFFlags(unsigned Flags) { + if (!PrintHackDirectives) + return; + + OS << "\t.mips_hack_elf_flags 0x"; + OS.write_hex(Flags); + OS << '\n'; +} +void MipsTargetAsmStreamer::emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val) { + if (!PrintHackDirectives) + return; + + OS << "\t.mips_hack_stocg "; + OS << Sym->getName(); + OS << ", "; + OS << Val; + OS << '\n'; +} + +MCELFStreamer &MipsTargetELFStreamer::getStreamer() { + return static_cast<MCELFStreamer &>(*Streamer); +} + +void MipsTargetELFStreamer::emitMipsHackELFFlags(unsigned Flags) { + MCAssembler &MCA = getStreamer().getAssembler(); + MCA.setELFHeaderEFlags(Flags); +} + +// Set a symbol's STO flags +void MipsTargetELFStreamer::emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val) { + MCSymbolData &Data = getStreamer().getOrCreateSymbolData(Sym); + // The "other" values are stored in the last 6 bits of the second byte + // The traditional defines for STO values assume the full byte and thus + // the shift to pack it. + MCELF::setOther(Data, Val >> 2); +} diff --git a/contrib/llvm/lib/Target/Mips/MSA.txt b/contrib/llvm/lib/Target/Mips/MSA.txt new file mode 100644 index 000000000000..d1c41932fcb5 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MSA.txt @@ -0,0 +1,78 @@ +Code Generation Notes for MSA +============================= + +Intrinsics are lowered to SelectionDAG nodes where possible in order to enable +optimisation, reduce the size of the ISel matcher, and reduce repetition in +the implementation. In a small number of cases, this can cause different +(semantically equivalent) instructions to be used in place of the requested +instruction, even when no optimisation has taken place. + +Instructions +============ + +This section describes any quirks of instruction selection for MSA. For +example, two instructions might be equally valid for some given IR and one is +chosen in preference to the other. + +bclri.b: + It is not possible to emit bclri.b since andi.b covers exactly the + same cases. andi.b should use fractionally less power than bclri.b in + most hardware implementations so it is used in preference to bclri.b. + +vshf.w: + It is not possible to emit vshf.w when the shuffle description is + constant since shf.w covers exactly the same cases. shf.w is used + instead. It is also impossible for the shuffle description to be + unknown at compile-time due to the definition of shufflevector in + LLVM IR. + +vshf.[bhwd] + When the shuffle description describes a splat operation, splat.[bhwd] + instructions will be selected instead of vshf.[bhwd]. Unlike the ilv*, + and pck* instructions, this is matched from MipsISD::VSHF instead of + a special-case MipsISD node. + +ilvl.d, pckev.d: + It is not possible to emit ilvl.d, or pckev.d since ilvev.d covers the + same shuffle. ilvev.d will be emitted instead. + +ilvr.d, ilvod.d, pckod.d: + It is not possible to emit ilvr.d, or pckod.d since ilvod.d covers the + same shuffle. ilvod.d will be emitted instead. + +splat.[bhwd] + The intrinsic will work as expected. However, unlike other intrinsics + it lowers directly to MipsISD::VSHF instead of using common IR. + +splati.w: + It is not possible to emit splati.w since shf.w covers the same cases. + shf.w will be emitted instead. + +copy_s.w: + On MIPS32, the copy_u.d intrinsic will emit this instruction instead of + copy_u.w. This is semantically equivalent since the general-purpose + register file is 32-bits wide. + +binsri.[bhwd], binsli.[bhwd]: + These two operations are equivalent to each other with the operands + swapped and condition inverted. The compiler may use either one as + appropriate. + Furthermore, the compiler may use bsel.[bhwd] for some masks that do + not survive the legalization process (this is a bug and will be fixed). + +bmnz.v, bmz.v, bsel.v: + These three operations differ only in the operand that is tied to the + result. + It is (currently) not possible to emit bmz.v, or bsel.v since bmnz.v is + the same operation and will be emitted instead. + In future, the compiler may choose between these three instructions + according to register allocation. + +bmnzi.b, bmzi.b: + Like their non-immediate counterparts, bmnzi.v and bmzi.v are the same + operation with the operands swapped. bmnzi.v will (currently) be emitted + for both cases. + +bseli.v: + Unlike the non-immediate versions, bseli.v is distinguishable from + bmnzi.b and bmzi.b and can be emitted. diff --git a/contrib/llvm/lib/Target/Mips/MicroMipsInstrFormats.td b/contrib/llvm/lib/Target/Mips/MicroMipsInstrFormats.td new file mode 100644 index 000000000000..c12a32e3d803 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MicroMipsInstrFormats.td @@ -0,0 +1,304 @@ +class MMArch { + string Arch = "micromips"; + list<dag> Pattern = []; +} + +class ADD_FM_MM<bits<6> op, bits<10> funct> : MMArch { + bits<5> rt; + bits<5> rs; + bits<5> rd; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = rd; + let Inst{10} = 0; + let Inst{9-0} = funct; +} + +class ADDI_FM_MM<bits<6> op> : MMArch { + bits<5> rs; + bits<5> rt; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-0} = imm16; +} + +class SLTI_FM_MM<bits<6> op> : MMArch { + bits<5> rt; + bits<5> rs; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-0} = imm16; +} + +class LUI_FM_MM : MMArch { + bits<5> rt; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = 0x10; + let Inst{25-21} = 0xd; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +class MULT_FM_MM<bits<10> funct> : MMArch { + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class SRA_FM_MM<bits<10> funct, bit rotate> : MMArch { + bits<5> rd; + bits<5> rt; + bits<5> shamt; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rd; + let Inst{20-16} = rt; + let Inst{15-11} = shamt; + let Inst{10} = rotate; + let Inst{9-0} = funct; +} + +class SRLV_FM_MM<bits<10> funct, bit rotate> : MMArch { + bits<5> rd; + bits<5> rt; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = rd; + let Inst{10} = rotate; + let Inst{9-0} = funct; +} + +class LW_FM_MM<bits<6> op> : MMArch { + bits<5> rt; + bits<21> addr; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = addr{20-16}; + let Inst{15-0} = addr{15-0}; +} + +class LWL_FM_MM<bits<4> funct> { + bits<5> rt; + bits<21> addr; + + bits<32> Inst; + + let Inst{31-26} = 0x18; + let Inst{25-21} = rt; + let Inst{20-16} = addr{20-16}; + let Inst{15-12} = funct; + let Inst{11-0} = addr{11-0}; +} + +class CMov_F_I_FM_MM<bits<7> func> : MMArch { + bits<5> rd; + bits<5> rs; + bits<3> fcc; + + bits<32> Inst; + + let Inst{31-26} = 0x15; + let Inst{25-21} = rd; + let Inst{20-16} = rs; + let Inst{15-13} = fcc; + let Inst{12-6} = func; + let Inst{5-0} = 0x3b; +} + +class MTLO_FM_MM<bits<10> funct> : MMArch { + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = 0x00; + let Inst{20-16} = rs; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class MFLO_FM_MM<bits<10> funct> : MMArch { + bits<5> rd; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = 0x00; + let Inst{20-16} = rd; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class CLO_FM_MM<bits<10> funct> : MMArch { + bits<5> rd; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = rd; + let Inst{20-16} = rs; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class SEB_FM_MM<bits<10> funct> : MMArch { + bits<5> rd; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = rd; + let Inst{20-16} = rt; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class EXT_FM_MM<bits<6> funct> : MMArch { + bits<5> rt; + bits<5> rs; + bits<5> pos; + bits<5> size; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-11} = size; + let Inst{10-6} = pos; + let Inst{5-0} = funct; +} + +class J_FM_MM<bits<6> op> : MMArch { + bits<26> target; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-0} = target; +} + +class JR_FM_MM<bits<8> funct> : MMArch { + bits<5> rs; + + bits<32> Inst; + + let Inst{31-21} = 0x00; + let Inst{20-16} = rs; + let Inst{15-14} = 0x0; + let Inst{13-6} = funct; + let Inst{5-0} = 0x3c; +} + +class JALR_FM_MM<bits<10> funct> : MMArch { + bits<5> rs; + bits<5> rd; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = rd; + let Inst{20-16} = rs; + let Inst{15-6} = funct; + let Inst{5-0} = 0x3c; +} + +class BEQ_FM_MM<bits<6> op> : MMArch { + bits<5> rs; + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-0} = offset; +} + +class BGEZ_FM_MM<bits<5> funct> : MMArch { + bits<5> rs; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = 0x10; + let Inst{25-21} = funct; + let Inst{20-16} = rs; + let Inst{15-0} = offset; +} + +class BGEZAL_FM_MM<bits<5> funct> : MMArch { + bits<5> rs; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = 0x10; + let Inst{25-21} = funct; + let Inst{20-16} = rs; + let Inst{15-0} = offset; +} + +class TEQ_FM_MM<bits<6> funct> : MMArch { + bits<5> rs; + bits<5> rt; + bits<4> code_; + + bits<32> Inst; + + let Inst{31-26} = 0x00; + let Inst{25-21} = rt; + let Inst{20-16} = rs; + let Inst{15-12} = code_; + let Inst{11-6} = funct; + let Inst{5-0} = 0x3c; +} + +class TEQI_FM_MM<bits<5> funct> : MMArch { + bits<5> rs; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = 0x10; + let Inst{25-21} = funct; + let Inst{20-16} = rs; + let Inst{15-0} = imm16; +} diff --git a/contrib/llvm/lib/Target/Mips/MicroMipsInstrInfo.td b/contrib/llvm/lib/Target/Mips/MicroMipsInstrInfo.td new file mode 100644 index 000000000000..d9507fa88ebc --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MicroMipsInstrInfo.td @@ -0,0 +1,219 @@ +def addrimm12 : ComplexPattern<iPTR, 2, "selectIntAddrMM", [frameindex]>; + +def simm12 : Operand<i32> { + let DecoderMethod = "DecodeSimm12"; +} + +def mem_mm_12 : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops GPR32, simm12); + let EncoderMethod = "getMemEncodingMMImm12"; + let ParserMatchClass = MipsMemAsmOperand; + let OperandType = "OPERAND_MEMORY"; +} + +def jmptarget_mm : Operand<OtherVT> { + let EncoderMethod = "getJumpTargetOpValueMM"; +} + +def calltarget_mm : Operand<iPTR> { + let EncoderMethod = "getJumpTargetOpValueMM"; +} + +def brtarget_mm : Operand<OtherVT> { + let EncoderMethod = "getBranchTargetOpValueMM"; + let OperandType = "OPERAND_PCREL"; + let DecoderMethod = "DecodeBranchTargetMM"; +} + +let canFoldAsLoad = 1 in +class LoadLeftRightMM<string opstr, SDNode OpNode, RegisterOperand RO, + Operand MemOpnd> : + InstSE<(outs RO:$rt), (ins MemOpnd:$addr, RO:$src), + !strconcat(opstr, "\t$rt, $addr"), + [(set RO:$rt, (OpNode addrimm12:$addr, RO:$src))], + NoItinerary, FrmI> { + let DecoderMethod = "DecodeMemMMImm12"; + string Constraints = "$src = $rt"; +} + +class StoreLeftRightMM<string opstr, SDNode OpNode, RegisterOperand RO, + Operand MemOpnd>: + InstSE<(outs), (ins RO:$rt, MemOpnd:$addr), + !strconcat(opstr, "\t$rt, $addr"), + [(OpNode RO:$rt, addrimm12:$addr)], NoItinerary, FrmI> { + let DecoderMethod = "DecodeMemMMImm12"; +} + +let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in { + /// Arithmetic Instructions (ALU Immediate) + def ADDiu_MM : MMRel, ArithLogicI<"addiu", simm16, GPR32Opnd>, + ADDI_FM_MM<0xc>; + def ADDi_MM : MMRel, ArithLogicI<"addi", simm16, GPR32Opnd>, + ADDI_FM_MM<0x4>; + def SLTi_MM : MMRel, SetCC_I<"slti", setlt, simm16, immSExt16, GPR32Opnd>, + SLTI_FM_MM<0x24>; + def SLTiu_MM : MMRel, SetCC_I<"sltiu", setult, simm16, immSExt16, GPR32Opnd>, + SLTI_FM_MM<0x2c>; + def ANDi_MM : MMRel, ArithLogicI<"andi", uimm16, GPR32Opnd>, + ADDI_FM_MM<0x34>; + def ORi_MM : MMRel, ArithLogicI<"ori", uimm16, GPR32Opnd>, + ADDI_FM_MM<0x14>; + def XORi_MM : MMRel, ArithLogicI<"xori", uimm16, GPR32Opnd>, + ADDI_FM_MM<0x1c>; + def LUi_MM : MMRel, LoadUpper<"lui", GPR32Opnd, uimm16>, LUI_FM_MM; + + /// Arithmetic Instructions (3-Operand, R-Type) + def ADDu_MM : MMRel, ArithLogicR<"addu", GPR32Opnd>, ADD_FM_MM<0, 0x150>; + def SUBu_MM : MMRel, ArithLogicR<"subu", GPR32Opnd>, ADD_FM_MM<0, 0x1d0>; + def MUL_MM : MMRel, ArithLogicR<"mul", GPR32Opnd>, ADD_FM_MM<0, 0x210>; + def ADD_MM : MMRel, ArithLogicR<"add", GPR32Opnd>, ADD_FM_MM<0, 0x110>; + def SUB_MM : MMRel, ArithLogicR<"sub", GPR32Opnd>, ADD_FM_MM<0, 0x190>; + def SLT_MM : MMRel, SetCC_R<"slt", setlt, GPR32Opnd>, ADD_FM_MM<0, 0x350>; + def SLTu_MM : MMRel, SetCC_R<"sltu", setult, GPR32Opnd>, + ADD_FM_MM<0, 0x390>; + def AND_MM : MMRel, ArithLogicR<"and", GPR32Opnd, 1, IIAlu, and>, + ADD_FM_MM<0, 0x250>; + def OR_MM : MMRel, ArithLogicR<"or", GPR32Opnd, 1, IIAlu, or>, + ADD_FM_MM<0, 0x290>; + def XOR_MM : MMRel, ArithLogicR<"xor", GPR32Opnd, 1, IIAlu, xor>, + ADD_FM_MM<0, 0x310>; + def NOR_MM : MMRel, LogicNOR<"nor", GPR32Opnd>, ADD_FM_MM<0, 0x2d0>; + def MULT_MM : MMRel, Mult<"mult", IIImul, GPR32Opnd, [HI0, LO0]>, + MULT_FM_MM<0x22c>; + def MULTu_MM : MMRel, Mult<"multu", IIImul, GPR32Opnd, [HI0, LO0]>, + MULT_FM_MM<0x26c>; + def SDIV_MM : MMRel, Div<"div", IIIdiv, GPR32Opnd, [HI0, LO0]>, + MULT_FM_MM<0x2ac>; + def UDIV_MM : MMRel, Div<"divu", IIIdiv, GPR32Opnd, [HI0, LO0]>, + MULT_FM_MM<0x2ec>; + + /// Shift Instructions + def SLL_MM : MMRel, shift_rotate_imm<"sll", uimm5, GPR32Opnd>, + SRA_FM_MM<0, 0>; + def SRL_MM : MMRel, shift_rotate_imm<"srl", uimm5, GPR32Opnd>, + SRA_FM_MM<0x40, 0>; + def SRA_MM : MMRel, shift_rotate_imm<"sra", uimm5, GPR32Opnd>, + SRA_FM_MM<0x80, 0>; + def SLLV_MM : MMRel, shift_rotate_reg<"sllv", GPR32Opnd>, + SRLV_FM_MM<0x10, 0>; + def SRLV_MM : MMRel, shift_rotate_reg<"srlv", GPR32Opnd>, + SRLV_FM_MM<0x50, 0>; + def SRAV_MM : MMRel, shift_rotate_reg<"srav", GPR32Opnd>, + SRLV_FM_MM<0x90, 0>; + def ROTR_MM : MMRel, shift_rotate_imm<"rotr", uimm5, GPR32Opnd>, + SRA_FM_MM<0xc0, 0>; + def ROTRV_MM : MMRel, shift_rotate_reg<"rotrv", GPR32Opnd>, + SRLV_FM_MM<0xd0, 0>; + + /// Load and Store Instructions - aligned + let DecoderMethod = "DecodeMemMMImm16" in { + def LB_MM : Load<"lb", GPR32Opnd>, MMRel, LW_FM_MM<0x7>; + def LBu_MM : Load<"lbu", GPR32Opnd>, MMRel, LW_FM_MM<0x5>; + def LH_MM : Load<"lh", GPR32Opnd>, MMRel, LW_FM_MM<0xf>; + def LHu_MM : Load<"lhu", GPR32Opnd>, MMRel, LW_FM_MM<0xd>; + def LW_MM : Load<"lw", GPR32Opnd>, MMRel, LW_FM_MM<0x3f>; + def SB_MM : Store<"sb", GPR32Opnd>, MMRel, LW_FM_MM<0x6>; + def SH_MM : Store<"sh", GPR32Opnd>, MMRel, LW_FM_MM<0xe>; + def SW_MM : Store<"sw", GPR32Opnd>, MMRel, LW_FM_MM<0x3e>; + } + + /// Load and Store Instructions - unaligned + def LWL_MM : LoadLeftRightMM<"lwl", MipsLWL, GPR32Opnd, mem_mm_12>, + LWL_FM_MM<0x0>; + def LWR_MM : LoadLeftRightMM<"lwr", MipsLWR, GPR32Opnd, mem_mm_12>, + LWL_FM_MM<0x1>; + def SWL_MM : StoreLeftRightMM<"swl", MipsSWL, GPR32Opnd, mem_mm_12>, + LWL_FM_MM<0x8>; + def SWR_MM : StoreLeftRightMM<"swr", MipsSWR, GPR32Opnd, mem_mm_12>, + LWL_FM_MM<0x9>; + + /// Move Conditional + def MOVZ_I_MM : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd, + NoItinerary>, ADD_FM_MM<0, 0x58>; + def MOVN_I_MM : MMRel, CMov_I_I_FT<"movn", GPR32Opnd, GPR32Opnd, + NoItinerary>, ADD_FM_MM<0, 0x18>; + def MOVT_I_MM : MMRel, CMov_F_I_FT<"movt", GPR32Opnd, IIAlu>, + CMov_F_I_FM_MM<0x25>; + def MOVF_I_MM : MMRel, CMov_F_I_FT<"movf", GPR32Opnd, IIAlu>, + CMov_F_I_FM_MM<0x5>; + + /// Move to/from HI/LO + def MTHI_MM : MMRel, MoveToLOHI<"mthi", GPR32Opnd, [HI0]>, + MTLO_FM_MM<0x0b5>; + def MTLO_MM : MMRel, MoveToLOHI<"mtlo", GPR32Opnd, [LO0]>, + MTLO_FM_MM<0x0f5>; + def MFHI_MM : MMRel, MoveFromLOHI<"mfhi", GPR32Opnd, AC0>, + MFLO_FM_MM<0x035>; + def MFLO_MM : MMRel, MoveFromLOHI<"mflo", GPR32Opnd, AC0>, + MFLO_FM_MM<0x075>; + + /// Multiply Add/Sub Instructions + def MADD_MM : MMRel, MArithR<"madd", 1>, MULT_FM_MM<0x32c>; + def MADDU_MM : MMRel, MArithR<"maddu", 1>, MULT_FM_MM<0x36c>; + def MSUB_MM : MMRel, MArithR<"msub">, MULT_FM_MM<0x3ac>; + def MSUBU_MM : MMRel, MArithR<"msubu">, MULT_FM_MM<0x3ec>; + + /// Count Leading + def CLZ_MM : MMRel, CountLeading0<"clz", GPR32Opnd>, CLO_FM_MM<0x16c>; + def CLO_MM : MMRel, CountLeading1<"clo", GPR32Opnd>, CLO_FM_MM<0x12c>; + + /// Sign Ext In Register Instructions. + def SEB_MM : MMRel, SignExtInReg<"seb", i8, GPR32Opnd>, SEB_FM_MM<0x0ac>; + def SEH_MM : MMRel, SignExtInReg<"seh", i16, GPR32Opnd>, SEB_FM_MM<0x0ec>; + + /// Word Swap Bytes Within Halfwords + def WSBH_MM : MMRel, SubwordSwap<"wsbh", GPR32Opnd>, SEB_FM_MM<0x1ec>; + + def EXT_MM : MMRel, ExtBase<"ext", GPR32Opnd, uimm5, MipsExt>, + EXT_FM_MM<0x2c>; + def INS_MM : MMRel, InsBase<"ins", GPR32Opnd, uimm5, MipsIns>, + EXT_FM_MM<0x0c>; + + /// Jump Instructions + let DecoderMethod = "DecodeJumpTargetMM" in { + def J_MM : MMRel, JumpFJ<jmptarget_mm, "j", br, bb, "j">, + J_FM_MM<0x35>; + def JAL_MM : MMRel, JumpLink<"jal", calltarget_mm>, J_FM_MM<0x3d>; + def TAILCALL_MM : MMRel, JumpFJ<calltarget_mm, "j", MipsTailCall, imm, + "tcall">, J_FM_MM<0x3d>, IsTailCall; + } + def JR_MM : MMRel, IndirectBranch<"jr", GPR32Opnd>, JR_FM_MM<0x3c>; + def JALR_MM : MMRel, JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM_MM<0x03c>; + def TAILCALL_R_MM : MMRel, JumpFR<"tcallr", GPR32Opnd, MipsTailCall>, + JR_FM_MM<0x3c>, IsTailCall; + def RET_MM : MMRel, RetBase<"ret", GPR32Opnd>, JR_FM_MM<0x3c>; + + /// Branch Instructions + def BEQ_MM : MMRel, CBranch<"beq", brtarget_mm, seteq, GPR32Opnd>, + BEQ_FM_MM<0x25>; + def BNE_MM : MMRel, CBranch<"bne", brtarget_mm, setne, GPR32Opnd>, + BEQ_FM_MM<0x2d>; + def BGEZ_MM : MMRel, CBranchZero<"bgez", brtarget_mm, setge, GPR32Opnd>, + BGEZ_FM_MM<0x2>; + def BGTZ_MM : MMRel, CBranchZero<"bgtz", brtarget_mm, setgt, GPR32Opnd>, + BGEZ_FM_MM<0x6>; + def BLEZ_MM : MMRel, CBranchZero<"blez", brtarget_mm, setle, GPR32Opnd>, + BGEZ_FM_MM<0x4>; + def BLTZ_MM : MMRel, CBranchZero<"bltz", brtarget_mm, setlt, GPR32Opnd>, + BGEZ_FM_MM<0x0>; + def BGEZAL_MM : MMRel, BGEZAL_FT<"bgezal", brtarget_mm, GPR32Opnd>, + BGEZAL_FM_MM<0x03>; + def BLTZAL_MM : MMRel, BGEZAL_FT<"bltzal", brtarget_mm, GPR32Opnd>, + BGEZAL_FM_MM<0x01>; + + /// Trap Instructions + def TEQ_MM : MMRel, TEQ_FT<"teq", GPR32Opnd>, TEQ_FM_MM<0x0>; + def TGE_MM : MMRel, TEQ_FT<"tge", GPR32Opnd>, TEQ_FM_MM<0x08>; + def TGEU_MM : MMRel, TEQ_FT<"tgeu", GPR32Opnd>, TEQ_FM_MM<0x10>; + def TLT_MM : MMRel, TEQ_FT<"tlt", GPR32Opnd>, TEQ_FM_MM<0x20>; + def TLTU_MM : MMRel, TEQ_FT<"tltu", GPR32Opnd>, TEQ_FM_MM<0x28>; + def TNE_MM : MMRel, TEQ_FT<"tne", GPR32Opnd>, TEQ_FM_MM<0x30>; + + def TEQI_MM : MMRel, TEQI_FT<"teqi", GPR32Opnd>, TEQI_FM_MM<0x0e>; + def TGEI_MM : MMRel, TEQI_FT<"tgei", GPR32Opnd>, TEQI_FM_MM<0x09>; + def TGEIU_MM : MMRel, TEQI_FT<"tgeiu", GPR32Opnd>, TEQI_FM_MM<0x0b>; + def TLTI_MM : MMRel, TEQI_FT<"tlti", GPR32Opnd>, TEQI_FM_MM<0x08>; + def TLTIU_MM : MMRel, TEQI_FT<"tltiu", GPR32Opnd>, TEQI_FM_MM<0x0a>; + def TNEI_MM : MMRel, TEQI_FT<"tnei", GPR32Opnd>, TEQI_FM_MM<0x0c>; +} diff --git a/contrib/llvm/lib/Target/Mips/Mips.h b/contrib/llvm/lib/Target/Mips/Mips.h new file mode 100644 index 000000000000..e796debd79b6 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips.h @@ -0,0 +1,33 @@ +//===-- Mips.h - Top-level interface for Mips representation ----*- 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 Mips back-end. +// +//===----------------------------------------------------------------------===// + +#ifndef TARGET_MIPS_H +#define TARGET_MIPS_H + +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + class MipsTargetMachine; + class FunctionPass; + + FunctionPass *createMipsISelDag(MipsTargetMachine &TM); + FunctionPass *createMipsDelaySlotFillerPass(MipsTargetMachine &TM); + FunctionPass *createMipsLongBranchPass(MipsTargetMachine &TM); + FunctionPass *createMipsJITCodeEmitterPass(MipsTargetMachine &TM, + JITCodeEmitter &JCE); + FunctionPass *createMipsConstantIslandPass(MipsTargetMachine &tm); +} // end namespace llvm; + +#endif diff --git a/contrib/llvm/lib/Target/Mips/Mips.td b/contrib/llvm/lib/Target/Mips/Mips.td new file mode 100644 index 000000000000..b8e3f39256da --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips.td @@ -0,0 +1,121 @@ +//===-- Mips.td - Describe the Mips 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 Mips target. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// Register File, Calling Conv, Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "MipsRegisterInfo.td" +include "MipsSchedule.td" +include "MipsInstrInfo.td" +include "MipsCallingConv.td" + +def MipsInstrInfo : InstrInfo; + +//===----------------------------------------------------------------------===// +// Mips Subtarget features // +//===----------------------------------------------------------------------===// + +def FeatureGP64Bit : SubtargetFeature<"gp64", "IsGP64bit", "true", + "General Purpose Registers are 64-bit wide.">; +def FeatureFP64Bit : SubtargetFeature<"fp64", "IsFP64bit", "true", + "Support 64-bit FP registers.">; +def FeatureSingleFloat : SubtargetFeature<"single-float", "IsSingleFloat", + "true", "Only supports single precision float">; +def FeatureO32 : SubtargetFeature<"o32", "MipsABI", "O32", + "Enable o32 ABI">; +def FeatureN32 : SubtargetFeature<"n32", "MipsABI", "N32", + "Enable n32 ABI">; +def FeatureN64 : SubtargetFeature<"n64", "MipsABI", "N64", + "Enable n64 ABI">; +def FeatureEABI : SubtargetFeature<"eabi", "MipsABI", "EABI", + "Enable eabi ABI">; +def FeatureVFPU : SubtargetFeature<"vfpu", "HasVFPU", + "true", "Enable vector FPU instructions.">; +def FeatureSEInReg : SubtargetFeature<"seinreg", "HasSEInReg", "true", + "Enable 'signext in register' instructions.">; +def FeatureCondMov : SubtargetFeature<"condmov", "HasCondMov", "true", + "Enable 'conditional move' instructions.">; +def FeatureSwap : SubtargetFeature<"swap", "HasSwap", "true", + "Enable 'byte/half swap' instructions.">; +def FeatureBitCount : SubtargetFeature<"bitcount", "HasBitCount", "true", + "Enable 'count leading bits' instructions.">; +def FeatureFPIdx : SubtargetFeature<"FPIdx", "HasFPIdx", "true", + "Enable 'FP indexed load/store' instructions.">; +def FeatureMips32 : SubtargetFeature<"mips32", "MipsArchVersion", "Mips32", + "Mips32 ISA Support", + [FeatureCondMov, FeatureBitCount]>; +def FeatureMips32r2 : SubtargetFeature<"mips32r2", "MipsArchVersion", + "Mips32r2", "Mips32r2 ISA Support", + [FeatureMips32, FeatureSEInReg, FeatureSwap, + FeatureFPIdx]>; +def FeatureMips64 : SubtargetFeature<"mips64", "MipsArchVersion", + "Mips64", "Mips64 ISA Support", + [FeatureGP64Bit, FeatureFP64Bit, + FeatureMips32, FeatureFPIdx]>; +def FeatureMips64r2 : SubtargetFeature<"mips64r2", "MipsArchVersion", + "Mips64r2", "Mips64r2 ISA Support", + [FeatureMips64, FeatureMips32r2]>; + +def FeatureMips16 : SubtargetFeature<"mips16", "InMips16Mode", "true", + "Mips16 mode">; + +def FeatureDSP : SubtargetFeature<"dsp", "HasDSP", "true", "Mips DSP ASE">; +def FeatureDSPR2 : SubtargetFeature<"dspr2", "HasDSPR2", "true", + "Mips DSP-R2 ASE", [FeatureDSP]>; + +def FeatureMSA : SubtargetFeature<"msa", "HasMSA", "true", "Mips MSA ASE">; + +def FeatureMicroMips : SubtargetFeature<"micromips", "InMicroMipsMode", "true", + "microMips mode">; + +//===----------------------------------------------------------------------===// +// Mips processors supported. +//===----------------------------------------------------------------------===// + +class Proc<string Name, list<SubtargetFeature> Features> + : Processor<Name, MipsGenericItineraries, Features>; + +def : Proc<"mips32", [FeatureMips32]>; +def : Proc<"mips32r2", [FeatureMips32r2]>; +def : Proc<"mips64", [FeatureMips64]>; +def : Proc<"mips64r2", [FeatureMips64r2]>; +def : Proc<"mips16", [FeatureMips16]>; + +def MipsAsmWriter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; + bit isMCAsmWriter = 1; +} + +def MipsAsmParser : AsmParser { + let ShouldEmitMatchRegisterName = 0; + let MnemonicContainsDot = 1; +} + +def MipsAsmParserVariant : AsmParserVariant { + int Variant = 0; + + // Recognize hard coded registers. + string RegisterPrefix = "$"; +} + +def Mips : Target { + let InstructionSet = MipsInstrInfo; + let AssemblyParsers = [MipsAsmParser]; + let AssemblyWriters = [MipsAsmWriter]; + let AssemblyParserVariants = [MipsAsmParserVariant]; +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.cpp b/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.cpp new file mode 100644 index 000000000000..6655ff98e033 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.cpp @@ -0,0 +1,180 @@ +//===-- Mips16FrameLowering.cpp - Mips16 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 Mips16 implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "Mips16FrameLowering.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "Mips16InstrInfo.h" +#include "MipsInstrInfo.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/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +void Mips16FrameLowering::emitPrologue(MachineFunction &MF) const { + MachineBasicBlock &MBB = MF.front(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const Mips16InstrInfo &TII = + *static_cast<const Mips16InstrInfo*>(MF.getTarget().getInstrInfo()); + MachineBasicBlock::iterator MBBI = MBB.begin(); + DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + uint64_t StackSize = MFI->getStackSize(); + + // No need to allocate space on the stack. + if (StackSize == 0 && !MFI->adjustsStack()) return; + + MachineModuleInfo &MMI = MF.getMMI(); + const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); + MachineLocation DstML, SrcML; + + // Adjust stack. + TII.makeFrame(Mips::SP, StackSize, MBB, MBBI); + + // emit ".cfi_def_cfa_offset StackSize" + MCSymbol *AdjustSPLabel = MMI.getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, + TII.get(TargetOpcode::PROLOG_LABEL)).addSym(AdjustSPLabel); + MMI.addFrameInst( + MCCFIInstruction::createDefCfaOffset(AdjustSPLabel, -StackSize)); + + MCSymbol *CSLabel = MMI.getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, + TII.get(TargetOpcode::PROLOG_LABEL)).addSym(CSLabel); + unsigned S2 = MRI->getDwarfRegNum(Mips::S2, true); + MMI.addFrameInst(MCCFIInstruction::createOffset(CSLabel, S2, -8)); + + unsigned S1 = MRI->getDwarfRegNum(Mips::S1, true); + MMI.addFrameInst(MCCFIInstruction::createOffset(CSLabel, S1, -12)); + + unsigned S0 = MRI->getDwarfRegNum(Mips::S0, true); + MMI.addFrameInst(MCCFIInstruction::createOffset(CSLabel, S0, -16)); + + unsigned RA = MRI->getDwarfRegNum(Mips::RA, true); + MMI.addFrameInst(MCCFIInstruction::createOffset(CSLabel, RA, -4)); + + if (hasFP(MF)) + BuildMI(MBB, MBBI, dl, TII.get(Mips::MoveR3216), Mips::S0) + .addReg(Mips::SP); + +} + +void Mips16FrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const Mips16InstrInfo &TII = + *static_cast<const Mips16InstrInfo*>(MF.getTarget().getInstrInfo()); + DebugLoc dl = MBBI->getDebugLoc(); + uint64_t StackSize = MFI->getStackSize(); + + if (!StackSize) + return; + + if (hasFP(MF)) + BuildMI(MBB, MBBI, dl, TII.get(Mips::Move32R16), Mips::SP) + .addReg(Mips::S0); + + // Adjust stack. + // assumes stacksize multiple of 8 + TII.restoreFrame(Mips::SP, StackSize, MBB, MBBI); +} + +bool Mips16FrameLowering:: +spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const { + MachineFunction *MF = MBB.getParent(); + MachineBasicBlock *EntryBlock = MF->begin(); + + // + // Registers RA, S0,S1 are the callee saved registers and they + // will be saved with the "save" instruction + // during emitPrologue + // + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + // Add the callee-saved register as live-in. Do not add if the register is + // RA and return address is taken, because it has already been added in + // method MipsTargetLowering::LowerRETURNADDR. + // It's killed at the spill, unless the register is RA and return address + // is taken. + unsigned Reg = CSI[i].getReg(); + bool IsRAAndRetAddrIsTaken = (Reg == Mips::RA) + && MF->getFrameInfo()->isReturnAddressTaken(); + if (!IsRAAndRetAddrIsTaken) + EntryBlock->addLiveIn(Reg); + } + + return true; +} + +bool Mips16FrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const { + // + // Registers RA,S0,S1 are the callee saved registers and they will be restored + // with the restore instruction during emitEpilogue. + // We need to override this virtual function, otherwise llvm will try and + // restore the registers on it's on from the stack. + // + + return true; +} + +// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions +void Mips16FrameLowering:: +eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + if (!hasReservedCallFrame(MF)) { + int64_t Amount = I->getOperand(0).getImm(); + + if (I->getOpcode() == Mips::ADJCALLSTACKDOWN) + Amount = -Amount; + + const Mips16InstrInfo &TII = + *static_cast<const Mips16InstrInfo*>(MF.getTarget().getInstrInfo()); + + TII.adjustStackPtr(Mips::SP, Amount, MBB, I); + } + + MBB.erase(I); +} + +bool +Mips16FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + // Reserve call frame if the size of the maximum call frame fits into 15-bit + // immediate field and there are no variable sized objects on the stack. + return isInt<15>(MFI->getMaxCallFrameSize()) && !MFI->hasVarSizedObjects(); +} + +void Mips16FrameLowering:: +processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const { + MF.getRegInfo().setPhysRegUsed(Mips::RA); + MF.getRegInfo().setPhysRegUsed(Mips::S0); + MF.getRegInfo().setPhysRegUsed(Mips::S1); + MF.getRegInfo().setPhysRegUsed(Mips::S2); +} + +const MipsFrameLowering * +llvm::createMips16FrameLowering(const MipsSubtarget &ST) { + return new Mips16FrameLowering(ST); +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.h b/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.h new file mode 100644 index 000000000000..8ce2ceda7c74 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16FrameLowering.h @@ -0,0 +1,52 @@ +//===-- Mips16FrameLowering.h - Mips16 frame lowering ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// +//===----------------------------------------------------------------------===// + +#ifndef MIPS16_FRAMEINFO_H +#define MIPS16_FRAMEINFO_H + +#include "MipsFrameLowering.h" + +namespace llvm { +class Mips16FrameLowering : public MipsFrameLowering { +public: + explicit Mips16FrameLowering(const MipsSubtarget &STI) + : MipsFrameLowering(STI, STI.stackAlignment()) {} + + /// emitProlog/emitEpilog - These methods insert prolog and epilog code into + /// the function. + void emitPrologue(MachineFunction &MF) const; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const; + + bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const; + + bool hasReservedCallFrame(const MachineFunction &MF) const; + + void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const; +}; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/Mips/Mips16HardFloat.cpp b/contrib/llvm/lib/Target/Mips/Mips16HardFloat.cpp new file mode 100644 index 000000000000..81bf18cd09d9 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16HardFloat.cpp @@ -0,0 +1,517 @@ +//===---- Mips16HardFloat.cpp for Mips16 Hard Float --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a pass needed for Mips16 Hard Float +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips16-hard-float" +#include "Mips16HardFloat.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <string> + +static void inlineAsmOut + (LLVMContext &C, StringRef AsmString, BasicBlock *BB ) { + std::vector<llvm::Type *> AsmArgTypes; + std::vector<llvm::Value*> AsmArgs; + llvm::FunctionType *AsmFTy = + llvm::FunctionType::get(Type::getVoidTy(C), + AsmArgTypes, false); + llvm::InlineAsm *IA = + llvm::InlineAsm::get(AsmFTy, AsmString, "", true, + /* IsAlignStack */ false, + llvm::InlineAsm::AD_ATT); + CallInst::Create(IA, AsmArgs, "", BB); +} + +namespace { + +class InlineAsmHelper { + LLVMContext &C; + BasicBlock *BB; +public: + InlineAsmHelper(LLVMContext &C_, BasicBlock *BB_) : + C(C_), BB(BB_) { + } + + void Out(StringRef AsmString) { + inlineAsmOut(C, AsmString, BB); + } + +}; +} +// +// Return types that matter for hard float are: +// float, double, complex float, and complex double +// +enum FPReturnVariant { + FRet, DRet, CFRet, CDRet, NoFPRet +}; + +// +// Determine which FP return type this function has +// +static FPReturnVariant whichFPReturnVariant(Type *T) { + switch (T->getTypeID()) { + case Type::FloatTyID: + return FRet; + case Type::DoubleTyID: + return DRet; + case Type::StructTyID: + if (T->getStructNumElements() != 2) + break; + if ((T->getContainedType(0)->isFloatTy()) && + (T->getContainedType(1)->isFloatTy())) + return CFRet; + if ((T->getContainedType(0)->isDoubleTy()) && + (T->getContainedType(1)->isDoubleTy())) + return CDRet; + break; + default: + break; + } + return NoFPRet; +} + +// +// Parameter type that matter are float, (float, float), (float, double), +// double, (double, double), (double, float) +// +enum FPParamVariant { + FSig, FFSig, FDSig, + DSig, DDSig, DFSig, NoSig +}; + +// which floating point parameter signature variant we are dealing with +// +typedef Type::TypeID TypeID; +const Type::TypeID FloatTyID = Type::FloatTyID; +const Type::TypeID DoubleTyID = Type::DoubleTyID; + +static FPParamVariant whichFPParamVariantNeeded(Function &F) { + switch (F.arg_size()) { + case 0: + return NoSig; + case 1:{ + TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID(); + switch (ArgTypeID) { + case FloatTyID: + return FSig; + case DoubleTyID: + return DSig; + default: + return NoSig; + } + } + default: { + TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID(); + TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID(); + switch(ArgTypeID0) { + case FloatTyID: { + switch (ArgTypeID1) { + case FloatTyID: + return FFSig; + case DoubleTyID: + return FDSig; + default: + return FSig; + } + } + case DoubleTyID: { + switch (ArgTypeID1) { + case FloatTyID: + return DFSig; + case DoubleTyID: + return DDSig; + default: + return DSig; + } + } + default: + return NoSig; + } + } + } + llvm_unreachable("can't get here"); +} + +// Figure out if we need float point based on the function parameters. +// We need to move variables in and/or out of floating point +// registers because of the ABI +// +static bool needsFPStubFromParams(Function &F) { + if (F.arg_size() >=1) { + Type *ArgType = F.getFunctionType()->getParamType(0); + switch (ArgType->getTypeID()) { + case Type::FloatTyID: + case Type::DoubleTyID: + return true; + default: + break; + } + } + return false; +} + +static bool needsFPReturnHelper(Function &F) { + Type* RetType = F.getReturnType(); + return whichFPReturnVariant(RetType) != NoFPRet; +} + +static bool needsFPHelperFromSig(Function &F) { + return needsFPStubFromParams(F) || needsFPReturnHelper(F); +} + +// +// We swap between FP and Integer registers to allow Mips16 and Mips32 to +// interoperate +// + +static void swapFPIntParams + (FPParamVariant PV, Module *M, InlineAsmHelper &IAH, + bool LE, bool ToFP) { + //LLVMContext &Context = M->getContext(); + std::string MI = ToFP? "mtc1 ": "mfc1 "; + switch (PV) { + case FSig: + IAH.Out(MI + "$$4,$$f12"); + break; + case FFSig: + IAH.Out(MI +"$$4,$$f12"); + IAH.Out(MI + "$$5,$$f14"); + break; + case FDSig: + IAH.Out(MI + "$$4,$$f12"); + if (LE) { + IAH.Out(MI + "$$6,$$f14"); + IAH.Out(MI + "$$7,$$f15"); + } else { + IAH.Out(MI + "$$7,$$f14"); + IAH.Out(MI + "$$6,$$f15"); + } + break; + case DSig: + if (LE) { + IAH.Out(MI + "$$4,$$f12"); + IAH.Out(MI + "$$5,$$f13"); + } else { + IAH.Out(MI + "$$5,$$f12"); + IAH.Out(MI + "$$4,$$f13"); + } + break; + case DDSig: + if (LE) { + IAH.Out(MI + "$$4,$$f12"); + IAH.Out(MI + "$$5,$$f13"); + IAH.Out(MI + "$$6,$$f14"); + IAH.Out(MI + "$$7,$$f15"); + } else { + IAH.Out(MI + "$$5,$$f12"); + IAH.Out(MI + "$$4,$$f13"); + IAH.Out(MI + "$$7,$$f14"); + IAH.Out(MI + "$$6,$$f15"); + } + break; + case DFSig: + if (LE) { + IAH.Out(MI + "$$4,$$f12"); + IAH.Out(MI + "$$5,$$f13"); + } else { + IAH.Out(MI + "$$5,$$f12"); + IAH.Out(MI + "$$4,$$f13"); + } + IAH.Out(MI + "$$6,$$f14"); + break; + case NoSig: + return; + } +} +// +// Make sure that we know we already need a stub for this function. +// Having called needsFPHelperFromSig +// +static void assureFPCallStub(Function &F, Module *M, + const MipsSubtarget &Subtarget){ + // for now we only need them for static relocation + if (Subtarget.getRelocationModel() == Reloc::PIC_) + return; + LLVMContext &Context = M->getContext(); + bool LE = Subtarget.isLittle(); + std::string Name = F.getName(); + std::string SectionName = ".mips16.call.fp." + Name; + std::string StubName = "__call_stub_fp_" + Name; + // + // see if we already have the stub + // + Function *FStub = M->getFunction(StubName); + if (FStub && !FStub->isDeclaration()) return; + FStub = Function::Create(F.getFunctionType(), + Function::InternalLinkage, StubName, M); + FStub->addFnAttr("mips16_fp_stub"); + FStub->addFnAttr(llvm::Attribute::Naked); + FStub->addFnAttr(llvm::Attribute::NoInline); + FStub->addFnAttr(llvm::Attribute::NoUnwind); + FStub->addFnAttr("nomips16"); + FStub->setSection(SectionName); + BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub); + InlineAsmHelper IAH(Context, BB); + IAH.Out(".set reorder"); + FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType()); + FPParamVariant PV = whichFPParamVariantNeeded(F); + swapFPIntParams(PV, M, IAH, LE, true); + if (RV != NoFPRet) { + IAH.Out("move $$18, $$31"); + IAH.Out("jal " + Name); + } else { + IAH.Out("lui $$25,%hi(" + Name + ")"); + IAH.Out("addiu $$25,$$25,%lo(" + Name + ")" ); + } + switch (RV) { + case FRet: + IAH.Out("mfc1 $$2,$$f0"); + break; + case DRet: + if (LE) { + IAH.Out("mfc1 $$2,$$f0"); + IAH.Out("mfc1 $$3,$$f1"); + } else { + IAH.Out("mfc1 $$3,$$f0"); + IAH.Out("mfc1 $$2,$$f1"); + } + break; + case CFRet: + if (LE) { + IAH.Out("mfc1 $$2,$$f0"); + IAH.Out("mfc1 $$3,$$f2"); + } else { + IAH.Out("mfc1 $$3,$$f0"); + IAH.Out("mfc1 $$3,$$f2"); + } + break; + case CDRet: + if (LE) { + IAH.Out("mfc1 $$4,$$f2"); + IAH.Out("mfc1 $$5,$$f3"); + IAH.Out("mfc1 $$2,$$f0"); + IAH.Out("mfc1 $$3,$$f1"); + + } else { + IAH.Out("mfc1 $$5,$$f2"); + IAH.Out("mfc1 $$4,$$f3"); + IAH.Out("mfc1 $$3,$$f0"); + IAH.Out("mfc1 $$2,$$f1"); + } + break; + case NoFPRet: + break; + } + if (RV != NoFPRet) + IAH.Out("jr $$18"); + else + IAH.Out("jr $$25"); + new UnreachableInst(Context, BB); +} + +// +// Functions that are llvm intrinsics and don't need helpers. +// +static const char *IntrinsicInline[] = + {"fabs", + "fabsf", + "llvm.ceil.f32", "llvm.ceil.f64", + "llvm.copysign.f32", "llvm.copysign.f64", + "llvm.cos.f32", "llvm.cos.f64", + "llvm.exp.f32", "llvm.exp.f64", + "llvm.exp2.f32", "llvm.exp2.f64", + "llvm.fabs.f32", "llvm.fabs.f64", + "llvm.floor.f32", "llvm.floor.f64", + "llvm.fma.f32", "llvm.fma.f64", + "llvm.log.f32", "llvm.log.f64", + "llvm.log10.f32", "llvm.log10.f64", + "llvm.nearbyint.f32", "llvm.nearbyint.f64", + "llvm.pow.f32", "llvm.pow.f64", + "llvm.powi.f32", "llvm.powi.f64", + "llvm.rint.f32", "llvm.rint.f64", + "llvm.round.f32", "llvm.round.f64", + "llvm.sin.f32", "llvm.sin.f64", + "llvm.sqrt.f32", "llvm.sqrt.f64", + "llvm.trunc.f32", "llvm.trunc.f64", + }; + +static bool isIntrinsicInline(Function *F) { + return std::binary_search( + IntrinsicInline, array_endof(IntrinsicInline), + F->getName()); +} +// +// Returns of float, double and complex need to be handled with a helper +// function. +// +static bool fixupFPReturnAndCall + (Function &F, Module *M, const MipsSubtarget &Subtarget) { + bool Modified = false; + LLVMContext &C = M->getContext(); + Type *MyVoid = Type::getVoidTy(C); + for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); + I != E; ++I) { + Instruction &Inst = *I; + if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) { + Value *RVal = RI->getReturnValue(); + if (!RVal) continue; + // + // If there is a return value and it needs a helper function, + // figure out which one and add a call before the actual + // return to this helper. The purpose of the helper is to move + // floating point values from their soft float return mapping to + // where they would have been mapped to in floating point registers. + // + Type *T = RVal->getType(); + FPReturnVariant RV = whichFPReturnVariant(T); + if (RV == NoFPRet) continue; + static const char* Helper[NoFPRet] = + {"__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc", + "__mips16_ret_dc"}; + const char *Name = Helper[RV]; + AttributeSet A; + Value *Params[] = {RVal}; + Modified = true; + // + // These helper functions have a different calling ABI so + // this __Mips16RetHelper indicates that so that later + // during call setup, the proper call lowering to the helper + // functions will take place. + // + A = A.addAttribute(C, AttributeSet::FunctionIndex, + "__Mips16RetHelper"); + A = A.addAttribute(C, AttributeSet::FunctionIndex, + Attribute::ReadNone); + A = A.addAttribute(C, AttributeSet::FunctionIndex, + Attribute::NoInline); + Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, NULL)); + CallInst::Create(F, Params, "", &Inst ); + } else if (const CallInst *CI = dyn_cast<CallInst>(I)) { + // pic mode calls are handled by already defined + // helper functions + if (Subtarget.getRelocationModel() != Reloc::PIC_ ) { + Function *F_ = CI->getCalledFunction(); + if (F_ && !isIntrinsicInline(F_) && needsFPHelperFromSig(*F_)) { + assureFPCallStub(*F_, M, Subtarget); + Modified=true; + } + } + } + } + return Modified; +} + +static void createFPFnStub(Function *F, Module *M, FPParamVariant PV, + const MipsSubtarget &Subtarget ) { + bool PicMode = Subtarget.getRelocationModel() == Reloc::PIC_; + bool LE = Subtarget.isLittle(); + LLVMContext &Context = M->getContext(); + std::string Name = F->getName(); + std::string SectionName = ".mips16.fn." + Name; + std::string StubName = "__fn_stub_" + Name; + std::string LocalName = "$$__fn_local_" + Name; + Function *FStub = Function::Create + (F->getFunctionType(), + Function::InternalLinkage, StubName, M); + FStub->addFnAttr("mips16_fp_stub"); + FStub->addFnAttr(llvm::Attribute::Naked); + FStub->addFnAttr(llvm::Attribute::NoUnwind); + FStub->addFnAttr(llvm::Attribute::NoInline); + FStub->addFnAttr("nomips16"); + FStub->setSection(SectionName); + BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub); + InlineAsmHelper IAH(Context, BB); + IAH.Out(" .set macro"); + if (PicMode) { + IAH.Out(".set noreorder"); + IAH.Out(".cpload $$25"); + IAH.Out(".set reorder"); + IAH.Out(".reloc 0,R_MIPS_NONE," + Name); + IAH.Out("la $$25," + LocalName); + } + else { + IAH.Out(".set reorder"); + IAH.Out("la $$25," + Name); + } + swapFPIntParams(PV, M, IAH, LE, false); + IAH.Out("jr $$25"); + IAH.Out(LocalName + " = " + Name); + new UnreachableInst(FStub->getContext(), BB); +} + +// +// remove the use-soft-float attribute +// +static void removeUseSoftFloat(Function &F) { + AttributeSet A; + DEBUG(errs() << "removing -use-soft-float\n"); + A = A.addAttribute(F.getContext(), AttributeSet::FunctionIndex, + "use-soft-float", "false"); + F.removeAttributes(AttributeSet::FunctionIndex, A); + if (F.hasFnAttribute("use-soft-float")) { + DEBUG(errs() << "still has -use-soft-float\n"); + } + F.addAttributes(AttributeSet::FunctionIndex, A); +} + +namespace llvm { + +// +// This pass only makes sense when the underlying chip has floating point but +// we are compiling as mips16. +// For all mips16 functions (that are not stubs we have already generated), or +// declared via attributes as nomips16, we must: +// 1) fixup all returns of float, double, single and double complex +// by calling a helper function before the actual return. +// 2) generate helper functions (stubs) that can be called by mips32 functions +// that will move parameters passed normally passed in floating point +// registers the soft float equivalents. +// 3) in the case of static relocation, generate helper functions so that +// mips16 functions can call extern functions of unknown type (mips16 or +// mips32). +// 4) TBD. For pic, calls to extern functions of unknown type are handled by +// predefined helper functions in libc but this work is currently done +// during call lowering but it should be moved here in the future. +// +bool Mips16HardFloat::runOnModule(Module &M) { + DEBUG(errs() << "Run on Module Mips16HardFloat\n"); + bool Modified = false; + for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { + if (F->hasFnAttribute("nomips16") && + F->hasFnAttribute("use-soft-float")) { + removeUseSoftFloat(*F); + continue; + } + if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") || + F->hasFnAttribute("nomips16")) continue; + Modified |= fixupFPReturnAndCall(*F, &M, Subtarget); + FPParamVariant V = whichFPParamVariantNeeded(*F); + if (V != NoSig) { + Modified = true; + createFPFnStub(F, &M, V, Subtarget); + } + } + return Modified; +} + +char Mips16HardFloat::ID = 0; + +} + +ModulePass *llvm::createMips16HardFloat(MipsTargetMachine &TM) { + return new Mips16HardFloat(TM); +} + diff --git a/contrib/llvm/lib/Target/Mips/Mips16HardFloat.h b/contrib/llvm/lib/Target/Mips/Mips16HardFloat.h new file mode 100644 index 000000000000..b7f712af5b28 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16HardFloat.h @@ -0,0 +1,54 @@ +//===---- Mips16HardFloat.h for Mips16 Hard Float --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a phase which implements part of the floating point +// interoperability between Mips16 and Mips32 code. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "MipsTargetMachine.h" +#include "llvm/Pass.h" +#include "llvm/Target/TargetMachine.h" + + +#ifndef MIPS16HARDFLOAT_H +#define MIPS16HARDFLOAT_H + +using namespace llvm; + +namespace llvm { + +class Mips16HardFloat : public ModulePass { + +public: + static char ID; + + Mips16HardFloat(MipsTargetMachine &TM_) : ModulePass(ID), + TM(TM_), Subtarget(TM.getSubtarget<MipsSubtarget>()) { + } + + virtual const char *getPassName() const { + return "MIPS16 Hard Float Pass"; + } + + virtual bool runOnModule(Module &M); + +protected: + /// Keep a pointer to the MipsSubtarget around so that we can make the right + /// decision when generating code for different targets. + const TargetMachine &TM; + const MipsSubtarget &Subtarget; + +}; + +ModulePass *createMips16HardFloat(MipsTargetMachine &TM); + +} +#endif diff --git a/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp new file mode 100644 index 000000000000..4948f40734c8 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp @@ -0,0 +1,316 @@ +//===-- Mips16ISelDAGToDAG.cpp - A Dag to Dag Inst Selector for Mips16 ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsDAGToDAGISel specialized for mips16. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-isel" +#include "Mips16ISelDAGToDAG.h" +#include "Mips.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsMachineFunction.h" +#include "MipsRegisterInfo.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/CFG.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +using namespace llvm; + +bool Mips16DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { + if (!Subtarget.inMips16Mode()) + return false; + return MipsDAGToDAGISel::runOnMachineFunction(MF); +} +/// Select multiply instructions. +std::pair<SDNode*, SDNode*> +Mips16DAGToDAGISel::selectMULT(SDNode *N, unsigned Opc, SDLoc DL, EVT Ty, + bool HasLo, bool HasHi) { + SDNode *Lo = 0, *Hi = 0; + SDNode *Mul = CurDAG->getMachineNode(Opc, DL, MVT::Glue, N->getOperand(0), + N->getOperand(1)); + SDValue InFlag = SDValue(Mul, 0); + + if (HasLo) { + unsigned Opcode = Mips::Mflo16; + Lo = CurDAG->getMachineNode(Opcode, DL, Ty, MVT::Glue, InFlag); + InFlag = SDValue(Lo, 1); + } + if (HasHi) { + unsigned Opcode = Mips::Mfhi16; + Hi = CurDAG->getMachineNode(Opcode, DL, Ty, InFlag); + } + return std::make_pair(Lo, Hi); +} + +void Mips16DAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + if (!MipsFI->globalBaseRegSet()) + return; + + MachineBasicBlock &MBB = MF.front(); + MachineBasicBlock::iterator I = MBB.begin(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + unsigned V0, V1, V2, GlobalBaseReg = MipsFI->getGlobalBaseReg(); + const TargetRegisterClass *RC = + (const TargetRegisterClass*)&Mips::CPU16RegsRegClass; + + V0 = RegInfo.createVirtualRegister(RC); + V1 = RegInfo.createVirtualRegister(RC); + V2 = RegInfo.createVirtualRegister(RC); + + BuildMI(MBB, I, DL, TII.get(Mips::GotPrologue16), V0). + addReg(V1, RegState::Define). + addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI). + addExternalSymbol("_gp_disp", MipsII::MO_ABS_LO); + + BuildMI(MBB, I, DL, TII.get(Mips::SllX16), V2).addReg(V0).addImm(16); + BuildMI(MBB, I, DL, TII.get(Mips::AdduRxRyRz16), GlobalBaseReg) + .addReg(V1).addReg(V2); +} + +// Insert instructions to initialize the Mips16 SP Alias register in the +// first MBB of the function. +// +void Mips16DAGToDAGISel::initMips16SPAliasReg(MachineFunction &MF) { + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + if (!MipsFI->mips16SPAliasRegSet()) + return; + + MachineBasicBlock &MBB = MF.front(); + MachineBasicBlock::iterator I = MBB.begin(); + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + unsigned Mips16SPAliasReg = MipsFI->getMips16SPAliasReg(); + + BuildMI(MBB, I, DL, TII.get(Mips::MoveR3216), Mips16SPAliasReg) + .addReg(Mips::SP); +} + +void Mips16DAGToDAGISel::processFunctionAfterISel(MachineFunction &MF) { + initGlobalBaseReg(MF); + initMips16SPAliasReg(MF); +} + +/// getMips16SPAliasReg - Output the instructions required to put the +/// SP into a Mips16 accessible aliased register. +SDValue Mips16DAGToDAGISel::getMips16SPAliasReg() { + unsigned Mips16SPAliasReg = + MF->getInfo<MipsFunctionInfo>()->getMips16SPAliasReg(); + return CurDAG->getRegister(Mips16SPAliasReg, + getTargetLowering()->getPointerTy()); +} + +void Mips16DAGToDAGISel::getMips16SPRefReg(SDNode *Parent, SDValue &AliasReg) { + SDValue AliasFPReg = CurDAG->getRegister(Mips::S0, + getTargetLowering()->getPointerTy()); + if (Parent) { + switch (Parent->getOpcode()) { + case ISD::LOAD: { + LoadSDNode *SD = dyn_cast<LoadSDNode>(Parent); + switch (SD->getMemoryVT().getSizeInBits()) { + case 8: + case 16: + AliasReg = TM.getFrameLowering()->hasFP(*MF)? + AliasFPReg: getMips16SPAliasReg(); + return; + } + break; + } + case ISD::STORE: { + StoreSDNode *SD = dyn_cast<StoreSDNode>(Parent); + switch (SD->getMemoryVT().getSizeInBits()) { + case 8: + case 16: + AliasReg = TM.getFrameLowering()->hasFP(*MF)? + AliasFPReg: getMips16SPAliasReg(); + return; + } + break; + } + } + } + AliasReg = CurDAG->getRegister(Mips::SP, getTargetLowering()->getPointerTy()); + return; + +} + +bool Mips16DAGToDAGISel::selectAddr16( + SDNode *Parent, SDValue Addr, SDValue &Base, SDValue &Offset, + SDValue &Alias) { + EVT ValTy = Addr.getValueType(); + + Alias = CurDAG->getTargetConstant(0, ValTy); + + // if Address is FI, get the TargetFrameIndex. + if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + Offset = CurDAG->getTargetConstant(0, ValTy); + getMips16SPRefReg(Parent, Alias); + return true; + } + // on PIC code Load GA + if (Addr.getOpcode() == MipsISD::Wrapper) { + Base = Addr.getOperand(0); + Offset = Addr.getOperand(1); + return true; + } + if (TM.getRelocationModel() != Reloc::PIC_) { + if ((Addr.getOpcode() == ISD::TargetExternalSymbol || + Addr.getOpcode() == ISD::TargetGlobalAddress)) + return false; + } + // Addresses of the form FI+const or FI|const + if (CurDAG->isBaseWithConstantOffset(Addr)) { + ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)); + if (isInt<16>(CN->getSExtValue())) { + + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode> + (Addr.getOperand(0))) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + getMips16SPRefReg(Parent, Alias); + } + else + Base = Addr.getOperand(0); + + Offset = CurDAG->getTargetConstant(CN->getZExtValue(), ValTy); + return true; + } + } + // Operand is a result from an ADD. + if (Addr.getOpcode() == ISD::ADD) { + // When loading from constant pools, load the lower address part in + // the instruction itself. Example, instead of: + // lui $2, %hi($CPI1_0) + // addiu $2, $2, %lo($CPI1_0) + // lwc1 $f0, 0($2) + // Generate: + // lui $2, %hi($CPI1_0) + // lwc1 $f0, %lo($CPI1_0)($2) + if (Addr.getOperand(1).getOpcode() == MipsISD::Lo || + Addr.getOperand(1).getOpcode() == MipsISD::GPRel) { + SDValue Opnd0 = Addr.getOperand(1).getOperand(0); + if (isa<ConstantPoolSDNode>(Opnd0) || isa<GlobalAddressSDNode>(Opnd0) || + isa<JumpTableSDNode>(Opnd0)) { + Base = Addr.getOperand(0); + Offset = Opnd0; + return true; + } + } + + // If an indexed floating point load/store can be emitted, return false. + const LSBaseSDNode *LS = dyn_cast<LSBaseSDNode>(Parent); + + if (LS && + (LS->getMemoryVT() == MVT::f32 || LS->getMemoryVT() == MVT::f64) && + Subtarget.hasFPIdx()) + return false; + } + Base = Addr; + Offset = CurDAG->getTargetConstant(0, ValTy); + return true; +} + +/// Select instructions not customized! Used for +/// expanded, promoted and normal instructions +std::pair<bool, SDNode*> Mips16DAGToDAGISel::selectNode(SDNode *Node) { + unsigned Opcode = Node->getOpcode(); + SDLoc DL(Node); + + /// + // Instruction Selection not handled by the auto-generated + // tablegen selection should be handled here. + /// + EVT NodeTy = Node->getValueType(0); + unsigned MultOpc; + + switch(Opcode) { + default: break; + + case ISD::SUBE: + case ISD::ADDE: { + SDValue InFlag = Node->getOperand(2), CmpLHS; + unsigned Opc = InFlag.getOpcode(); (void)Opc; + assert(((Opc == ISD::ADDC || Opc == ISD::ADDE) || + (Opc == ISD::SUBC || Opc == ISD::SUBE)) && + "(ADD|SUB)E flag operand must come from (ADD|SUB)C/E insn"); + + unsigned MOp; + if (Opcode == ISD::ADDE) { + CmpLHS = InFlag.getValue(0); + MOp = Mips::AdduRxRyRz16; + } else { + CmpLHS = InFlag.getOperand(0); + MOp = Mips::SubuRxRyRz16; + } + + SDValue Ops[] = { CmpLHS, InFlag.getOperand(1) }; + + SDValue LHS = Node->getOperand(0); + SDValue RHS = Node->getOperand(1); + + EVT VT = LHS.getValueType(); + + unsigned Sltu_op = Mips::SltuRxRyRz16; + SDNode *Carry = CurDAG->getMachineNode(Sltu_op, DL, VT, Ops); + unsigned Addu_op = Mips::AdduRxRyRz16; + SDNode *AddCarry = CurDAG->getMachineNode(Addu_op, DL, VT, + SDValue(Carry,0), RHS); + + SDNode *Result = CurDAG->SelectNodeTo(Node, MOp, VT, MVT::Glue, LHS, + SDValue(AddCarry,0)); + return std::make_pair(true, Result); + } + + /// Mul with two results + case ISD::SMUL_LOHI: + case ISD::UMUL_LOHI: { + MultOpc = (Opcode == ISD::UMUL_LOHI ? Mips::MultuRxRy16 : Mips::MultRxRy16); + std::pair<SDNode*, SDNode*> LoHi = selectMULT(Node, MultOpc, DL, NodeTy, + true, true); + if (!SDValue(Node, 0).use_empty()) + ReplaceUses(SDValue(Node, 0), SDValue(LoHi.first, 0)); + + if (!SDValue(Node, 1).use_empty()) + ReplaceUses(SDValue(Node, 1), SDValue(LoHi.second, 0)); + + return std::make_pair(true, (SDNode*)NULL); + } + + case ISD::MULHS: + case ISD::MULHU: { + MultOpc = (Opcode == ISD::MULHU ? Mips::MultuRxRy16 : Mips::MultRxRy16); + SDNode *Result = selectMULT(Node, MultOpc, DL, NodeTy, false, true).second; + return std::make_pair(true, Result); + } + } + + return std::make_pair(false, (SDNode*)NULL); +} + +FunctionPass *llvm::createMips16ISelDag(MipsTargetMachine &TM) { + return new Mips16DAGToDAGISel(TM); +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.h b/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.h new file mode 100644 index 000000000000..49dc6e587b62 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.h @@ -0,0 +1,53 @@ +//===---- Mips16ISelDAGToDAG.h - A Dag to Dag Inst Selector for Mips ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsDAGToDAGISel specialized for mips16. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPS16ISELDAGTODAG_H +#define MIPS16ISELDAGTODAG_H + +#include "MipsISelDAGToDAG.h" + +namespace llvm { + +class Mips16DAGToDAGISel : public MipsDAGToDAGISel { +public: + explicit Mips16DAGToDAGISel(MipsTargetMachine &TM) : MipsDAGToDAGISel(TM) {} + +private: + std::pair<SDNode*, SDNode*> selectMULT(SDNode *N, unsigned Opc, SDLoc DL, + EVT Ty, bool HasLo, bool HasHi); + + SDValue getMips16SPAliasReg(); + + virtual bool runOnMachineFunction(MachineFunction &MF); + + void getMips16SPRefReg(SDNode *Parent, SDValue &AliasReg); + + virtual bool selectAddr16(SDNode *Parent, SDValue N, SDValue &Base, + SDValue &Offset, SDValue &Alias); + + virtual std::pair<bool, SDNode*> selectNode(SDNode *Node); + + virtual void processFunctionAfterISel(MachineFunction &MF); + + // Insert instructions to initialize the global base register in the + // first MBB of the function. + void initGlobalBaseReg(MachineFunction &MF); + + void initMips16SPAliasReg(MachineFunction &MF); +}; + +FunctionPass *createMips16ISelDag(MipsTargetMachine &TM); + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/Mips16ISelLowering.cpp b/contrib/llvm/lib/Target/Mips/Mips16ISelLowering.cpp new file mode 100644 index 000000000000..61d8bb8e5582 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16ISelLowering.cpp @@ -0,0 +1,775 @@ +//===-- Mips16ISelLowering.h - Mips16 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. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsTargetLowering specialized for mips16. +// +//===----------------------------------------------------------------------===// +#define DEBUG_TYPE "mips-lower" +#include "Mips16ISelLowering.h" +#include "MipsRegisterInfo.h" +#include "MipsTargetMachine.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetInstrInfo.h" + +using namespace llvm; + +static cl::opt<bool> DontExpandCondPseudos16( + "mips16-dont-expand-cond-pseudo", + cl::init(false), + cl::desc("Dont expand conditional move related " + "pseudos for Mips 16"), + cl::Hidden); + +namespace { +struct Mips16Libcall { + RTLIB::Libcall Libcall; + const char *Name; + + bool operator<(const Mips16Libcall &RHS) const { + return std::strcmp(Name, RHS.Name) < 0; + } +}; + +struct Mips16IntrinsicHelperType{ + const char* Name; + const char* Helper; + + bool operator<(const Mips16IntrinsicHelperType &RHS) const { + return std::strcmp(Name, RHS.Name) < 0; + } + bool operator==(const Mips16IntrinsicHelperType &RHS) const { + return std::strcmp(Name, RHS.Name) == 0; + } +}; +} + +// Libcalls for which no helper is generated. Sorted by name for binary search. +static const Mips16Libcall HardFloatLibCalls[] = { + { RTLIB::ADD_F64, "__mips16_adddf3" }, + { RTLIB::ADD_F32, "__mips16_addsf3" }, + { RTLIB::DIV_F64, "__mips16_divdf3" }, + { RTLIB::DIV_F32, "__mips16_divsf3" }, + { RTLIB::OEQ_F64, "__mips16_eqdf2" }, + { RTLIB::OEQ_F32, "__mips16_eqsf2" }, + { RTLIB::FPEXT_F32_F64, "__mips16_extendsfdf2" }, + { RTLIB::FPTOSINT_F64_I32, "__mips16_fix_truncdfsi" }, + { RTLIB::FPTOSINT_F32_I32, "__mips16_fix_truncsfsi" }, + { RTLIB::SINTTOFP_I32_F64, "__mips16_floatsidf" }, + { RTLIB::SINTTOFP_I32_F32, "__mips16_floatsisf" }, + { RTLIB::UINTTOFP_I32_F64, "__mips16_floatunsidf" }, + { RTLIB::UINTTOFP_I32_F32, "__mips16_floatunsisf" }, + { RTLIB::OGE_F64, "__mips16_gedf2" }, + { RTLIB::OGE_F32, "__mips16_gesf2" }, + { RTLIB::OGT_F64, "__mips16_gtdf2" }, + { RTLIB::OGT_F32, "__mips16_gtsf2" }, + { RTLIB::OLE_F64, "__mips16_ledf2" }, + { RTLIB::OLE_F32, "__mips16_lesf2" }, + { RTLIB::OLT_F64, "__mips16_ltdf2" }, + { RTLIB::OLT_F32, "__mips16_ltsf2" }, + { RTLIB::MUL_F64, "__mips16_muldf3" }, + { RTLIB::MUL_F32, "__mips16_mulsf3" }, + { RTLIB::UNE_F64, "__mips16_nedf2" }, + { RTLIB::UNE_F32, "__mips16_nesf2" }, + { RTLIB::UNKNOWN_LIBCALL, "__mips16_ret_dc" }, // No associated libcall. + { RTLIB::UNKNOWN_LIBCALL, "__mips16_ret_df" }, // No associated libcall. + { RTLIB::UNKNOWN_LIBCALL, "__mips16_ret_sc" }, // No associated libcall. + { RTLIB::UNKNOWN_LIBCALL, "__mips16_ret_sf" }, // No associated libcall. + { RTLIB::SUB_F64, "__mips16_subdf3" }, + { RTLIB::SUB_F32, "__mips16_subsf3" }, + { RTLIB::FPROUND_F64_F32, "__mips16_truncdfsf2" }, + { RTLIB::UO_F64, "__mips16_unorddf2" }, + { RTLIB::UO_F32, "__mips16_unordsf2" } +}; + +static const Mips16IntrinsicHelperType Mips16IntrinsicHelper[] = { + {"__fixunsdfsi", "__mips16_call_stub_2" }, + {"ceil", "__mips16_call_stub_df_2"}, + {"ceilf", "__mips16_call_stub_sf_1"}, + {"copysign", "__mips16_call_stub_df_10"}, + {"copysignf", "__mips16_call_stub_sf_5"}, + {"cos", "__mips16_call_stub_df_2"}, + {"cosf", "__mips16_call_stub_sf_1"}, + {"exp2", "__mips16_call_stub_df_2"}, + {"exp2f", "__mips16_call_stub_sf_1"}, + {"floor", "__mips16_call_stub_df_2"}, + {"floorf", "__mips16_call_stub_sf_1"}, + {"log2", "__mips16_call_stub_df_2"}, + {"log2f", "__mips16_call_stub_sf_1"}, + {"nearbyint", "__mips16_call_stub_df_2"}, + {"nearbyintf", "__mips16_call_stub_sf_1"}, + {"rint", "__mips16_call_stub_df_2"}, + {"rintf", "__mips16_call_stub_sf_1"}, + {"sin", "__mips16_call_stub_df_2"}, + {"sinf", "__mips16_call_stub_sf_1"}, + {"sqrt", "__mips16_call_stub_df_2"}, + {"sqrtf", "__mips16_call_stub_sf_1"}, + {"trunc", "__mips16_call_stub_df_2"}, + {"truncf", "__mips16_call_stub_sf_1"}, +}; + +Mips16TargetLowering::Mips16TargetLowering(MipsTargetMachine &TM) + : MipsTargetLowering(TM) { + // + // set up as if mips32 and then revert so we can test the mechanism + // for switching + addRegisterClass(MVT::i32, &Mips::GPR32RegClass); + addRegisterClass(MVT::f32, &Mips::FGR32RegClass); + computeRegisterProperties(); + clearRegisterClasses(); + + // Set up the register classes + addRegisterClass(MVT::i32, &Mips::CPU16RegsRegClass); + + if (Subtarget->inMips16HardFloat()) + setMips16HardFloatLibCalls(); + + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand); + setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_SWAP, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_ADD, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_SUB, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_AND, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_OR, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_XOR, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_NAND, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_MIN, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_MAX, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_UMIN, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i32, Expand); + + setOperationAction(ISD::ROTR, MVT::i32, Expand); + setOperationAction(ISD::ROTR, MVT::i64, Expand); + setOperationAction(ISD::BSWAP, MVT::i32, Expand); + setOperationAction(ISD::BSWAP, MVT::i64, Expand); + + computeRegisterProperties(); +} + +const MipsTargetLowering * +llvm::createMips16TargetLowering(MipsTargetMachine &TM) { + return new Mips16TargetLowering(TM); +} + +bool +Mips16TargetLowering::allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const { + return false; +} + +MachineBasicBlock * +Mips16TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + switch (MI->getOpcode()) { + default: + return MipsTargetLowering::EmitInstrWithCustomInserter(MI, BB); + case Mips::SelBeqZ: + return emitSel16(Mips::BeqzRxImm16, MI, BB); + case Mips::SelBneZ: + return emitSel16(Mips::BnezRxImm16, MI, BB); + case Mips::SelTBteqZCmpi: + return emitSeliT16(Mips::Bteqz16, Mips::CmpiRxImmX16, MI, BB); + case Mips::SelTBteqZSlti: + return emitSeliT16(Mips::Bteqz16, Mips::SltiRxImmX16, MI, BB); + case Mips::SelTBteqZSltiu: + return emitSeliT16(Mips::Bteqz16, Mips::SltiuRxImmX16, MI, BB); + case Mips::SelTBtneZCmpi: + return emitSeliT16(Mips::Btnez16, Mips::CmpiRxImmX16, MI, BB); + case Mips::SelTBtneZSlti: + return emitSeliT16(Mips::Btnez16, Mips::SltiRxImmX16, MI, BB); + case Mips::SelTBtneZSltiu: + return emitSeliT16(Mips::Btnez16, Mips::SltiuRxImmX16, MI, BB); + case Mips::SelTBteqZCmp: + return emitSelT16(Mips::Bteqz16, Mips::CmpRxRy16, MI, BB); + case Mips::SelTBteqZSlt: + return emitSelT16(Mips::Bteqz16, Mips::SltRxRy16, MI, BB); + case Mips::SelTBteqZSltu: + return emitSelT16(Mips::Bteqz16, Mips::SltuRxRy16, MI, BB); + case Mips::SelTBtneZCmp: + return emitSelT16(Mips::Btnez16, Mips::CmpRxRy16, MI, BB); + case Mips::SelTBtneZSlt: + return emitSelT16(Mips::Btnez16, Mips::SltRxRy16, MI, BB); + case Mips::SelTBtneZSltu: + return emitSelT16(Mips::Btnez16, Mips::SltuRxRy16, MI, BB); + case Mips::BteqzT8CmpX16: + return emitFEXT_T8I816_ins(Mips::Bteqz16, Mips::CmpRxRy16, MI, BB); + case Mips::BteqzT8SltX16: + return emitFEXT_T8I816_ins(Mips::Bteqz16, Mips::SltRxRy16, MI, BB); + case Mips::BteqzT8SltuX16: + // TBD: figure out a way to get this or remove the instruction + // altogether. + return emitFEXT_T8I816_ins(Mips::Bteqz16, Mips::SltuRxRy16, MI, BB); + case Mips::BtnezT8CmpX16: + return emitFEXT_T8I816_ins(Mips::Btnez16, Mips::CmpRxRy16, MI, BB); + case Mips::BtnezT8SltX16: + return emitFEXT_T8I816_ins(Mips::Btnez16, Mips::SltRxRy16, MI, BB); + case Mips::BtnezT8SltuX16: + // TBD: figure out a way to get this or remove the instruction + // altogether. + return emitFEXT_T8I816_ins(Mips::Btnez16, Mips::SltuRxRy16, MI, BB); + case Mips::BteqzT8CmpiX16: return emitFEXT_T8I8I16_ins( + Mips::Bteqz16, Mips::CmpiRxImm16, Mips::CmpiRxImmX16, false, MI, BB); + case Mips::BteqzT8SltiX16: return emitFEXT_T8I8I16_ins( + Mips::Bteqz16, Mips::SltiRxImm16, Mips::SltiRxImmX16, true, MI, BB); + case Mips::BteqzT8SltiuX16: return emitFEXT_T8I8I16_ins( + Mips::Bteqz16, Mips::SltiuRxImm16, Mips::SltiuRxImmX16, false, MI, BB); + case Mips::BtnezT8CmpiX16: return emitFEXT_T8I8I16_ins( + Mips::Btnez16, Mips::CmpiRxImm16, Mips::CmpiRxImmX16, false, MI, BB); + case Mips::BtnezT8SltiX16: return emitFEXT_T8I8I16_ins( + Mips::Btnez16, Mips::SltiRxImm16, Mips::SltiRxImmX16, true, MI, BB); + case Mips::BtnezT8SltiuX16: return emitFEXT_T8I8I16_ins( + Mips::Btnez16, Mips::SltiuRxImm16, Mips::SltiuRxImmX16, false, MI, BB); + break; + case Mips::SltCCRxRy16: + return emitFEXT_CCRX16_ins(Mips::SltRxRy16, MI, BB); + break; + case Mips::SltiCCRxImmX16: + return emitFEXT_CCRXI16_ins + (Mips::SltiRxImm16, Mips::SltiRxImmX16, MI, BB); + case Mips::SltiuCCRxImmX16: + return emitFEXT_CCRXI16_ins + (Mips::SltiuRxImm16, Mips::SltiuRxImmX16, MI, BB); + case Mips::SltuCCRxRy16: + return emitFEXT_CCRX16_ins + (Mips::SltuRxRy16, MI, BB); + } +} + +bool Mips16TargetLowering:: +isEligibleForTailCallOptimization(const MipsCC &MipsCCInfo, + unsigned NextStackOffset, + const MipsFunctionInfo& FI) const { + // No tail call optimization for mips16. + return false; +} + +void Mips16TargetLowering::setMips16HardFloatLibCalls() { + for (unsigned I = 0; I != array_lengthof(HardFloatLibCalls); ++I) { + assert((I == 0 || HardFloatLibCalls[I - 1] < HardFloatLibCalls[I]) && + "Array not sorted!"); + if (HardFloatLibCalls[I].Libcall != RTLIB::UNKNOWN_LIBCALL) + setLibcallName(HardFloatLibCalls[I].Libcall, HardFloatLibCalls[I].Name); + } + + setLibcallName(RTLIB::O_F64, "__mips16_unorddf2"); + setLibcallName(RTLIB::O_F32, "__mips16_unordsf2"); +} + +// +// The Mips16 hard float is a crazy quilt inherited from gcc. I have a much +// cleaner way to do all of this but it will have to wait until the traditional +// gcc mechanism is completed. +// +// For Pic, in order for Mips16 code to call Mips32 code which according the abi +// have either arguments or returned values placed in floating point registers, +// we use a set of helper functions. (This includes functions which return type +// complex which on Mips are returned in a pair of floating point registers). +// +// This is an encoding that we inherited from gcc. +// In Mips traditional O32, N32 ABI, floating point numbers are passed in +// floating point argument registers 1,2 only when the first and optionally +// the second arguments are float (sf) or double (df). +// For Mips16 we are only concerned with the situations where floating point +// arguments are being passed in floating point registers by the ABI, because +// Mips16 mode code cannot execute floating point instructions to load those +// values and hence helper functions are needed. +// The possibilities are (), (sf), (sf, sf), (sf, df), (df), (df, sf), (df, df) +// the helper function suffixs for these are: +// 0, 1, 5, 9, 2, 6, 10 +// this suffix can then be calculated as follows: +// for a given argument Arg: +// Arg1x, Arg2x = 1 : Arg is sf +// 2 : Arg is df +// 0: Arg is neither sf or df +// So this stub is the string for number Arg1x + Arg2x*4. +// However not all numbers between 0 and 10 are possible, we check anyway and +// assert if the impossible exists. +// + +unsigned int Mips16TargetLowering::getMips16HelperFunctionStubNumber + (ArgListTy &Args) const { + unsigned int resultNum = 0; + if (Args.size() >= 1) { + Type *t = Args[0].Ty; + if (t->isFloatTy()) { + resultNum = 1; + } + else if (t->isDoubleTy()) { + resultNum = 2; + } + } + if (resultNum) { + if (Args.size() >=2) { + Type *t = Args[1].Ty; + if (t->isFloatTy()) { + resultNum += 4; + } + else if (t->isDoubleTy()) { + resultNum += 8; + } + } + } + return resultNum; +} + +// +// prefixs are attached to stub numbers depending on the return type . +// return type: float sf_ +// double df_ +// single complex sc_ +// double complext dc_ +// others NO PREFIX +// +// +// The full name of a helper function is__mips16_call_stub + +// return type dependent prefix + stub number +// +// +// This is something that probably should be in a different source file and +// perhaps done differently but my main purpose is to not waste runtime +// on something that we can enumerate in the source. Another possibility is +// to have a python script to generate these mapping tables. This will do +// for now. There are a whole series of helper function mapping arrays, one +// for each return type class as outlined above. There there are 11 possible +// entries. Ones with 0 are ones which should never be selected +// +// All the arrays are similar except for ones which return neither +// sf, df, sc, dc, in which only care about ones which have sf or df as a +// first parameter. +// +#define P_ "__mips16_call_stub_" +#define MAX_STUB_NUMBER 10 +#define T1 P "1", P "2", 0, 0, P "5", P "6", 0, 0, P "9", P "10" +#define T P "0" , T1 +#define P P_ +static char const * vMips16Helper[MAX_STUB_NUMBER+1] = + {0, T1 }; +#undef P +#define P P_ "sf_" +static char const * sfMips16Helper[MAX_STUB_NUMBER+1] = + { T }; +#undef P +#define P P_ "df_" +static char const * dfMips16Helper[MAX_STUB_NUMBER+1] = + { T }; +#undef P +#define P P_ "sc_" +static char const * scMips16Helper[MAX_STUB_NUMBER+1] = + { T }; +#undef P +#define P P_ "dc_" +static char const * dcMips16Helper[MAX_STUB_NUMBER+1] = + { T }; +#undef P +#undef P_ + + +const char* Mips16TargetLowering:: + getMips16HelperFunction + (Type* RetTy, ArgListTy &Args, bool &needHelper) const { + const unsigned int stubNum = getMips16HelperFunctionStubNumber(Args); +#ifndef NDEBUG + const unsigned int maxStubNum = 10; + assert(stubNum <= maxStubNum); + const bool validStubNum[maxStubNum+1] = + {true, true, true, false, false, true, true, false, false, true, true}; + assert(validStubNum[stubNum]); +#endif + const char *result; + if (RetTy->isFloatTy()) { + result = sfMips16Helper[stubNum]; + } + else if (RetTy ->isDoubleTy()) { + result = dfMips16Helper[stubNum]; + } + else if (RetTy->isStructTy()) { + // check if it's complex + if (RetTy->getNumContainedTypes() == 2) { + if ((RetTy->getContainedType(0)->isFloatTy()) && + (RetTy->getContainedType(1)->isFloatTy())) { + result = scMips16Helper[stubNum]; + } + else if ((RetTy->getContainedType(0)->isDoubleTy()) && + (RetTy->getContainedType(1)->isDoubleTy())) { + result = dcMips16Helper[stubNum]; + } + else { + llvm_unreachable("Uncovered condition"); + } + } + else { + llvm_unreachable("Uncovered condition"); + } + } + else { + if (stubNum == 0) { + needHelper = false; + return ""; + } + result = vMips16Helper[stubNum]; + } + needHelper = true; + return result; +} + +void Mips16TargetLowering:: +getOpndList(SmallVectorImpl<SDValue> &Ops, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage, + CallLoweringInfo &CLI, SDValue Callee, SDValue Chain) const { + SelectionDAG &DAG = CLI.DAG; + MachineFunction &MF = DAG.getMachineFunction(); + MipsFunctionInfo *FuncInfo = MF.getInfo<MipsFunctionInfo>(); + const char* Mips16HelperFunction = 0; + bool NeedMips16Helper = false; + + if (getTargetMachine().Options.UseSoftFloat && + Subtarget->inMips16HardFloat()) { + // + // currently we don't have symbols tagged with the mips16 or mips32 + // qualifier so we will assume that we don't know what kind it is. + // and generate the helper + // + bool LookupHelper = true; + if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(CLI.Callee)) { + Mips16Libcall Find = { RTLIB::UNKNOWN_LIBCALL, S->getSymbol() }; + + if (std::binary_search(HardFloatLibCalls, array_endof(HardFloatLibCalls), + Find)) + LookupHelper = false; + else { + Mips16IntrinsicHelperType IntrinsicFind = {S->getSymbol(), ""}; + // one more look at list of intrinsics + if (std::binary_search(Mips16IntrinsicHelper, + array_endof(Mips16IntrinsicHelper), + IntrinsicFind)) { + const Mips16IntrinsicHelperType *h =(std::find(Mips16IntrinsicHelper, + array_endof(Mips16IntrinsicHelper), + IntrinsicFind)); + Mips16HelperFunction = h->Helper; + NeedMips16Helper = true; + LookupHelper = false; + } + + } + } else if (GlobalAddressSDNode *G = + dyn_cast<GlobalAddressSDNode>(CLI.Callee)) { + Mips16Libcall Find = { RTLIB::UNKNOWN_LIBCALL, + G->getGlobal()->getName().data() }; + + if (std::binary_search(HardFloatLibCalls, array_endof(HardFloatLibCalls), + Find)) + LookupHelper = false; + } + if (LookupHelper) Mips16HelperFunction = + getMips16HelperFunction(CLI.RetTy, CLI.Args, NeedMips16Helper); + + } + + SDValue JumpTarget = Callee; + + // T9 should contain the address of the callee function if + // -reloction-model=pic or it is an indirect call. + if (IsPICCall || !GlobalOrExternal) { + unsigned V0Reg = Mips::V0; + if (NeedMips16Helper) { + RegsToPass.push_front(std::make_pair(V0Reg, Callee)); + JumpTarget = DAG.getExternalSymbol(Mips16HelperFunction, getPointerTy()); + ExternalSymbolSDNode *S = cast<ExternalSymbolSDNode>(JumpTarget); + JumpTarget = getAddrGlobal(S, JumpTarget.getValueType(), DAG, + MipsII::MO_GOT, Chain, + FuncInfo->callPtrInfo(S->getSymbol())); + } else + RegsToPass.push_front(std::make_pair((unsigned)Mips::T9, Callee)); + } + + Ops.push_back(JumpTarget); + + MipsTargetLowering::getOpndList(Ops, RegsToPass, IsPICCall, GlobalOrExternal, + InternalLinkage, CLI, Callee, Chain); +} + +MachineBasicBlock *Mips16TargetLowering:: +emitSel16(unsigned Opc, MachineInstr *MI, MachineBasicBlock *BB) const { + if (DontExpandCondPseudos16) + return BB; + 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 = BB->getBasicBlock(); + MachineFunction::iterator It = BB; + ++It; + + // thisMBB: + // ... + // TrueVal = ... + // setcc r1, r2, r3 + // bNE r1, r0, copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, copy0MBB); + F->insert(It, sinkMBB); + + // Transfer the remainder of BB and its successor edges to sinkMBB. + sinkMBB->splice(sinkMBB->begin(), BB, + llvm::next(MachineBasicBlock::iterator(MI)), + BB->end()); + sinkMBB->transferSuccessorsAndUpdatePHIs(BB); + + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(sinkMBB); + + BuildMI(BB, DL, TII->get(Opc)).addReg(MI->getOperand(3).getReg()) + .addMBB(sinkMBB); + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to sinkMBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ] + // ... + BB = sinkMBB; + + BuildMI(*BB, BB->begin(), DL, + TII->get(Mips::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +MachineBasicBlock *Mips16TargetLowering::emitSelT16 + (unsigned Opc1, unsigned Opc2, + MachineInstr *MI, MachineBasicBlock *BB) const { + if (DontExpandCondPseudos16) + return BB; + 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 = BB->getBasicBlock(); + MachineFunction::iterator It = BB; + ++It; + + // thisMBB: + // ... + // TrueVal = ... + // setcc r1, r2, r3 + // bNE r1, r0, copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, copy0MBB); + F->insert(It, sinkMBB); + + // Transfer the remainder of BB and its successor edges to sinkMBB. + sinkMBB->splice(sinkMBB->begin(), BB, + llvm::next(MachineBasicBlock::iterator(MI)), + BB->end()); + sinkMBB->transferSuccessorsAndUpdatePHIs(BB); + + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(sinkMBB); + + BuildMI(BB, DL, TII->get(Opc2)).addReg(MI->getOperand(3).getReg()) + .addReg(MI->getOperand(4).getReg()); + BuildMI(BB, DL, TII->get(Opc1)).addMBB(sinkMBB); + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to sinkMBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ] + // ... + BB = sinkMBB; + + BuildMI(*BB, BB->begin(), DL, + TII->get(Mips::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; + +} + +MachineBasicBlock *Mips16TargetLowering::emitSeliT16 + (unsigned Opc1, unsigned Opc2, + MachineInstr *MI, MachineBasicBlock *BB) const { + if (DontExpandCondPseudos16) + return BB; + 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 = BB->getBasicBlock(); + MachineFunction::iterator It = BB; + ++It; + + // thisMBB: + // ... + // TrueVal = ... + // setcc r1, r2, r3 + // bNE r1, r0, copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, copy0MBB); + F->insert(It, sinkMBB); + + // Transfer the remainder of BB and its successor edges to sinkMBB. + sinkMBB->splice(sinkMBB->begin(), BB, + llvm::next(MachineBasicBlock::iterator(MI)), + BB->end()); + sinkMBB->transferSuccessorsAndUpdatePHIs(BB); + + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(sinkMBB); + + BuildMI(BB, DL, TII->get(Opc2)).addReg(MI->getOperand(3).getReg()) + .addImm(MI->getOperand(4).getImm()); + BuildMI(BB, DL, TII->get(Opc1)).addMBB(sinkMBB); + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to sinkMBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ] + // ... + BB = sinkMBB; + + BuildMI(*BB, BB->begin(), DL, + TII->get(Mips::PHI), MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; + +} + +MachineBasicBlock + *Mips16TargetLowering::emitFEXT_T8I816_ins(unsigned BtOpc, unsigned CmpOpc, + MachineInstr *MI, + MachineBasicBlock *BB) const { + if (DontExpandCondPseudos16) + return BB; + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + unsigned regX = MI->getOperand(0).getReg(); + unsigned regY = MI->getOperand(1).getReg(); + MachineBasicBlock *target = MI->getOperand(2).getMBB(); + BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(CmpOpc)).addReg(regX) + .addReg(regY); + BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(BtOpc)).addMBB(target); + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +MachineBasicBlock *Mips16TargetLowering::emitFEXT_T8I8I16_ins( + unsigned BtOpc, unsigned CmpiOpc, unsigned CmpiXOpc, bool ImmSigned, + MachineInstr *MI, MachineBasicBlock *BB) const { + if (DontExpandCondPseudos16) + return BB; + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + unsigned regX = MI->getOperand(0).getReg(); + int64_t imm = MI->getOperand(1).getImm(); + MachineBasicBlock *target = MI->getOperand(2).getMBB(); + unsigned CmpOpc; + if (isUInt<8>(imm)) + CmpOpc = CmpiOpc; + else if ((!ImmSigned && isUInt<16>(imm)) || + (ImmSigned && isInt<16>(imm))) + CmpOpc = CmpiXOpc; + else + llvm_unreachable("immediate field not usable"); + BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(CmpOpc)).addReg(regX) + .addImm(imm); + BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(BtOpc)).addMBB(target); + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +static unsigned Mips16WhichOp8uOr16simm + (unsigned shortOp, unsigned longOp, int64_t Imm) { + if (isUInt<8>(Imm)) + return shortOp; + else if (isInt<16>(Imm)) + return longOp; + else + llvm_unreachable("immediate field not usable"); +} + +MachineBasicBlock *Mips16TargetLowering::emitFEXT_CCRX16_ins( + unsigned SltOpc, + MachineInstr *MI, MachineBasicBlock *BB) const { + if (DontExpandCondPseudos16) + return BB; + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + unsigned CC = MI->getOperand(0).getReg(); + unsigned regX = MI->getOperand(1).getReg(); + unsigned regY = MI->getOperand(2).getReg(); + BuildMI(*BB, MI, MI->getDebugLoc(), + TII->get(SltOpc)).addReg(regX).addReg(regY); + BuildMI(*BB, MI, MI->getDebugLoc(), + TII->get(Mips::MoveR3216), CC).addReg(Mips::T8); + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +MachineBasicBlock *Mips16TargetLowering::emitFEXT_CCRXI16_ins( + unsigned SltiOpc, unsigned SltiXOpc, + MachineInstr *MI, MachineBasicBlock *BB )const { + if (DontExpandCondPseudos16) + return BB; + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + unsigned CC = MI->getOperand(0).getReg(); + unsigned regX = MI->getOperand(1).getReg(); + int64_t Imm = MI->getOperand(2).getImm(); + unsigned SltOpc = Mips16WhichOp8uOr16simm(SltiOpc, SltiXOpc, Imm); + BuildMI(*BB, MI, MI->getDebugLoc(), + TII->get(SltOpc)).addReg(regX).addImm(Imm); + BuildMI(*BB, MI, MI->getDebugLoc(), + TII->get(Mips::MoveR3216), CC).addReg(Mips::T8); + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; + +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16ISelLowering.h b/contrib/llvm/lib/Target/Mips/Mips16ISelLowering.h new file mode 100644 index 000000000000..33b953f6ff39 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16ISelLowering.h @@ -0,0 +1,78 @@ +//===-- Mips16ISelLowering.h - Mips16 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. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsTargetLowering specialized for mips16. +// +//===----------------------------------------------------------------------===// + +#ifndef Mips16ISELLOWERING_H +#define Mips16ISELLOWERING_H + +#include "MipsISelLowering.h" + +namespace llvm { + class Mips16TargetLowering : public MipsTargetLowering { + public: + explicit Mips16TargetLowering(MipsTargetMachine &TM); + + virtual bool allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const; + + virtual MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const; + + private: + virtual bool + isEligibleForTailCallOptimization(const MipsCC &MipsCCInfo, + unsigned NextStackOffset, + const MipsFunctionInfo& FI) const; + + void setMips16HardFloatLibCalls(); + + unsigned int + getMips16HelperFunctionStubNumber(ArgListTy &Args) const; + + const char *getMips16HelperFunction + (Type* RetTy, ArgListTy &Args, bool &needHelper) const; + + virtual void + getOpndList(SmallVectorImpl<SDValue> &Ops, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage, + CallLoweringInfo &CLI, SDValue Callee, SDValue Chain) const; + + MachineBasicBlock *emitSel16(unsigned Opc, MachineInstr *MI, + MachineBasicBlock *BB) const; + + MachineBasicBlock *emitSeliT16(unsigned Opc1, unsigned Opc2, + MachineInstr *MI, + MachineBasicBlock *BB) const; + + MachineBasicBlock *emitSelT16(unsigned Opc1, unsigned Opc2, + MachineInstr *MI, + MachineBasicBlock *BB) const; + + MachineBasicBlock *emitFEXT_T8I816_ins(unsigned BtOpc, unsigned CmpOpc, + MachineInstr *MI, + MachineBasicBlock *BB) const; + + MachineBasicBlock *emitFEXT_T8I8I16_ins( + unsigned BtOpc, unsigned CmpiOpc, unsigned CmpiXOpc, bool ImmSigned, + MachineInstr *MI, MachineBasicBlock *BB) const; + + MachineBasicBlock *emitFEXT_CCRX16_ins( + unsigned SltOpc, + MachineInstr *MI, MachineBasicBlock *BB) const; + + MachineBasicBlock *emitFEXT_CCRXI16_ins( + unsigned SltiOpc, unsigned SltiXOpc, + MachineInstr *MI, MachineBasicBlock *BB )const; + }; +} + +#endif // Mips16ISELLOWERING_H diff --git a/contrib/llvm/lib/Target/Mips/Mips16InstrFormats.td b/contrib/llvm/lib/Target/Mips/Mips16InstrFormats.td new file mode 100644 index 000000000000..da3a1f114af3 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16InstrFormats.td @@ -0,0 +1,640 @@ +//===- Mips16InstrFormats.td - Mips Instruction Formats ----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Describe MIPS instructions format +// +// CPU INSTRUCTION FORMATS +// +// funct or f Function field +// +// immediate 4-,5-,8- or 11-bit immediate, branch displacement, or +// or imm address displacement +// +// op 5-bit major operation code +// +// rx 3-bit source or destination register +// +// ry 3-bit source or destination register +// +// rz 3-bit source or destination register +// +// sa 3- or 5-bit shift amount +// +//===----------------------------------------------------------------------===// + + +// Base class for Mips 16 Format +// This class does not depend on the instruction size +// +class MipsInst16_Base<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: Instruction +{ + + let Namespace = "Mips"; + + let OutOperandList = outs; + let InOperandList = ins; + + let AsmString = asmstr; + let Pattern = pattern; + let Itinerary = itin; + + let Predicates = [InMips16Mode]; +} + +// +// Generic Mips 16 Format +// +class MipsInst16<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: + MipsInst16_Base<outs, ins, asmstr, pattern, itin> +{ + field bits<16> Inst; + bits<5> Opcode = 0; + + // Top 5 bits are the 'opcode' field + let Inst{15-11} = Opcode; + + let Size=2; + field bits<16> SoftFail = 0; +} + +// +// For 32 bit extended instruction forms. +// +class MipsInst16_32<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: + MipsInst16_Base<outs, ins, asmstr, pattern, itin> +{ + field bits<32> Inst; + + let Size=4; + field bits<32> SoftFail = 0; +} + +class MipsInst16_EXTEND<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: + MipsInst16_32<outs, ins, asmstr, pattern, itin> +{ + let Inst{31-27} = 0b11110; +} + + + +// Mips Pseudo Instructions Format +class MipsPseudo16<dag outs, dag ins, string asmstr, list<dag> pattern>: + MipsInst16<outs, ins, asmstr, pattern, IIPseudo> { + let isCodeGenOnly = 1; + let isPseudo = 1; +} + + +//===----------------------------------------------------------------------===// +// Format I instruction class in Mips : <|opcode|imm11|> +//===----------------------------------------------------------------------===// + +class FI16<bits<5> op, dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<11> imm11; + + let Opcode = op; + + let Inst{10-0} = imm11; +} + +//===----------------------------------------------------------------------===// +// Format RI instruction class in Mips : <|opcode|rx|imm8|> +//===----------------------------------------------------------------------===// + +class FRI16<bits<5> op, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<8> imm8; + + let Opcode = op; + + let Inst{10-8} = rx; + let Inst{7-0} = imm8; +} + +//===----------------------------------------------------------------------===// +// Format RR instruction class in Mips : <|opcode|rx|ry|funct|> +//===----------------------------------------------------------------------===// + +class FRR16<bits<5> _funct, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<3> ry; + bits<5> funct; + + let Opcode = 0b11101; + let funct = _funct; + + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4-0} = funct; +} + +class FRRBreak16<dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<6> Code; + bits<5> funct; + + let Opcode = 0b11101; + let funct = 0b00101; + + let Inst{10-5} = Code; + let Inst{4-0} = funct; +} + +// +// For conversion functions. +// +class FRR_SF16<bits<5> _funct, bits<3> _subfunct, dag outs, dag ins, + string asmstr, list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<3> subfunct; + bits<5> funct; + + let Opcode = 0b11101; // RR + let funct = _funct; + let subfunct = _subfunct; + + let Inst{10-8} = rx; + let Inst{7-5} = subfunct; + let Inst{4-0} = funct; +} + +// +// just used for breakpoint (hardware and software) instructions. +// +class FC16<bits<5> _funct, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<6> _code; // code is a keyword in tablegen + bits<5> funct; + + let Opcode = 0b11101; // RR + let funct = _funct; + + let Inst{10-5} = _code; + let Inst{4-0} = funct; +} + +// +// J(AL)R(C) subformat +// +class FRR16_JALRC<bits<1> _nd, bits<1> _l, bits<1> r_a, + dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<1> nd; + bits<1> l; + bits<1> ra; + + let nd = _nd; + let l = _l; + let ra = r_a; + + let Opcode = 0b11101; + + let Inst{10-8} = rx; + let Inst{7} = nd; + let Inst{6} = l; + let Inst{5} = ra; + let Inst{4-0} = 0; +} + +//===----------------------------------------------------------------------===// +// Format RRI instruction class in Mips : <|opcode|rx|ry|imm5|> +//===----------------------------------------------------------------------===// + +class FRRI16<bits<5> op, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<3> ry; + bits<5> imm5; + + let Opcode = op; + + + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4-0} = imm5; +} + +//===----------------------------------------------------------------------===// +// Format RRR instruction class in Mips : <|opcode|rx|ry|rz|f|> +//===----------------------------------------------------------------------===// + +class FRRR16<bits<2> _f, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<3> ry; + bits<3> rz; + bits<2> f; + + let Opcode = 0b11100; + let f = _f; + + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4-2} = rz; + let Inst{1-0} = f; +} + +//===----------------------------------------------------------------------===// +// Format RRI-A instruction class in Mips : <|opcode|rx|ry|f|imm4|> +//===----------------------------------------------------------------------===// + +class FRRI_A16<bits<1> _f, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<3> ry; + bits<1> f; + bits<4> imm4; + + let Opcode = 0b01000; + let f = _f; + + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4} = f; + let Inst{3-0} = imm4; +} + +//===----------------------------------------------------------------------===// +// Format Shift instruction class in Mips : <|opcode|rx|ry|sa|f|> +//===----------------------------------------------------------------------===// + +class FSHIFT16<bits<2> _f, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> rx; + bits<3> ry; + bits<3> sa; + bits<2> f; + + let Opcode = 0b00110; + let f = _f; + + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4-2} = sa; + let Inst{1-0} = f; +} + +//===----------------------------------------------------------------------===// +// Format i8 instruction class in Mips : <|opcode|funct|imm8> +//===----------------------------------------------------------------------===// + +class FI816<bits<3> _func, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<3> func; + bits<8> imm8; + + let Opcode = 0b01100; + let func = _func; + + let Inst{10-8} = func; + let Inst{7-0} = imm8; +} + +//===----------------------------------------------------------------------===// +// Format i8_MOVR32 instruction class in Mips : <|opcode|func|ry|r32> +//===----------------------------------------------------------------------===// + +class FI8_MOVR3216<dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + + bits<4> ry; + bits<4> r32; + + let Opcode = 0b01100; + + let Inst{10-8} = 0b111; + let Inst{7-4} = ry; + let Inst{3-0} = r32; + +} + + + +//===----------------------------------------------------------------------===// +// Format i8_MOV32R instruction class in Mips : <|opcode|func|r32|rz> +//===----------------------------------------------------------------------===// + +class FI8_MOV32R16<dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + + bits<3> func; + bits<5> r32; + bits<3> rz; + + + let Opcode = 0b01100; + + let Inst{10-8} = 0b101; + let Inst{7-5} = r32{2-0}; + let Inst{4-3} = r32{4-3}; + let Inst{2-0} = rz; + +} + +//===----------------------------------------------------------------------===// +// Format i8_SVRS instruction class in Mips : +// <|opcode|svrs|s|ra|s0|s1|framesize> +//===----------------------------------------------------------------------===// + +class FI8_SVRS16<bits<1> _s, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16<outs, ins, asmstr, pattern, itin> +{ + bits<1> s; + bits<1> ra = 0; + bits<1> s0 = 0; + bits<1> s1 = 0; + bits<4> framesize = 0; + + let s =_s; + let Opcode = 0b01100; + + let Inst{10-8} = 0b100; + let Inst{7} = s; + let Inst{6} = ra; + let Inst{5} = s0; + let Inst{4} = s1; + let Inst{3-0} = framesize; + +} + +//===----------------------------------------------------------------------===// +// Format JAL instruction class in Mips16 : +// <|opcode|svrs|s|ra|s0|s1|framesize> +//===----------------------------------------------------------------------===// + +class FJAL16<bits<1> _X, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_32<outs, ins, asmstr, pattern, itin> +{ + bits<1> X; + bits<26> imm26; + + + let X = _X; + + let Inst{31-27} = 0b00011; + let Inst{26} = X; + let Inst{25-21} = imm26{20-16}; + let Inst{20-16} = imm26{25-21}; + let Inst{15-0} = imm26{15-0}; + +} + +//===----------------------------------------------------------------------===// +// Format EXT-I instruction class in Mips16 : +// <|EXTEND|imm10:5|imm15:11|op|0|0|0|0|0|0|imm4:0> +//===----------------------------------------------------------------------===// + +class FEXT_I16<bits<5> _eop, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<16> imm16; + bits<5> eop; + + let eop = _eop; + + let Inst{26-21} = imm16{10-5}; + let Inst{20-16} = imm16{15-11}; + let Inst{15-11} = eop; + let Inst{10-5} = 0; + let Inst{4-0} = imm16{4-0}; + +} + +//===----------------------------------------------------------------------===// +// Format ASMACRO instruction class in Mips16 : +// <EXTEND|select|p4|p3|RRR|p2|p1|p0> +//===----------------------------------------------------------------------===// + +class FASMACRO16<dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<3> select; + bits<3> p4; + bits<5> p3; + bits<5> RRR = 0b11100; + bits<3> p2; + bits<3> p1; + bits<5> p0; + + + let Inst{26-24} = select; + let Inst{23-21} = p4; + let Inst{20-16} = p3; + let Inst{15-11} = RRR; + let Inst{10-8} = p2; + let Inst{7-5} = p1; + let Inst{4-0} = p0; + +} + + +//===----------------------------------------------------------------------===// +// Format EXT-RI instruction class in Mips16 : +// <|EXTEND|imm10:5|imm15:11|op|rx|0|0|0|imm4:0> +//===----------------------------------------------------------------------===// + +class FEXT_RI16<bits<5> _op, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<16> imm16; + bits<5> op; + bits<3> rx; + + let op = _op; + + let Inst{26-21} = imm16{10-5}; + let Inst{20-16} = imm16{15-11}; + let Inst{15-11} = op; + let Inst{10-8} = rx; + let Inst{7-5} = 0; + let Inst{4-0} = imm16{4-0}; + +} + +//===----------------------------------------------------------------------===// +// Format EXT-RRI instruction class in Mips16 : +// <|EXTEND|imm10:5|imm15:11|op|rx|ry|imm4:0> +//===----------------------------------------------------------------------===// + +class FEXT_RRI16<bits<5> _op, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<5> op; + bits<16> imm16; + bits<3> rx; + bits<3> ry; + + let op=_op; + + let Inst{26-21} = imm16{10-5}; + let Inst{20-16} = imm16{15-11}; + let Inst{15-11} = op; + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4-0} = imm16{4-0}; + +} + +//===----------------------------------------------------------------------===// +// Format EXT-RRI-A instruction class in Mips16 : +// <|EXTEND|imm10:4|imm14:11|RRI-A|rx|ry|f|imm3:0> +//===----------------------------------------------------------------------===// + +class FEXT_RRI_A16<bits<1> _f, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<15> imm15; + bits<3> rx; + bits<3> ry; + bits<1> f; + + let f = _f; + + let Inst{26-20} = imm15{10-4}; + let Inst{19-16} = imm15{14-11}; + let Inst{15-11} = 0b01000; + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4} = f; + let Inst{3-0} = imm15{3-0}; + +} + +//===----------------------------------------------------------------------===// +// Format EXT-SHIFT instruction class in Mips16 : +// <|EXTEND|sa 4:0|s5|0|SHIFT|rx|ry|0|f> +//===----------------------------------------------------------------------===// + +class FEXT_SHIFT16<bits<2> _f, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<6> sa6; + bits<3> rx; + bits<3> ry; + bits<2> f; + + let f = _f; + + let Inst{26-22} = sa6{4-0}; + let Inst{21} = sa6{5}; + let Inst{20-16} = 0; + let Inst{15-11} = 0b00110; + let Inst{10-8} = rx; + let Inst{7-5} = ry; + let Inst{4-2} = 0; + let Inst{1-0} = f; + +} + +//===----------------------------------------------------------------------===// +// Format EXT-I8 instruction class in Mips16 : +// <|EXTEND|imm10:5|imm15:11|I8|funct|0|imm4:0> +//===----------------------------------------------------------------------===// + +class FEXT_I816<bits<3> _funct, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<16> imm16; + bits<5> I8; + bits<3> funct; + + let funct = _funct; + let I8 = 0b0110; + + let Inst{26-21} = imm16{10-5}; + let Inst{20-16} = imm16{15-11}; + let Inst{15-11} = I8; + let Inst{10-8} = funct; + let Inst{7-5} = 0; + let Inst{4-0} = imm16{4-0}; + +} + +//===----------------------------------------------------------------------===// +// Format EXT-I8_SVRS instruction class in Mips16 : +// <|EXTEND|xsregs|framesize7:4|aregs|I8|SVRS|s|ra|s0|s1|framesize3:0> +//===----------------------------------------------------------------------===// + +class FEXT_I8_SVRS16<bits<1> s_, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + MipsInst16_EXTEND<outs, ins, asmstr, pattern, itin> +{ + bits<3> xsregs =0; + bits<8> framesize =0; + bits<3> aregs =0; + bits<5> I8 = 0b01100; + bits<3> SVRS = 0b100; + bits<1> s; + bits<1> ra = 0; + bits<1> s0 = 0; + bits<1> s1 = 0; + + let s= s_; + + let Inst{26-24} = xsregs; + let Inst{23-20} = framesize{7-4}; + let Inst{19} = 0; + let Inst{18-16} = aregs; + let Inst{15-11} = I8; + let Inst{10-8} = SVRS; + let Inst{7} = s; + let Inst{6} = ra; + let Inst{5} = s0; + let Inst{4} = s1; + let Inst{3-0} = framesize{3-0}; + + +} + diff --git a/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.cpp b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.cpp new file mode 100644 index 000000000000..000ea2897f43 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.cpp @@ -0,0 +1,548 @@ +//===-- Mips16InstrInfo.cpp - Mips16 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 Mips16 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// +#include "Mips16InstrInfo.h" +#include "InstPrinter/MipsInstPrinter.h" +#include "MipsMachineFunction.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" +#include <cctype> + +using namespace llvm; + +static cl::opt<bool> NeverUseSaveRestore( + "mips16-never-use-save-restore", + cl::init(false), + cl::desc("For testing ability to adjust stack pointer " + "without save/restore instruction"), + cl::Hidden); + + +Mips16InstrInfo::Mips16InstrInfo(MipsTargetMachine &tm) + : MipsInstrInfo(tm, Mips::Bimm16), + RI(*tm.getSubtargetImpl()) {} + +const MipsRegisterInfo &Mips16InstrInfo::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. +unsigned Mips16InstrInfo:: +isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const +{ + 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 Mips16InstrInfo:: +isStoreToStackSlot(const MachineInstr *MI, int &FrameIndex) const +{ + return 0; +} + +void Mips16InstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const { + unsigned Opc = 0; + + if (Mips::CPU16RegsRegClass.contains(DestReg) && + Mips::GPR32RegClass.contains(SrcReg)) + Opc = Mips::MoveR3216; + else if (Mips::GPR32RegClass.contains(DestReg) && + Mips::CPU16RegsRegClass.contains(SrcReg)) + Opc = Mips::Move32R16; + else if ((SrcReg == Mips::HI0) && + (Mips::CPU16RegsRegClass.contains(DestReg))) + Opc = Mips::Mfhi16, SrcReg = 0; + + else if ((SrcReg == Mips::LO0) && + (Mips::CPU16RegsRegClass.contains(DestReg))) + Opc = Mips::Mflo16, SrcReg = 0; + + + assert(Opc && "Cannot copy registers"); + + MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(Opc)); + + if (DestReg) + MIB.addReg(DestReg, RegState::Define); + + if (SrcReg) + MIB.addReg(SrcReg, getKillRegState(KillSrc)); +} + +void Mips16InstrInfo:: +storeRegToStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned SrcReg, bool isKill, int FI, + const TargetRegisterClass *RC, const TargetRegisterInfo *TRI, + int64_t Offset) const { + DebugLoc DL; + if (I != MBB.end()) DL = I->getDebugLoc(); + MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOStore); + unsigned Opc = 0; + if (Mips::CPU16RegsRegClass.hasSubClassEq(RC)) + Opc = Mips::SwRxSpImmX16; + assert(Opc && "Register class not handled!"); + BuildMI(MBB, I, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill)). + addFrameIndex(FI).addImm(Offset) + .addMemOperand(MMO); +} + +void Mips16InstrInfo:: +loadRegFromStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned DestReg, int FI, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, int64_t Offset) const { + DebugLoc DL; + if (I != MBB.end()) DL = I->getDebugLoc(); + MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOLoad); + unsigned Opc = 0; + + if (Mips::CPU16RegsRegClass.hasSubClassEq(RC)) + Opc = Mips::LwRxSpImmX16; + assert(Opc && "Register class not handled!"); + BuildMI(MBB, I, DL, get(Opc), DestReg).addFrameIndex(FI).addImm(Offset) + .addMemOperand(MMO); +} + +bool Mips16InstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { + MachineBasicBlock &MBB = *MI->getParent(); + switch(MI->getDesc().getOpcode()) { + default: + return false; + case Mips::RetRA16: + ExpandRetRA16(MBB, MI, Mips::JrcRa16); + break; + } + + MBB.erase(MI); + return true; +} + +/// GetOppositeBranchOpc - Return the inverse of the specified +/// opcode, e.g. turning BEQ to BNE. +unsigned Mips16InstrInfo::getOppositeBranchOpc(unsigned Opc) const { + switch (Opc) { + default: llvm_unreachable("Illegal opcode!"); + case Mips::BeqzRxImmX16: return Mips::BnezRxImmX16; + case Mips::BnezRxImmX16: return Mips::BeqzRxImmX16; + case Mips::BeqzRxImm16: return Mips::BnezRxImm16; + case Mips::BnezRxImm16: return Mips::BeqzRxImm16; + case Mips::BteqzT8CmpX16: return Mips::BtnezT8CmpX16; + case Mips::BteqzT8SltX16: return Mips::BtnezT8SltX16; + case Mips::BteqzT8SltiX16: return Mips::BtnezT8SltiX16; + case Mips::Btnez16: return Mips::Bteqz16; + case Mips::BtnezX16: return Mips::BteqzX16; + case Mips::BtnezT8CmpiX16: return Mips::BteqzT8CmpiX16; + case Mips::BtnezT8SltuX16: return Mips::BteqzT8SltuX16; + case Mips::BtnezT8SltiuX16: return Mips::BteqzT8SltiuX16; + case Mips::Bteqz16: return Mips::Btnez16; + case Mips::BteqzX16: return Mips::BtnezX16; + case Mips::BteqzT8CmpiX16: return Mips::BtnezT8CmpiX16; + case Mips::BteqzT8SltuX16: return Mips::BtnezT8SltuX16; + case Mips::BteqzT8SltiuX16: return Mips::BtnezT8SltiuX16; + case Mips::BtnezT8CmpX16: return Mips::BteqzT8CmpX16; + case Mips::BtnezT8SltX16: return Mips::BteqzT8SltX16; + case Mips::BtnezT8SltiX16: return Mips::BteqzT8SltiX16; + } + assert(false && "Implement this function."); + return 0; +} + +// Adjust SP by FrameSize bytes. Save RA, S0, S1 +void Mips16InstrInfo::makeFrame(unsigned SP, int64_t FrameSize, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + if (!NeverUseSaveRestore) { + if (isUInt<11>(FrameSize)) + BuildMI(MBB, I, DL, get(Mips::SaveRaF16)).addImm(FrameSize); + else { + int Base = 2040; // should create template function like isUInt that + // returns largest possible n bit unsigned integer + int64_t Remainder = FrameSize - Base; + BuildMI(MBB, I, DL, get(Mips::SaveRaF16)). addImm(Base); + if (isInt<16>(-Remainder)) + BuildAddiuSpImm(MBB, I, -Remainder); + else + adjustStackPtrBig(SP, -Remainder, MBB, I, Mips::V0, Mips::V1); + } + + } + else { + // + // sw ra, -4[sp] + // sw s1, -8[sp] + // sw s0, -12[sp] + + MachineInstrBuilder MIB1 = BuildMI(MBB, I, DL, get(Mips::SwRxSpImmX16), + Mips::RA); + MIB1.addReg(Mips::SP); + MIB1.addImm(-4); + MachineInstrBuilder MIB2 = BuildMI(MBB, I, DL, get(Mips::SwRxSpImmX16), + Mips::S1); + MIB2.addReg(Mips::SP); + MIB2.addImm(-8); + MachineInstrBuilder MIB3 = BuildMI(MBB, I, DL, get(Mips::SwRxSpImmX16), + Mips::S0); + MIB3.addReg(Mips::SP); + MIB3.addImm(-12); + adjustStackPtrBig(SP, -FrameSize, MBB, I, Mips::V0, Mips::V1); + } +} + +// Adjust SP by FrameSize bytes. Restore RA, S0, S1 +void Mips16InstrInfo::restoreFrame(unsigned SP, int64_t FrameSize, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + if (!NeverUseSaveRestore) { + if (isUInt<11>(FrameSize)) + BuildMI(MBB, I, DL, get(Mips::RestoreRaF16)).addImm(FrameSize); + else { + int Base = 2040; // should create template function like isUInt that + // returns largest possible n bit unsigned integer + int64_t Remainder = FrameSize - Base; + if (isInt<16>(Remainder)) + BuildAddiuSpImm(MBB, I, Remainder); + else + adjustStackPtrBig(SP, Remainder, MBB, I, Mips::A0, Mips::A1); + BuildMI(MBB, I, DL, get(Mips::RestoreRaF16)). addImm(Base); + } + } + else { + adjustStackPtrBig(SP, FrameSize, MBB, I, Mips::A0, Mips::A1); + // lw ra, -4[sp] + // lw s1, -8[sp] + // lw s0, -12[sp] + MachineInstrBuilder MIB1 = BuildMI(MBB, I, DL, get(Mips::LwRxSpImmX16), + Mips::A0); + MIB1.addReg(Mips::SP); + MIB1.addImm(-4); + MachineInstrBuilder MIB0 = BuildMI(MBB, I, DL, get(Mips::Move32R16), + Mips::RA); + MIB0.addReg(Mips::A0); + MachineInstrBuilder MIB2 = BuildMI(MBB, I, DL, get(Mips::LwRxSpImmX16), + Mips::S1); + MIB2.addReg(Mips::SP); + MIB2.addImm(-8); + MachineInstrBuilder MIB3 = BuildMI(MBB, I, DL, get(Mips::LwRxSpImmX16), + Mips::S0); + MIB3.addReg(Mips::SP); + MIB3.addImm(-12); + } + +} + +// Adjust SP by Amount bytes where bytes can be up to 32bit number. +// This can only be called at times that we know that there is at least one free +// register. +// This is clearly safe at prologue and epilogue. +// +void Mips16InstrInfo::adjustStackPtrBig(unsigned SP, int64_t Amount, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned Reg1, unsigned Reg2) const { + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); +// MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); +// unsigned Reg1 = RegInfo.createVirtualRegister(&Mips::CPU16RegsRegClass); +// unsigned Reg2 = RegInfo.createVirtualRegister(&Mips::CPU16RegsRegClass); + // + // li reg1, constant + // move reg2, sp + // add reg1, reg1, reg2 + // move sp, reg1 + // + // + MachineInstrBuilder MIB1 = BuildMI(MBB, I, DL, get(Mips::LwConstant32), Reg1); + MIB1.addImm(Amount); + MachineInstrBuilder MIB2 = BuildMI(MBB, I, DL, get(Mips::MoveR3216), Reg2); + MIB2.addReg(Mips::SP, RegState::Kill); + MachineInstrBuilder MIB3 = BuildMI(MBB, I, DL, get(Mips::AdduRxRyRz16), Reg1); + MIB3.addReg(Reg1); + MIB3.addReg(Reg2, RegState::Kill); + MachineInstrBuilder MIB4 = BuildMI(MBB, I, DL, get(Mips::Move32R16), + Mips::SP); + MIB4.addReg(Reg1, RegState::Kill); +} + +void Mips16InstrInfo::adjustStackPtrBigUnrestricted(unsigned SP, int64_t Amount, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + assert(false && "adjust stack pointer amount exceeded"); +} + +/// Adjust SP by Amount bytes. +void Mips16InstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + if (isInt<16>(Amount)) // need to change to addiu sp, ....and isInt<16> + BuildAddiuSpImm(MBB, I, Amount); + else + adjustStackPtrBigUnrestricted(SP, Amount, MBB, I); +} + +/// This function generates the sequence of instructions needed to get the +/// result of adding register REG and immediate IMM. +unsigned +Mips16InstrInfo::loadImmediate(unsigned FrameReg, + int64_t Imm, MachineBasicBlock &MBB, + MachineBasicBlock::iterator II, DebugLoc DL, + unsigned &NewImm) const { + // + // given original instruction is: + // Instr rx, T[offset] where offset is too big. + // + // lo = offset & 0xFFFF + // hi = ((offset >> 16) + (lo >> 15)) & 0xFFFF; + // + // let T = temporary register + // li T, hi + // shl T, 16 + // add T, Rx, T + // + RegScavenger rs; + int32_t lo = Imm & 0xFFFF; + NewImm = lo; + int Reg =0; + int SpReg = 0; + + rs.enterBasicBlock(&MBB); + rs.forward(II); + // + // We need to know which registers can be used, in the case where there + // are not enough free registers. We exclude all registers that + // are used in the instruction that we are helping. + // // Consider all allocatable registers in the register class initially + BitVector Candidates = + RI.getAllocatableSet + (*II->getParent()->getParent(), &Mips::CPU16RegsRegClass); + // Exclude all the registers being used by the instruction. + for (unsigned i = 0, e = II->getNumOperands(); i != e; ++i) { + MachineOperand &MO = II->getOperand(i); + if (MO.isReg() && MO.getReg() != 0 && !MO.isDef() && + !TargetRegisterInfo::isVirtualRegister(MO.getReg())) + Candidates.reset(MO.getReg()); + } + // + // If the same register was used and defined in an instruction, then + // it will not be in the list of candidates. + // + // we need to analyze the instruction that we are helping. + // we need to know if it defines register x but register x is not + // present as an operand of the instruction. this tells + // whether the register is live before the instruction. if it's not + // then we don't need to save it in case there are no free registers. + // + int DefReg = 0; + for (unsigned i = 0, e = II->getNumOperands(); i != e; ++i) { + MachineOperand &MO = II->getOperand(i); + if (MO.isReg() && MO.isDef()) { + DefReg = MO.getReg(); + break; + } + } + // + BitVector Available = rs.getRegsAvailable(&Mips::CPU16RegsRegClass); + + Available &= Candidates; + // + // we use T0 for the first register, if we need to save something away. + // we use T1 for the second register, if we need to save something away. + // + unsigned FirstRegSaved =0, SecondRegSaved=0; + unsigned FirstRegSavedTo = 0, SecondRegSavedTo = 0; + + + Reg = Available.find_first(); + + if (Reg == -1) { + Reg = Candidates.find_first(); + Candidates.reset(Reg); + if (DefReg != Reg) { + FirstRegSaved = Reg; + FirstRegSavedTo = Mips::T0; + copyPhysReg(MBB, II, DL, FirstRegSavedTo, FirstRegSaved, true); + } + } + else + Available.reset(Reg); + BuildMI(MBB, II, DL, get(Mips::LwConstant32), Reg).addImm(Imm); + NewImm = 0; + if (FrameReg == Mips::SP) { + SpReg = Available.find_first(); + if (SpReg == -1) { + SpReg = Candidates.find_first(); + // Candidates.reset(SpReg); // not really needed + if (DefReg!= SpReg) { + SecondRegSaved = SpReg; + SecondRegSavedTo = Mips::T1; + } + if (SecondRegSaved) + copyPhysReg(MBB, II, DL, SecondRegSavedTo, SecondRegSaved, true); + } + else + Available.reset(SpReg); + copyPhysReg(MBB, II, DL, SpReg, Mips::SP, false); + BuildMI(MBB, II, DL, get(Mips:: AdduRxRyRz16), Reg).addReg(SpReg, RegState::Kill) + .addReg(Reg); + } + else + BuildMI(MBB, II, DL, get(Mips:: AdduRxRyRz16), Reg).addReg(FrameReg) + .addReg(Reg, RegState::Kill); + if (FirstRegSaved || SecondRegSaved) { + II = llvm::next(II); + if (FirstRegSaved) + copyPhysReg(MBB, II, DL, FirstRegSaved, FirstRegSavedTo, true); + if (SecondRegSaved) + copyPhysReg(MBB, II, DL, SecondRegSaved, SecondRegSavedTo, true); + } + return Reg; +} + +/// This function generates the sequence of instructions needed to get the +/// result of adding register REG and immediate IMM. +unsigned +Mips16InstrInfo::basicLoadImmediate( + unsigned FrameReg, + int64_t Imm, MachineBasicBlock &MBB, + MachineBasicBlock::iterator II, DebugLoc DL, + unsigned &NewImm) const { + const TargetRegisterClass *RC = &Mips::CPU16RegsRegClass; + MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); + unsigned Reg = RegInfo.createVirtualRegister(RC); + BuildMI(MBB, II, DL, get(Mips::LwConstant32), Reg).addImm(Imm); + NewImm = 0; + return Reg; +} + +unsigned Mips16InstrInfo::getAnalyzableBrOpc(unsigned Opc) const { + return (Opc == Mips::BeqzRxImmX16 || Opc == Mips::BimmX16 || + Opc == Mips::Bimm16 || + Opc == Mips::Bteqz16 || Opc == Mips::Btnez16 || + Opc == Mips::BeqzRxImm16 || Opc == Mips::BnezRxImm16 || + Opc == Mips::BnezRxImmX16 || Opc == Mips::BteqzX16 || + Opc == Mips::BteqzT8CmpX16 || Opc == Mips::BteqzT8CmpiX16 || + Opc == Mips::BteqzT8SltX16 || Opc == Mips::BteqzT8SltuX16 || + Opc == Mips::BteqzT8SltiX16 || Opc == Mips::BteqzT8SltiuX16 || + Opc == Mips::BtnezX16 || Opc == Mips::BtnezT8CmpX16 || + Opc == Mips::BtnezT8CmpiX16 || Opc == Mips::BtnezT8SltX16 || + Opc == Mips::BtnezT8SltuX16 || Opc == Mips::BtnezT8SltiX16 || + Opc == Mips::BtnezT8SltiuX16 ) ? Opc : 0; +} + +void Mips16InstrInfo::ExpandRetRA16(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned Opc) const { + BuildMI(MBB, I, I->getDebugLoc(), get(Opc)); +} + + +const MCInstrDesc &Mips16InstrInfo::AddiuSpImm(int64_t Imm) const { + if (validSpImm8(Imm)) + return get(Mips::AddiuSpImm16); + else + return get(Mips::AddiuSpImmX16); +} + +void Mips16InstrInfo::BuildAddiuSpImm + (MachineBasicBlock &MBB, MachineBasicBlock::iterator I, int64_t Imm) const { + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + BuildMI(MBB, I, DL, AddiuSpImm(Imm)).addImm(Imm); +} + +const MipsInstrInfo *llvm::createMips16InstrInfo(MipsTargetMachine &TM) { + return new Mips16InstrInfo(TM); +} + +bool Mips16InstrInfo::validImmediate(unsigned Opcode, unsigned Reg, + int64_t Amount) { + switch (Opcode) { + case Mips::LbRxRyOffMemX16: + case Mips::LbuRxRyOffMemX16: + case Mips::LhRxRyOffMemX16: + case Mips::LhuRxRyOffMemX16: + case Mips::SbRxRyOffMemX16: + case Mips::ShRxRyOffMemX16: + case Mips::LwRxRyOffMemX16: + case Mips::SwRxRyOffMemX16: + case Mips::SwRxSpImmX16: + case Mips::LwRxSpImmX16: + return isInt<16>(Amount); + case Mips::AddiuRxRyOffMemX16: + if ((Reg == Mips::PC) || (Reg == Mips::SP)) + return isInt<16>(Amount); + return isInt<15>(Amount); + } + llvm_unreachable("unexpected Opcode in validImmediate"); +} + +/// Measure the specified inline asm to determine an approximation of its +/// length. +/// Comments (which run till the next SeparatorString or newline) do not +/// count as an instruction. +/// Any other non-whitespace text is considered an instruction, with +/// multiple instructions separated by SeparatorString or newlines. +/// Variable-length instructions are not handled here; this function +/// may be overloaded in the target code to do that. +/// We implement the special case of the .space directive taking only an +/// integer argument, which is the size in bytes. This is used for creating +/// inline code spacing for testing purposes using inline assembly. +/// +unsigned Mips16InstrInfo::getInlineAsmLength(const char *Str, + const MCAsmInfo &MAI) const { + + + // Count the number of instructions in the asm. + bool atInsnStart = true; + unsigned Length = 0; + for (; *Str; ++Str) { + if (*Str == '\n' || strncmp(Str, MAI.getSeparatorString(), + strlen(MAI.getSeparatorString())) == 0) + atInsnStart = true; + if (atInsnStart && !std::isspace(static_cast<unsigned char>(*Str))) { + if (strncmp(Str, ".space", 6)==0) { + char *EStr; int Sz; + Sz = strtol(Str+6, &EStr, 10); + while (isspace(*EStr)) ++EStr; + if (*EStr=='\0') { + DEBUG(dbgs() << "parsed .space " << Sz << '\n'); + return Sz; + } + } + Length += MAI.getMaxInstLength(); + atInsnStart = false; + } + if (atInsnStart && strncmp(Str, MAI.getCommentString(), + strlen(MAI.getCommentString())) == 0) + atInsnStart = false; + } + + return Length; +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.h b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.h new file mode 100644 index 000000000000..d9a594b537a2 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.h @@ -0,0 +1,133 @@ +//===-- Mips16InstrInfo.h - Mips16 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 Mips16 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPS16INSTRUCTIONINFO_H +#define MIPS16INSTRUCTIONINFO_H + +#include "Mips16RegisterInfo.h" +#include "MipsInstrInfo.h" + +namespace llvm { + +class Mips16InstrInfo : public MipsInstrInfo { + const Mips16RegisterInfo RI; + +public: + explicit Mips16InstrInfo(MipsTargetMachine &TM); + + virtual const MipsRegisterInfo &getRegisterInfo() const; + + /// 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; + + virtual void copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const; + + virtual void storeRegToStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const; + + virtual void loadRegFromStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const; + + virtual bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const; + + virtual unsigned getOppositeBranchOpc(unsigned Opc) const; + + // Adjust SP by FrameSize bytes. Save RA, S0, S1 + void makeFrame(unsigned SP, int64_t FrameSize, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + // Adjust SP by FrameSize bytes. Restore RA, S0, S1 + void restoreFrame(unsigned SP, int64_t FrameSize, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + + /// Adjust SP by Amount bytes. + void adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + /// Emit a series of instructions to load an immediate. + // This is to adjust some FrameReg. We return the new register to be used + // in place of FrameReg and the adjusted immediate field (&NewImm) + // + unsigned loadImmediate(unsigned FrameReg, + int64_t Imm, MachineBasicBlock &MBB, + MachineBasicBlock::iterator II, DebugLoc DL, + unsigned &NewImm) const; + + unsigned basicLoadImmediate(unsigned FrameReg, + int64_t Imm, MachineBasicBlock &MBB, + MachineBasicBlock::iterator II, DebugLoc DL, + unsigned &NewImm) const; + + static bool validImmediate(unsigned Opcode, unsigned Reg, int64_t Amount); + + static bool validSpImm8(int offset) { + return ((offset & 7) == 0) && isInt<11>(offset); + } + + // + // build the proper one based on the Imm field + // + + const MCInstrDesc& AddiuSpImm(int64_t Imm) const; + + void BuildAddiuSpImm + (MachineBasicBlock &MBB, MachineBasicBlock::iterator I, int64_t Imm) const; + + unsigned getInlineAsmLength(const char *Str, + const MCAsmInfo &MAI) const; +private: + virtual unsigned getAnalyzableBrOpc(unsigned Opc) const; + + void ExpandRetRA16(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned Opc) const; + + // Adjust SP by Amount bytes where bytes can be up to 32bit number. + void adjustStackPtrBig(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned Reg1, unsigned Reg2) const; + + // Adjust SP by Amount bytes where bytes can be up to 32bit number. + void adjustStackPtrBigUnrestricted(unsigned SP, int64_t Amount, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.td b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.td new file mode 100644 index 000000000000..7441c78a0330 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16InstrInfo.td @@ -0,0 +1,1909 @@ +//===- Mips16InstrInfo.td - Target Description for Mips16 -*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Mips16 instructions. +// +//===----------------------------------------------------------------------===// +// +// +// Mips Address +// +def addr16 : + ComplexPattern<iPTR, 3, "selectAddr16", [frameindex], [SDNPWantParent]>; + +// +// Address operand +def mem16 : Operand<i32> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops CPU16Regs, simm16, CPU16RegsPlusSP); + let EncoderMethod = "getMemEncoding"; +} + +def mem16_ea : Operand<i32> { + let PrintMethod = "printMemOperandEA"; + let MIOperandInfo = (ops CPU16RegsPlusSP, simm16); + let EncoderMethod = "getMemEncoding"; +} + +// +// I-type instruction format +// +// this is only used by bimm. the actual assembly value is a 12 bit signed +// number +// +class FI16_ins<bits<5> op, string asmstr, InstrItinClass itin>: + FI16<op, (outs), (ins brtarget:$imm16), + !strconcat(asmstr, "\t$imm16 # 16 bit inst"), [], itin>; + +// +// +// I8 instruction format +// + +class FI816_ins_base<bits<3> _func, string asmstr, + string asmstr2, InstrItinClass itin>: + FI816<_func, (outs), (ins simm16:$imm), !strconcat(asmstr, asmstr2), + [], itin>; + +class FI816_ins<bits<3> _func, string asmstr, + InstrItinClass itin>: + FI816_ins_base<_func, asmstr, "\t$imm # 16 bit inst", itin>; + +class FI816_SP_ins<bits<3> _func, string asmstr, + InstrItinClass itin>: + FI816_ins_base<_func, asmstr, "\t$$sp, $imm # 16 bit inst", itin>; + +// +// RI instruction format +// + + +class FRI16_ins_base<bits<5> op, string asmstr, string asmstr2, + InstrItinClass itin>: + FRI16<op, (outs CPU16Regs:$rx), (ins simm16:$imm), + !strconcat(asmstr, asmstr2), [], itin>; + +class FRI16_ins<bits<5> op, string asmstr, + InstrItinClass itin>: + FRI16_ins_base<op, asmstr, "\t$rx, $imm \t# 16 bit inst", itin>; + +class FRI16_TCP_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FRI16<_op, (outs CPU16Regs:$rx), (ins pcrel16:$imm, i32imm:$size), + !strconcat(asmstr, "\t$rx, $imm\t# 16 bit inst"), [], itin>; + +class FRI16R_ins_base<bits<5> op, string asmstr, string asmstr2, + InstrItinClass itin>: + FRI16<op, (outs), (ins CPU16Regs:$rx, simm16:$imm), + !strconcat(asmstr, asmstr2), [], itin>; + +class FRI16R_ins<bits<5> op, string asmstr, + InstrItinClass itin>: + FRI16R_ins_base<op, asmstr, "\t$rx, $imm \t# 16 bit inst", itin>; + +class F2RI16_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FRI16<_op, (outs CPU16Regs:$rx), (ins CPU16Regs:$rx_, simm16:$imm), + !strconcat(asmstr, "\t$rx, $imm\t# 16 bit inst"), [], itin> { + let Constraints = "$rx_ = $rx"; +} + +class FRI16_B_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FRI16<_op, (outs), (ins CPU16Regs:$rx, brtarget:$imm), + !strconcat(asmstr, "\t$rx, $imm # 16 bit inst"), [], itin>; +// +// Compare a register and immediate and place result in CC +// Implicit use of T8 +// +// EXT-CCRR Instruction format +// +class FEXT_CCRXI16_ins<string asmstr>: + MipsPseudo16<(outs CPU16Regs:$cc), (ins CPU16Regs:$rx, simm16:$imm), + !strconcat(asmstr, "\t$rx, $imm\n\tmove\t$cc, $$t8"), []> { + let isCodeGenOnly=1; + let usesCustomInserter = 1; +} + +// JAL and JALX instruction format +// +class FJAL16_ins<bits<1> _X, string asmstr, + InstrItinClass itin>: + FJAL16<_X, (outs), (ins simm20:$imm), + !strconcat(asmstr, "\t$imm\n\tnop"),[], + itin> { + let isCodeGenOnly=1; +} +// +// EXT-I instruction format +// +class FEXT_I16_ins<bits<5> eop, string asmstr, InstrItinClass itin> : + FEXT_I16<eop, (outs), (ins brtarget:$imm16), + !strconcat(asmstr, "\t$imm16"),[], itin>; + +// +// EXT-I8 instruction format +// + +class FEXT_I816_ins_base<bits<3> _func, string asmstr, + string asmstr2, InstrItinClass itin>: + FEXT_I816<_func, (outs), (ins simm16:$imm), !strconcat(asmstr, asmstr2), + [], itin>; + +class FEXT_I816_ins<bits<3> _func, string asmstr, + InstrItinClass itin>: + FEXT_I816_ins_base<_func, asmstr, "\t$imm", itin>; + +class FEXT_I816_SP_ins<bits<3> _func, string asmstr, + InstrItinClass itin>: + FEXT_I816_ins_base<_func, asmstr, "\t$$sp, $imm", itin>; + +// +// Assembler formats in alphabetical order. +// Natural and pseudos are mixed together. +// +// Compare two registers and place result in CC +// Implicit use of T8 +// +// CC-RR Instruction format +// +class FCCRR16_ins<string asmstr> : + MipsPseudo16<(outs CPU16Regs:$cc), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry\n\tmove\t$cc, $$t8"), []> { + let isCodeGenOnly=1; + let usesCustomInserter = 1; +} + +// +// EXT-RI instruction format +// + +class FEXT_RI16_ins_base<bits<5> _op, string asmstr, string asmstr2, + InstrItinClass itin>: + FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins simm16:$imm), + !strconcat(asmstr, asmstr2), [], itin>; + +class FEXT_RI16_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16_ins_base<_op, asmstr, "\t$rx, $imm", itin>; + +class FEXT_RI16R_ins_base<bits<5> _op, string asmstr, string asmstr2, + InstrItinClass itin>: + FEXT_RI16<_op, (outs ), (ins CPU16Regs:$rx, simm16:$imm), + !strconcat(asmstr, asmstr2), [], itin>; + +class FEXT_RI16R_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16R_ins_base<_op, asmstr, "\t$rx, $imm", itin>; + +class FEXT_RI16_PC_ins<bits<5> _op, string asmstr, InstrItinClass itin>: + FEXT_RI16_ins_base<_op, asmstr, "\t$rx, $$pc, $imm", itin>; + +class FEXT_RI16_B_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16<_op, (outs), (ins CPU16Regs:$rx, brtarget:$imm), + !strconcat(asmstr, "\t$rx, $imm"), [], itin>; + +class FEXT_RI16_TCP_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins pcrel16:$imm, i32imm:$size), + !strconcat(asmstr, "\t$rx, $imm"), [], itin>; + +class FEXT_2RI16_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins CPU16Regs:$rx_, simm16:$imm), + !strconcat(asmstr, "\t$rx, $imm"), [], itin> { + let Constraints = "$rx_ = $rx"; +} + + +// this has an explicit sp argument that we ignore to work around a problem +// in the compiler +class FEXT_RI16_SP_explicit_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins CPUSPReg:$ry, simm16:$imm), + !strconcat(asmstr, "\t$rx, $imm ( $ry ); "), [], itin>; + +class FEXT_RI16_SP_Store_explicit_ins<bits<5> _op, string asmstr, + InstrItinClass itin>: + FEXT_RI16<_op, (outs), (ins CPU16Regs:$rx, CPUSPReg:$ry, simm16:$imm), + !strconcat(asmstr, "\t$rx, $imm ( $ry ); "), [], itin>; + +// +// EXT-RRI instruction format +// + +class FEXT_RRI16_mem_ins<bits<5> op, string asmstr, Operand MemOpnd, + InstrItinClass itin>: + FEXT_RRI16<op, (outs CPU16Regs:$ry), (ins MemOpnd:$addr), + !strconcat(asmstr, "\t$ry, $addr"), [], itin>; + +class FEXT_RRI16_mem2_ins<bits<5> op, string asmstr, Operand MemOpnd, + InstrItinClass itin>: + FEXT_RRI16<op, (outs ), (ins CPU16Regs:$ry, MemOpnd:$addr), + !strconcat(asmstr, "\t$ry, $addr"), [], itin>; + +// +// +// EXT-RRI-A instruction format +// + +class FEXT_RRI_A16_mem_ins<bits<1> op, string asmstr, Operand MemOpnd, + InstrItinClass itin>: + FEXT_RRI_A16<op, (outs CPU16Regs:$ry), (ins MemOpnd:$addr), + !strconcat(asmstr, "\t$ry, $addr"), [], itin>; + +// +// EXT-SHIFT instruction format +// +class FEXT_SHIFT16_ins<bits<2> _f, string asmstr, InstrItinClass itin>: + FEXT_SHIFT16<_f, (outs CPU16Regs:$rx), (ins CPU16Regs:$ry, uimm5:$sa), + !strconcat(asmstr, "\t$rx, $ry, $sa"), [], itin>; + +// +// EXT-T8I8 +// +class FEXT_T8I816_ins<string asmstr, string asmstr2>: + MipsPseudo16<(outs), + (ins CPU16Regs:$rx, CPU16Regs:$ry, brtarget:$imm), + !strconcat(asmstr2, !strconcat("\t$rx, $ry\n\t", + !strconcat(asmstr, "\t$imm"))),[]> { + let isCodeGenOnly=1; + let usesCustomInserter = 1; +} + +// +// EXT-T8I8I +// +class FEXT_T8I8I16_ins<string asmstr, string asmstr2>: + MipsPseudo16<(outs), + (ins CPU16Regs:$rx, simm16:$imm, brtarget:$targ), + !strconcat(asmstr2, !strconcat("\t$rx, $imm\n\t", + !strconcat(asmstr, "\t$targ"))), []> { + let isCodeGenOnly=1; + let usesCustomInserter = 1; +} +// + + +// +// I8_MOVR32 instruction format (used only by the MOVR32 instructio +// +class FI8_MOVR3216_ins<string asmstr, InstrItinClass itin>: + FI8_MOVR3216<(outs CPU16Regs:$rz), (ins GPR32:$r32), + !strconcat(asmstr, "\t$rz, $r32"), [], itin>; + +// +// I8_MOV32R instruction format (used only by MOV32R instruction) +// + +class FI8_MOV32R16_ins<string asmstr, InstrItinClass itin>: + FI8_MOV32R16<(outs GPR32:$r32), (ins CPU16Regs:$rz), + !strconcat(asmstr, "\t$r32, $rz"), [], itin>; + +// +// This are pseudo formats for multiply +// This first one can be changed to non pseudo now. +// +// MULT +// +class FMULT16_ins<string asmstr, InstrItinClass itin> : + MipsPseudo16<(outs), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry"), []>; + +// +// MULT-LO +// +class FMULT16_LO_ins<string asmstr, InstrItinClass itin> : + MipsPseudo16<(outs CPU16Regs:$rz), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry\n\tmflo\t$rz"), []> { + let isCodeGenOnly=1; +} + +// +// RR-type instruction format +// + +class FRR16_ins<bits<5> f, string asmstr, InstrItinClass itin> : + FRR16<f, (outs CPU16Regs:$rx), (ins CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry"), [], itin> { +} + +class FRRBreakNull16_ins<string asmstr, InstrItinClass itin> : + FRRBreak16<(outs), (ins), asmstr, [], itin> { + let Code=0; +} + +class FRR16R_ins<bits<5> f, string asmstr, InstrItinClass itin> : + FRR16<f, (outs), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry"), [], itin> { +} + +class FRRTR16_ins<string asmstr> : + MipsPseudo16<(outs CPU16Regs:$rz), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry\n\tmove\t$rz, $$t8"), []> ; + +// +// maybe refactor but need a $zero as a dummy first parameter +// +class FRR16_div_ins<bits<5> f, string asmstr, InstrItinClass itin> : + FRR16<f, (outs ), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$$zero, $rx, $ry"), [], itin> ; + +class FUnaryRR16_ins<bits<5> f, string asmstr, InstrItinClass itin> : + FRR16<f, (outs CPU16Regs:$rx), (ins CPU16Regs:$ry), + !strconcat(asmstr, "\t$rx, $ry"), [], itin> ; + + +class FRR16_M_ins<bits<5> f, string asmstr, + InstrItinClass itin> : + FRR16<f, (outs CPU16Regs:$rx), (ins), + !strconcat(asmstr, "\t$rx"), [], itin>; + +class FRxRxRy16_ins<bits<5> f, string asmstr, + InstrItinClass itin> : + FRR16<f, (outs CPU16Regs:$rz), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rz, $ry"), + [], itin> { + let Constraints = "$rx = $rz"; +} + +let rx=0 in +class FRR16_JALRC_RA_only_ins<bits<1> nd_, bits<1> l_, + string asmstr, InstrItinClass itin>: + FRR16_JALRC<nd_, l_, 1, (outs), (ins), !strconcat(asmstr, "\t $$ra"), + [], itin> ; + + +class FRR16_JALRC_ins<bits<1> nd, bits<1> l, bits<1> ra, + string asmstr, InstrItinClass itin>: + FRR16_JALRC<nd, l, ra, (outs), (ins CPU16Regs:$rx), + !strconcat(asmstr, "\t $rx"), [], itin> ; + +class FRR_SF16_ins + <bits<5> _funct, bits<3> _subfunc, + string asmstr, InstrItinClass itin>: + FRR_SF16<_funct, _subfunc, (outs CPU16Regs:$rx), (ins CPU16Regs:$rx_), + !strconcat(asmstr, "\t $rx"), + [], itin> { + let Constraints = "$rx_ = $rx"; + } +// +// RRR-type instruction format +// + +class FRRR16_ins<bits<2> _f, string asmstr, InstrItinClass itin> : + FRRR16<_f, (outs CPU16Regs:$rz), (ins CPU16Regs:$rx, CPU16Regs:$ry), + !strconcat(asmstr, "\t$rz, $rx, $ry"), [], itin>; + +// +// These Sel patterns support the generation of conditional move +// pseudo instructions. +// +// The nomenclature uses the components making up the pseudo and may +// be a bit counter intuitive when compared with the end result we seek. +// For example using a bqez in the example directly below results in the +// conditional move being done if the tested register is not zero. +// I considered in easier to check by keeping the pseudo consistent with +// it's components but it could have been done differently. +// +// The simplest case is when can test and operand directly and do the +// conditional move based on a simple mips16 conditional +// branch instruction. +// for example: +// if $op == beqz or bnez: +// +// $op1 $rt, .+4 +// move $rd, $rs +// +// if $op == beqz, then if $rt != 0, then the conditional assignment +// $rd = $rs is done. + +// if $op == bnez, then if $rt == 0, then the conditional assignment +// $rd = $rs is done. +// +// So this pseudo class only has one operand, i.e. op +// +class Sel<string op>: + MipsPseudo16<(outs CPU16Regs:$rd_), (ins CPU16Regs:$rd, CPU16Regs:$rs, + CPU16Regs:$rt), + !strconcat(op, "\t$rt, .+4\n\t\n\tmove $rd, $rs"), []> { + //let isCodeGenOnly=1; + let Constraints = "$rd = $rd_"; + let usesCustomInserter = 1; +} + +// +// The next two instruction classes allow for an operand which tests +// two operands and returns a value in register T8 and +//then does a conditional branch based on the value of T8 +// + +// op2 can be cmpi or slti/sltiu +// op1 can bteqz or btnez +// the operands for op2 are a register and a signed constant +// +// $op2 $t, $imm ;test register t and branch conditionally +// $op1 .+4 ;op1 is a conditional branch +// move $rd, $rs +// +// +class SeliT<string op1, string op2>: + MipsPseudo16<(outs CPU16Regs:$rd_), (ins CPU16Regs:$rd, CPU16Regs:$rs, + CPU16Regs:$rl, simm16:$imm), + !strconcat(op2, + !strconcat("\t$rl, $imm\n\t", + !strconcat(op1, "\t.+4\n\tmove $rd, $rs"))), []> { + let isCodeGenOnly=1; + let Constraints = "$rd = $rd_"; + let usesCustomInserter = 1; +} + +// +// op2 can be cmp or slt/sltu +// op1 can be bteqz or btnez +// the operands for op2 are two registers +// op1 is a conditional branch +// +// +// $op2 $rl, $rr ;test registers rl,rr +// $op1 .+4 ;op2 is a conditional branch +// move $rd, $rs +// +// +class SelT<string op1, string op2>: + MipsPseudo16<(outs CPU16Regs:$rd_), + (ins CPU16Regs:$rd, CPU16Regs:$rs, + CPU16Regs:$rl, CPU16Regs:$rr), + !strconcat(op2, + !strconcat("\t$rl, $rr\n\t", + !strconcat(op1, "\t.+4\n\tmove $rd, $rs"))), []> { + let isCodeGenOnly=1; + let Constraints = "$rd = $rd_"; + let usesCustomInserter = 1; +} + +// +// 32 bit constant +// +def imm32: Operand<i32>; + +def Constant32: + MipsPseudo16<(outs), (ins imm32:$imm), "\t.word $imm", []>; + +def LwConstant32: + MipsPseudo16<(outs CPU16Regs:$rx), (ins imm32:$imm, imm32:$constid), + "lw\t$rx, 1f\n\tb\t2f\n\t.align\t2\n1: \t.word\t$imm\n2:", []>; + + +// +// Some general instruction class info +// +// + +class ArithLogic16Defs<bit isCom=0> { + bits<5> shamt = 0; + bit isCommutable = isCom; + bit isReMaterializable = 1; + bit neverHasSideEffects = 1; +} + +class branch16 { + bit isBranch = 1; + bit isTerminator = 1; + bit isBarrier = 1; +} + +class cbranch16 { + bit isBranch = 1; + bit isTerminator = 1; +} + +class MayLoad { + bit mayLoad = 1; +} + +class MayStore { + bit mayStore = 1; +} +// + + +// Format: ADDIU rx, immediate MIPS16e +// Purpose: Add Immediate Unsigned Word (2-Operand, Extended) +// To add a constant to a 32-bit integer. +// +def AddiuRxImmX16: FEXT_RI16_ins<0b01001, "addiu", IIAlu>; + +def AddiuRxRxImm16: F2RI16_ins<0b01001, "addiu", IIAlu>, + ArithLogic16Defs<0> { + let AddedComplexity = 5; +} +def AddiuRxRxImmX16: FEXT_2RI16_ins<0b01001, "addiu", IIAlu>, + ArithLogic16Defs<0> { + let isCodeGenOnly = 1; +} + +def AddiuRxRyOffMemX16: + FEXT_RRI_A16_mem_ins<0, "addiu", mem16_ea, IIAlu>; + +// + +// Format: ADDIU rx, pc, immediate MIPS16e +// Purpose: Add Immediate Unsigned Word (3-Operand, PC-Relative, Extended) +// To add a constant to the program counter. +// +def AddiuRxPcImmX16: FEXT_RI16_PC_ins<0b00001, "addiu", IIAlu>; + +// +// Format: ADDIU sp, immediate MIPS16e +// Purpose: Add Immediate Unsigned Word (2-Operand, SP-Relative, Extended) +// To add a constant to the stack pointer. +// +def AddiuSpImm16 + : FI816_SP_ins<0b011, "addiu", IIAlu> { + let Defs = [SP]; + let Uses = [SP]; + let AddedComplexity = 5; +} + +def AddiuSpImmX16 + : FEXT_I816_SP_ins<0b011, "addiu", IIAlu> { + let Defs = [SP]; + let Uses = [SP]; +} + +// +// Format: ADDU rz, rx, ry MIPS16e +// Purpose: Add Unsigned Word (3-Operand) +// To add 32-bit integers. +// + +def AdduRxRyRz16: FRRR16_ins<01, "addu", IIAlu>, ArithLogic16Defs<1>; + +// +// Format: AND rx, ry MIPS16e +// Purpose: AND +// To do a bitwise logical AND. + +def AndRxRxRy16: FRxRxRy16_ins<0b01100, "and", IIAlu>, ArithLogic16Defs<1>; + + +// +// Format: BEQZ rx, offset MIPS16e +// Purpose: Branch on Equal to Zero +// To test a GPR then do a PC-relative conditional branch. +// +def BeqzRxImm16: FRI16_B_ins<0b00100, "beqz", IIAlu>, cbranch16; + + +// +// Format: BEQZ rx, offset MIPS16e +// Purpose: Branch on Equal to Zero (Extended) +// To test a GPR then do a PC-relative conditional branch. +// +def BeqzRxImmX16: FEXT_RI16_B_ins<0b00100, "beqz", IIAlu>, cbranch16; + +// +// Format: B offset MIPS16e +// Purpose: Unconditional Branch (Extended) +// To do an unconditional PC-relative branch. +// + +def Bimm16: FI16_ins<0b00010, "b", IIAlu>, branch16; + +// Format: B offset MIPS16e +// Purpose: Unconditional Branch +// To do an unconditional PC-relative branch. +// +def BimmX16: FEXT_I16_ins<0b00010, "b", IIAlu>, branch16; + +// +// Format: BNEZ rx, offset MIPS16e +// Purpose: Branch on Not Equal to Zero +// To test a GPR then do a PC-relative conditional branch. +// +def BnezRxImm16: FRI16_B_ins<0b00101, "bnez", IIAlu>, cbranch16; + +// +// Format: BNEZ rx, offset MIPS16e +// Purpose: Branch on Not Equal to Zero (Extended) +// To test a GPR then do a PC-relative conditional branch. +// +def BnezRxImmX16: FEXT_RI16_B_ins<0b00101, "bnez", IIAlu>, cbranch16; + + +// +//Format: BREAK immediate +// Purpose: Breakpoint +// To cause a Breakpoint exception. + +def Break16: FRRBreakNull16_ins<"break 0", NoItinerary>; +// +// Format: BTEQZ offset MIPS16e +// Purpose: Branch on T Equal to Zero (Extended) +// To test special register T then do a PC-relative conditional branch. +// +def Bteqz16: FI816_ins<0b000, "bteqz", IIAlu>, cbranch16 { + let Uses = [T8]; +} + +def BteqzX16: FEXT_I816_ins<0b000, "bteqz", IIAlu>, cbranch16 { + let Uses = [T8]; +} + +def BteqzT8CmpX16: FEXT_T8I816_ins<"bteqz", "cmp">, cbranch16; + +def BteqzT8CmpiX16: FEXT_T8I8I16_ins<"bteqz", "cmpi">, + cbranch16; + +def BteqzT8SltX16: FEXT_T8I816_ins<"bteqz", "slt">, cbranch16; + +def BteqzT8SltuX16: FEXT_T8I816_ins<"bteqz", "sltu">, cbranch16; + +def BteqzT8SltiX16: FEXT_T8I8I16_ins<"bteqz", "slti">, cbranch16; + +def BteqzT8SltiuX16: FEXT_T8I8I16_ins<"bteqz", "sltiu">, + cbranch16; + +// +// Format: BTNEZ offset MIPS16e +// Purpose: Branch on T Not Equal to Zero (Extended) +// To test special register T then do a PC-relative conditional branch. +// + +def Btnez16: FI816_ins<0b001, "btnez", IIAlu>, cbranch16 { + let Uses = [T8]; +} + +def BtnezX16: FEXT_I816_ins<0b001, "btnez", IIAlu> ,cbranch16 { + let Uses = [T8]; +} + +def BtnezT8CmpX16: FEXT_T8I816_ins<"btnez", "cmp">, cbranch16; + +def BtnezT8CmpiX16: FEXT_T8I8I16_ins<"btnez", "cmpi">, cbranch16; + +def BtnezT8SltX16: FEXT_T8I816_ins<"btnez", "slt">, cbranch16; + +def BtnezT8SltuX16: FEXT_T8I816_ins<"btnez", "sltu">, cbranch16; + +def BtnezT8SltiX16: FEXT_T8I8I16_ins<"btnez", "slti">, cbranch16; + +def BtnezT8SltiuX16: FEXT_T8I8I16_ins<"btnez", "sltiu">, + cbranch16; + +// +// Format: CMP rx, ry MIPS16e +// Purpose: Compare +// To compare the contents of two GPRs. +// +def CmpRxRy16: FRR16R_ins<0b01010, "cmp", IIAlu> { + let Defs = [T8]; +} + +// +// Format: CMPI rx, immediate MIPS16e +// Purpose: Compare Immediate +// To compare a constant with the contents of a GPR. +// +def CmpiRxImm16: FRI16R_ins<0b01110, "cmpi", IIAlu> { + let Defs = [T8]; +} + +// +// Format: CMPI rx, immediate MIPS16e +// Purpose: Compare Immediate (Extended) +// To compare a constant with the contents of a GPR. +// +def CmpiRxImmX16: FEXT_RI16R_ins<0b01110, "cmpi", IIAlu> { + let Defs = [T8]; +} + + +// +// Format: DIV rx, ry MIPS16e +// Purpose: Divide Word +// To divide 32-bit signed integers. +// +def DivRxRy16: FRR16_div_ins<0b11010, "div", IIAlu> { + let Defs = [HI0, LO0]; +} + +// +// Format: DIVU rx, ry MIPS16e +// Purpose: Divide Unsigned Word +// To divide 32-bit unsigned integers. +// +def DivuRxRy16: FRR16_div_ins<0b11011, "divu", IIAlu> { + let Defs = [HI0, LO0]; +} +// +// Format: JAL target MIPS16e +// Purpose: Jump and Link +// To execute a procedure call within the current 256 MB-aligned +// region and preserve the current ISA. +// + +def Jal16 : FJAL16_ins<0b0, "jal", IIAlu> { + let hasDelaySlot = 0; // not true, but we add the nop for now + let isCall=1; +} + +// +// Format: JR ra MIPS16e +// Purpose: Jump Register Through Register ra +// To execute a branch to the instruction address in the return +// address register. +// + +def JrRa16: FRR16_JALRC_RA_only_ins<0, 0, "jr", IIAlu> { + let isBranch = 1; + let isIndirectBranch = 1; + let hasDelaySlot = 1; + let isTerminator=1; + let isBarrier=1; +} + +def JrcRa16: FRR16_JALRC_RA_only_ins<1, 1, "jrc", IIAlu> { + let isBranch = 1; + let isIndirectBranch = 1; + let isTerminator=1; + let isBarrier=1; +} + +def JrcRx16: FRR16_JALRC_ins<1, 1, 0, "jrc", IIAlu> { + let isBranch = 1; + let isIndirectBranch = 1; + let isTerminator=1; + let isBarrier=1; +} +// +// Format: LB ry, offset(rx) MIPS16e +// Purpose: Load Byte (Extended) +// To load a byte from memory as a signed value. +// +def LbRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10011, "lb", mem16, IILoad>, MayLoad{ + let isCodeGenOnly = 1; +} + +// +// Format: LBU ry, offset(rx) MIPS16e +// Purpose: Load Byte Unsigned (Extended) +// To load a byte from memory as a unsigned value. +// +def LbuRxRyOffMemX16: + FEXT_RRI16_mem_ins<0b10100, "lbu", mem16, IILoad>, MayLoad { + let isCodeGenOnly = 1; +} + +// +// Format: LH ry, offset(rx) MIPS16e +// Purpose: Load Halfword signed (Extended) +// To load a halfword from memory as a signed value. +// +def LhRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10100, "lh", mem16, IILoad>, MayLoad{ + let isCodeGenOnly = 1; +} + +// +// Format: LHU ry, offset(rx) MIPS16e +// Purpose: Load Halfword unsigned (Extended) +// To load a halfword from memory as an unsigned value. +// +def LhuRxRyOffMemX16: + FEXT_RRI16_mem_ins<0b10100, "lhu", mem16, IILoad>, MayLoad { + let isCodeGenOnly = 1; +} + +// +// Format: LI rx, immediate MIPS16e +// Purpose: Load Immediate +// To load a constant into a GPR. +// +def LiRxImm16: FRI16_ins<0b01101, "li", IIAlu>; + +// +// Format: LI rx, immediate MIPS16e +// Purpose: Load Immediate (Extended) +// To load a constant into a GPR. +// +def LiRxImmX16: FEXT_RI16_ins<0b01101, "li", IIAlu>; + +def LiRxImmAlignX16: FEXT_RI16_ins<0b01101, ".align 2\n\tli", IIAlu> { + let isCodeGenOnly = 1; +} + +// +// Format: LW ry, offset(rx) MIPS16e +// Purpose: Load Word (Extended) +// To load a word from memory as a signed value. +// +def LwRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10011, "lw", mem16, IILoad>, MayLoad{ + let isCodeGenOnly = 1; +} + +// Format: LW rx, offset(sp) MIPS16e +// Purpose: Load Word (SP-Relative, Extended) +// To load an SP-relative word from memory as a signed value. +// +def LwRxSpImmX16: FEXT_RI16_SP_explicit_ins<0b10010, "lw", IILoad>, MayLoad{ + let Uses = [SP]; +} + +def LwRxPcTcp16: FRI16_TCP_ins<0b10110, "lw", IILoad>, MayLoad; + +def LwRxPcTcpX16: FEXT_RI16_TCP_ins<0b10110, "lw", IILoad>, MayLoad; +// +// Format: MOVE r32, rz MIPS16e +// Purpose: Move +// To move the contents of a GPR to a GPR. +// +def Move32R16: FI8_MOV32R16_ins<"move", IIAlu>; + +// +// Format: MOVE ry, r32 MIPS16e +//Purpose: Move +// To move the contents of a GPR to a GPR. +// +def MoveR3216: FI8_MOVR3216_ins<"move", IIAlu>; + +// +// Format: MFHI rx MIPS16e +// Purpose: Move From HI Register +// To copy the special purpose HI register to a GPR. +// +def Mfhi16: FRR16_M_ins<0b10000, "mfhi", IIAlu> { + let Uses = [HI0]; + let neverHasSideEffects = 1; +} + +// +// Format: MFLO rx MIPS16e +// Purpose: Move From LO Register +// To copy the special purpose LO register to a GPR. +// +def Mflo16: FRR16_M_ins<0b10010, "mflo", IIAlu> { + let Uses = [LO0]; + let neverHasSideEffects = 1; +} + +// +// Pseudo Instruction for mult +// +def MultRxRy16: FMULT16_ins<"mult", IIAlu> { + let isCommutable = 1; + let neverHasSideEffects = 1; + let Defs = [HI0, LO0]; +} + +def MultuRxRy16: FMULT16_ins<"multu", IIAlu> { + let isCommutable = 1; + let neverHasSideEffects = 1; + let Defs = [HI0, LO0]; +} + +// +// Format: MULT rx, ry MIPS16e +// Purpose: Multiply Word +// To multiply 32-bit signed integers. +// +def MultRxRyRz16: FMULT16_LO_ins<"mult", IIAlu> { + let isCommutable = 1; + let neverHasSideEffects = 1; + let Defs = [HI0, LO0]; +} + +// +// Format: MULTU rx, ry MIPS16e +// Purpose: Multiply Unsigned Word +// To multiply 32-bit unsigned integers. +// +def MultuRxRyRz16: FMULT16_LO_ins<"multu", IIAlu> { + let isCommutable = 1; + let neverHasSideEffects = 1; + let Defs = [HI0, LO0]; +} + +// +// Format: NEG rx, ry MIPS16e +// Purpose: Negate +// To negate an integer value. +// +def NegRxRy16: FUnaryRR16_ins<0b11101, "neg", IIAlu>; + +// +// Format: NOT rx, ry MIPS16e +// Purpose: Not +// To complement an integer value +// +def NotRxRy16: FUnaryRR16_ins<0b01111, "not", IIAlu>; + +// +// Format: OR rx, ry MIPS16e +// Purpose: Or +// To do a bitwise logical OR. +// +def OrRxRxRy16: FRxRxRy16_ins<0b01101, "or", IIAlu>, ArithLogic16Defs<1>; + +// +// Format: RESTORE {ra,}{s0/s1/s0-1,}{framesize} +// (All args are optional) MIPS16e +// Purpose: Restore Registers and Deallocate Stack Frame +// To deallocate a stack frame before exit from a subroutine, +// restoring return address and static registers, and adjusting +// stack +// + +// fixed form for restoring RA and the frame +// for direct object emitter, encoding needs to be adjusted for the +// frame size +// +let ra=1, s=0,s0=1,s1=1 in +def RestoreRaF16: + FI8_SVRS16<0b1, (outs), (ins uimm16:$frame_size), + "restore\t$$ra, $$s0, $$s1, $$s2, $frame_size", [], IILoad >, MayLoad { + let isCodeGenOnly = 1; + let Defs = [S0, S1, S2, RA, SP]; + let Uses = [SP]; +} + +// Use Restore to increment SP since SP is not a Mip 16 register, this +// is an easy way to do that which does not require a register. +// +let ra=0, s=0,s0=0,s1=0 in +def RestoreIncSpF16: + FI8_SVRS16<0b1, (outs), (ins uimm16:$frame_size), + "restore\t$frame_size", [], IILoad >, MayLoad { + let isCodeGenOnly = 1; + let Defs = [SP]; + let Uses = [SP]; +} + +// +// Format: SAVE {ra,}{s0/s1/s0-1,}{framesize} (All arguments are optional) +// MIPS16e +// Purpose: Save Registers and Set Up Stack Frame +// To set up a stack frame on entry to a subroutine, +// saving return address and static registers, and adjusting stack +// +let ra=1, s=1,s0=1,s1=1 in +def SaveRaF16: + FI8_SVRS16<0b1, (outs), (ins uimm16:$frame_size), + "save\t$$ra, $$s0, $$s1, $$s2, $frame_size", [], IIStore >, MayStore { + let isCodeGenOnly = 1; + let Uses = [RA, SP, S0, S1, S2]; + let Defs = [SP]; +} + +// +// Use Save to decrement the SP by a constant since SP is not +// a Mips16 register. +// +let ra=0, s=0,s0=0,s1=0 in +def SaveDecSpF16: + FI8_SVRS16<0b1, (outs), (ins uimm16:$frame_size), + "save\t$frame_size", [], IIStore >, MayStore { + let isCodeGenOnly = 1; + let Uses = [SP]; + let Defs = [SP]; +} +// +// Format: SB ry, offset(rx) MIPS16e +// Purpose: Store Byte (Extended) +// To store a byte to memory. +// +def SbRxRyOffMemX16: + FEXT_RRI16_mem2_ins<0b11000, "sb", mem16, IIStore>, MayStore; + +// +// Format: SEB rx MIPS16e +// Purpose: Sign-Extend Byte +// Sign-extend least significant byte in register rx. +// +def SebRx16 + : FRR_SF16_ins<0b10001, 0b100, "seb", IIAlu>; + +// +// Format: SEH rx MIPS16e +// Purpose: Sign-Extend Halfword +// Sign-extend least significant word in register rx. +// +def SehRx16 + : FRR_SF16_ins<0b10001, 0b101, "seh", IIAlu>; + +// +// The Sel(T) instructions are pseudos +// T means that they use T8 implicitly. +// +// +// Format: SelBeqZ rd, rs, rt +// Purpose: if rt==0, do nothing +// else rs = rt +// +def SelBeqZ: Sel<"beqz">; + +// +// Format: SelTBteqZCmp rd, rs, rl, rr +// Purpose: b = Cmp rl, rr. +// If b==0 then do nothing. +// if b!=0 then rd = rs +// +def SelTBteqZCmp: SelT<"bteqz", "cmp">; + +// +// Format: SelTBteqZCmpi rd, rs, rl, rr +// Purpose: b = Cmpi rl, imm. +// If b==0 then do nothing. +// if b!=0 then rd = rs +// +def SelTBteqZCmpi: SeliT<"bteqz", "cmpi">; + +// +// Format: SelTBteqZSlt rd, rs, rl, rr +// Purpose: b = Slt rl, rr. +// If b==0 then do nothing. +// if b!=0 then rd = rs +// +def SelTBteqZSlt: SelT<"bteqz", "slt">; + +// +// Format: SelTBteqZSlti rd, rs, rl, rr +// Purpose: b = Slti rl, imm. +// If b==0 then do nothing. +// if b!=0 then rd = rs +// +def SelTBteqZSlti: SeliT<"bteqz", "slti">; + +// +// Format: SelTBteqZSltu rd, rs, rl, rr +// Purpose: b = Sltu rl, rr. +// If b==0 then do nothing. +// if b!=0 then rd = rs +// +def SelTBteqZSltu: SelT<"bteqz", "sltu">; + +// +// Format: SelTBteqZSltiu rd, rs, rl, rr +// Purpose: b = Sltiu rl, imm. +// If b==0 then do nothing. +// if b!=0 then rd = rs +// +def SelTBteqZSltiu: SeliT<"bteqz", "sltiu">; + +// +// Format: SelBnez rd, rs, rt +// Purpose: if rt!=0, do nothing +// else rs = rt +// +def SelBneZ: Sel<"bnez">; + +// +// Format: SelTBtneZCmp rd, rs, rl, rr +// Purpose: b = Cmp rl, rr. +// If b!=0 then do nothing. +// if b0=0 then rd = rs +// +def SelTBtneZCmp: SelT<"btnez", "cmp">; + +// +// Format: SelTBtnezCmpi rd, rs, rl, rr +// Purpose: b = Cmpi rl, imm. +// If b!=0 then do nothing. +// if b==0 then rd = rs +// +def SelTBtneZCmpi: SeliT<"btnez", "cmpi">; + +// +// Format: SelTBtneZSlt rd, rs, rl, rr +// Purpose: b = Slt rl, rr. +// If b!=0 then do nothing. +// if b==0 then rd = rs +// +def SelTBtneZSlt: SelT<"btnez", "slt">; + +// +// Format: SelTBtneZSlti rd, rs, rl, rr +// Purpose: b = Slti rl, imm. +// If b!=0 then do nothing. +// if b==0 then rd = rs +// +def SelTBtneZSlti: SeliT<"btnez", "slti">; + +// +// Format: SelTBtneZSltu rd, rs, rl, rr +// Purpose: b = Sltu rl, rr. +// If b!=0 then do nothing. +// if b==0 then rd = rs +// +def SelTBtneZSltu: SelT<"btnez", "sltu">; + +// +// Format: SelTBtneZSltiu rd, rs, rl, rr +// Purpose: b = Slti rl, imm. +// If b!=0 then do nothing. +// if b==0 then rd = rs +// +def SelTBtneZSltiu: SeliT<"btnez", "sltiu">; +// +// +// Format: SH ry, offset(rx) MIPS16e +// Purpose: Store Halfword (Extended) +// To store a halfword to memory. +// +def ShRxRyOffMemX16: + FEXT_RRI16_mem2_ins<0b11001, "sh", mem16, IIStore>, MayStore; + +// +// Format: SLL rx, ry, sa MIPS16e +// Purpose: Shift Word Left Logical (Extended) +// To execute a left-shift of a word by a fixed number of bits-0 to 31 bits. +// +def SllX16: FEXT_SHIFT16_ins<0b00, "sll", IIAlu>; + +// +// Format: SLLV ry, rx MIPS16e +// Purpose: Shift Word Left Logical Variable +// To execute a left-shift of a word by a variable number of bits. +// +def SllvRxRy16 : FRxRxRy16_ins<0b00100, "sllv", IIAlu>; + +// Format: SLTI rx, immediate MIPS16e +// Purpose: Set on Less Than Immediate +// To record the result of a less-than comparison with a constant. +// +// +def SltiRxImm16: FRI16R_ins<0b01010, "slti", IIAlu> { + let Defs = [T8]; +} + +// +// Format: SLTI rx, immediate MIPS16e +// Purpose: Set on Less Than Immediate (Extended) +// To record the result of a less-than comparison with a constant. +// +// +def SltiRxImmX16: FEXT_RI16R_ins<0b01010, "slti", IIAlu> { + let Defs = [T8]; +} + +def SltiCCRxImmX16: FEXT_CCRXI16_ins<"slti">; + +// Format: SLTIU rx, immediate MIPS16e +// Purpose: Set on Less Than Immediate Unsigned +// To record the result of a less-than comparison with a constant. +// +// +def SltiuRxImm16: FRI16R_ins<0b01011, "sltiu", IIAlu> { + let Defs = [T8]; +} + +// +// Format: SLTI rx, immediate MIPS16e +// Purpose: Set on Less Than Immediate Unsigned (Extended) +// To record the result of a less-than comparison with a constant. +// +// +def SltiuRxImmX16: FEXT_RI16R_ins<0b01011, "sltiu", IIAlu> { + let Defs = [T8]; +} +// +// Format: SLTIU rx, immediate MIPS16e +// Purpose: Set on Less Than Immediate Unsigned (Extended) +// To record the result of a less-than comparison with a constant. +// +def SltiuCCRxImmX16: FEXT_CCRXI16_ins<"sltiu">; + +// +// Format: SLT rx, ry MIPS16e +// Purpose: Set on Less Than +// To record the result of a less-than comparison. +// +def SltRxRy16: FRR16R_ins<0b00010, "slt", IIAlu>{ + let Defs = [T8]; +} + +def SltCCRxRy16: FCCRR16_ins<"slt">; + +// Format: SLTU rx, ry MIPS16e +// Purpose: Set on Less Than Unsigned +// To record the result of an unsigned less-than comparison. +// +def SltuRxRy16: FRR16R_ins<0b00011, "sltu", IIAlu>{ + let Defs = [T8]; +} + +def SltuRxRyRz16: FRRTR16_ins<"sltu"> { + let isCodeGenOnly=1; + let Defs = [T8]; +} + + +def SltuCCRxRy16: FCCRR16_ins<"sltu">; +// +// Format: SRAV ry, rx MIPS16e +// Purpose: Shift Word Right Arithmetic Variable +// To execute an arithmetic right-shift of a word by a variable +// number of bits. +// +def SravRxRy16: FRxRxRy16_ins<0b00111, "srav", IIAlu>; + + +// +// Format: SRA rx, ry, sa MIPS16e +// Purpose: Shift Word Right Arithmetic (Extended) +// To execute an arithmetic right-shift of a word by a fixed +// number of bits-1 to 8 bits. +// +def SraX16: FEXT_SHIFT16_ins<0b11, "sra", IIAlu>; + + +// +// Format: SRLV ry, rx MIPS16e +// Purpose: Shift Word Right Logical Variable +// To execute a logical right-shift of a word by a variable +// number of bits. +// +def SrlvRxRy16: FRxRxRy16_ins<0b00110, "srlv", IIAlu>; + + +// +// Format: SRL rx, ry, sa MIPS16e +// Purpose: Shift Word Right Logical (Extended) +// To execute a logical right-shift of a word by a fixed +// number of bits-1 to 31 bits. +// +def SrlX16: FEXT_SHIFT16_ins<0b10, "srl", IIAlu>; + +// +// Format: SUBU rz, rx, ry MIPS16e +// Purpose: Subtract Unsigned Word +// To subtract 32-bit integers +// +def SubuRxRyRz16: FRRR16_ins<0b11, "subu", IIAlu>, ArithLogic16Defs<0>; + +// +// Format: SW ry, offset(rx) MIPS16e +// Purpose: Store Word (Extended) +// To store a word to memory. +// +def SwRxRyOffMemX16: + FEXT_RRI16_mem2_ins<0b11011, "sw", mem16, IIStore>, MayStore; + +// +// Format: SW rx, offset(sp) MIPS16e +// Purpose: Store Word rx (SP-Relative) +// To store an SP-relative word to memory. +// +def SwRxSpImmX16: FEXT_RI16_SP_Store_explicit_ins + <0b11010, "sw", IIStore>, MayStore; + +// +// +// Format: XOR rx, ry MIPS16e +// Purpose: Xor +// To do a bitwise logical XOR. +// +def XorRxRxRy16: FRxRxRy16_ins<0b01110, "xor", IIAlu>, ArithLogic16Defs<1>; + +class Mips16Pat<dag pattern, dag result> : Pat<pattern, result> { + let Predicates = [InMips16Mode]; +} + +// Unary Arith/Logic +// +class ArithLogicU_pat<PatFrag OpNode, Instruction I> : + Mips16Pat<(OpNode CPU16Regs:$r), + (I CPU16Regs:$r)>; + +def: ArithLogicU_pat<not, NotRxRy16>; +def: ArithLogicU_pat<ineg, NegRxRy16>; + +class ArithLogic16_pat<SDNode OpNode, Instruction I> : + Mips16Pat<(OpNode CPU16Regs:$l, CPU16Regs:$r), + (I CPU16Regs:$l, CPU16Regs:$r)>; + +def: ArithLogic16_pat<add, AdduRxRyRz16>; +def: ArithLogic16_pat<and, AndRxRxRy16>; +def: ArithLogic16_pat<mul, MultRxRyRz16>; +def: ArithLogic16_pat<or, OrRxRxRy16>; +def: ArithLogic16_pat<sub, SubuRxRyRz16>; +def: ArithLogic16_pat<xor, XorRxRxRy16>; + +// Arithmetic and logical instructions with 2 register operands. + +class ArithLogicI16_pat<SDNode OpNode, PatFrag imm_type, Instruction I> : + Mips16Pat<(OpNode CPU16Regs:$in, imm_type:$imm), + (I CPU16Regs:$in, imm_type:$imm)>; + +def: ArithLogicI16_pat<add, immSExt8, AddiuRxRxImm16>; +def: ArithLogicI16_pat<add, immSExt16, AddiuRxRxImmX16>; +def: ArithLogicI16_pat<shl, immZExt5, SllX16>; +def: ArithLogicI16_pat<srl, immZExt5, SrlX16>; +def: ArithLogicI16_pat<sra, immZExt5, SraX16>; + +class shift_rotate_reg16_pat<SDNode OpNode, Instruction I> : + Mips16Pat<(OpNode CPU16Regs:$r, CPU16Regs:$ra), + (I CPU16Regs:$r, CPU16Regs:$ra)>; + +def: shift_rotate_reg16_pat<shl, SllvRxRy16>; +def: shift_rotate_reg16_pat<sra, SravRxRy16>; +def: shift_rotate_reg16_pat<srl, SrlvRxRy16>; + +class LoadM16_pat<PatFrag OpNode, Instruction I> : + Mips16Pat<(OpNode addr16:$addr), (I addr16:$addr)>; + +def: LoadM16_pat<sextloadi8, LbRxRyOffMemX16>; +def: LoadM16_pat<zextloadi8, LbuRxRyOffMemX16>; +def: LoadM16_pat<sextloadi16, LhRxRyOffMemX16>; +def: LoadM16_pat<zextloadi16, LhuRxRyOffMemX16>; +def: LoadM16_pat<load, LwRxRyOffMemX16>; + +class StoreM16_pat<PatFrag OpNode, Instruction I> : + Mips16Pat<(OpNode CPU16Regs:$r, addr16:$addr), + (I CPU16Regs:$r, addr16:$addr)>; + +def: StoreM16_pat<truncstorei8, SbRxRyOffMemX16>; +def: StoreM16_pat<truncstorei16, ShRxRyOffMemX16>; +def: StoreM16_pat<store, SwRxRyOffMemX16>; + +// Unconditional branch +class UncondBranch16_pat<SDNode OpNode, Instruction I>: + Mips16Pat<(OpNode bb:$imm16), (I bb:$imm16)> { + let Predicates = [InMips16Mode]; + } + +def : Mips16Pat<(MipsJmpLink (i32 tglobaladdr:$dst)), + (Jal16 tglobaladdr:$dst)>; + +def : Mips16Pat<(MipsJmpLink (i32 texternalsym:$dst)), + (Jal16 texternalsym:$dst)>; + +// Indirect branch +def: Mips16Pat< + (brind CPU16Regs:$rs), + (JrcRx16 CPU16Regs:$rs)>; + +// Jump and Link (Call) +let isCall=1, hasDelaySlot=0 in +def JumpLinkReg16: + FRR16_JALRC<0, 0, 0, (outs), (ins CPU16Regs:$rs), + "jalrc \t$rs", [(MipsJmpLink CPU16Regs:$rs)], IIBranch>; + +// Mips16 pseudos +let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, hasCtrlDep=1, + hasExtraSrcRegAllocReq = 1 in +def RetRA16 : MipsPseudo16<(outs), (ins), "", [(MipsRet)]>; + + +// setcc patterns + +class SetCC_R16<PatFrag cond_op, Instruction I>: + Mips16Pat<(cond_op CPU16Regs:$rx, CPU16Regs:$ry), + (I CPU16Regs:$rx, CPU16Regs:$ry)>; + +class SetCC_I16<PatFrag cond_op, PatLeaf imm_type, Instruction I>: + Mips16Pat<(cond_op CPU16Regs:$rx, imm_type:$imm16), + (I CPU16Regs:$rx, imm_type:$imm16)>; + + +def: Mips16Pat<(i32 addr16:$addr), + (AddiuRxRyOffMemX16 addr16:$addr)>; + + +// Large (>16 bit) immediate loads +def : Mips16Pat<(i32 imm:$imm), (LwConstant32 imm:$imm, -1)>; + +// Carry MipsPatterns +def : Mips16Pat<(subc CPU16Regs:$lhs, CPU16Regs:$rhs), + (SubuRxRyRz16 CPU16Regs:$lhs, CPU16Regs:$rhs)>; +def : Mips16Pat<(addc CPU16Regs:$lhs, CPU16Regs:$rhs), + (AdduRxRyRz16 CPU16Regs:$lhs, CPU16Regs:$rhs)>; +def : Mips16Pat<(addc CPU16Regs:$src, immSExt16:$imm), + (AddiuRxRxImmX16 CPU16Regs:$src, imm:$imm)>; + +// +// Some branch conditional patterns are not generated by llvm at this time. +// Some are for seemingly arbitrary reasons not used: i.e. with signed number +// comparison they are used and for unsigned a different pattern is used. +// I am pushing upstream from the full mips16 port and it seemed that I needed +// these earlier and the mips32 port has these but now I cannot create test +// cases that use these patterns. While I sort this all out I will leave these +// extra patterns commented out and if I can be sure they are really not used, +// I will delete the code. I don't want to check the code in uncommented without +// a valid test case. In some cases, the compiler is generating patterns with +// setcc instead and earlier I had implemented setcc first so may have masked +// the problem. The setcc variants are suboptimal for mips16 so I may wantto +// figure out how to enable the brcond patterns or else possibly new +// combinations of of brcond and setcc. +// +// +// bcond-seteq +// +def: Mips16Pat + <(brcond (i32 (seteq CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), + (BteqzT8CmpX16 CPU16Regs:$rx, CPU16Regs:$ry, bb:$imm16) + >; + + +def: Mips16Pat + <(brcond (i32 (seteq CPU16Regs:$rx, immZExt16:$imm)), bb:$targ16), + (BteqzT8CmpiX16 CPU16Regs:$rx, immSExt16:$imm, bb:$targ16) + >; + +def: Mips16Pat + <(brcond (i32 (seteq CPU16Regs:$rx, 0)), bb:$targ16), + (BeqzRxImm16 CPU16Regs:$rx, bb:$targ16) + >; + +// +// bcond-setgt (do we need to have this pair of setlt, setgt??) +// +def: Mips16Pat + <(brcond (i32 (setgt CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), + (BtnezT8SltX16 CPU16Regs:$ry, CPU16Regs:$rx, bb:$imm16) + >; + +// +// bcond-setge +// +def: Mips16Pat + <(brcond (i32 (setge CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), + (BteqzT8SltX16 CPU16Regs:$rx, CPU16Regs:$ry, bb:$imm16) + >; + +// +// never called because compiler transforms a >= k to a > (k-1) +def: Mips16Pat + <(brcond (i32 (setge CPU16Regs:$rx, immSExt16:$imm)), bb:$imm16), + (BteqzT8SltiX16 CPU16Regs:$rx, immSExt16:$imm, bb:$imm16) + >; + +// +// bcond-setlt +// +def: Mips16Pat + <(brcond (i32 (setlt CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), + (BtnezT8SltX16 CPU16Regs:$rx, CPU16Regs:$ry, bb:$imm16) + >; + +def: Mips16Pat + <(brcond (i32 (setlt CPU16Regs:$rx, immSExt16:$imm)), bb:$imm16), + (BtnezT8SltiX16 CPU16Regs:$rx, immSExt16:$imm, bb:$imm16) + >; + +// +// bcond-setle +// +def: Mips16Pat + <(brcond (i32 (setle CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), + (BteqzT8SltX16 CPU16Regs:$ry, CPU16Regs:$rx, bb:$imm16) + >; + +// +// bcond-setne +// +def: Mips16Pat + <(brcond (i32 (setne CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), + (BtnezT8CmpX16 CPU16Regs:$rx, CPU16Regs:$ry, bb:$imm16) + >; + +def: Mips16Pat + <(brcond (i32 (setne CPU16Regs:$rx, immZExt16:$imm)), bb:$targ16), + (BtnezT8CmpiX16 CPU16Regs:$rx, immSExt16:$imm, bb:$targ16) + >; + +def: Mips16Pat + <(brcond (i32 (setne CPU16Regs:$rx, 0)), bb:$targ16), + (BnezRxImm16 CPU16Regs:$rx, bb:$targ16) + >; + +// +// This needs to be there but I forget which code will generate it +// +def: Mips16Pat + <(brcond CPU16Regs:$rx, bb:$targ16), + (BnezRxImm16 CPU16Regs:$rx, bb:$targ16) + >; + +// + +// +// bcond-setugt +// +//def: Mips16Pat +// <(brcond (i32 (setugt CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), +// (BtnezT8SltuX16 CPU16Regs:$ry, CPU16Regs:$rx, bb:$imm16) +// >; + +// +// bcond-setuge +// +//def: Mips16Pat +// <(brcond (i32 (setuge CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), +// (BteqzT8SltuX16 CPU16Regs:$rx, CPU16Regs:$ry, bb:$imm16) +// >; + + +// +// bcond-setult +// +//def: Mips16Pat +// <(brcond (i32 (setult CPU16Regs:$rx, CPU16Regs:$ry)), bb:$imm16), +// (BtnezT8SltuX16 CPU16Regs:$rx, CPU16Regs:$ry, bb:$imm16) +// >; + +def: UncondBranch16_pat<br, Bimm16>; + +// Small immediates +def: Mips16Pat<(i32 immSExt16:$in), + (AddiuRxRxImmX16 (Move32R16 ZERO), immSExt16:$in)>; + +def: Mips16Pat<(i32 immZExt16:$in), (LiRxImmX16 immZExt16:$in)>; + +// +// MipsDivRem +// +def: Mips16Pat + <(MipsDivRem16 CPU16Regs:$rx, CPU16Regs:$ry), + (DivRxRy16 CPU16Regs:$rx, CPU16Regs:$ry)>; + +// +// MipsDivRemU +// +def: Mips16Pat + <(MipsDivRemU16 CPU16Regs:$rx, CPU16Regs:$ry), + (DivuRxRy16 CPU16Regs:$rx, CPU16Regs:$ry)>; + +// signed a,b +// x = (a>=b)?x:y +// +// if !(a < b) x = y +// +def : Mips16Pat<(select (i32 (setge CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBteqZSlt CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a, CPU16Regs:$b)>; + +// signed a,b +// x = (a>b)?x:y +// +// if (b < a) x = y +// +def : Mips16Pat<(select (i32 (setgt CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBtneZSlt CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$b, CPU16Regs:$a)>; + +// unsigned a,b +// x = (a>=b)?x:y +// +// if !(a < b) x = y; +// +def : Mips16Pat< + (select (i32 (setuge CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBteqZSltu CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a, CPU16Regs:$b)>; + +// unsigned a,b +// x = (a>b)?x:y +// +// if (b < a) x = y +// +def : Mips16Pat<(select (i32 (setugt CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBtneZSltu CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$b, CPU16Regs:$a)>; + +// signed +// x = (a >= k)?x:y +// due to an llvm optimization, i don't think that this will ever +// be used. This is transformed into x = (a > k-1)?x:y +// +// + +//def : Mips16Pat< +// (select (i32 (setge CPU16Regs:$lhs, immSExt16:$rhs)), +// CPU16Regs:$T, CPU16Regs:$F), +// (SelTBteqZSlti CPU16Regs:$T, CPU16Regs:$F, +// CPU16Regs:$lhs, immSExt16:$rhs)>; + +//def : Mips16Pat< +// (select (i32 (setuge CPU16Regs:$lhs, immSExt16:$rhs)), +// CPU16Regs:$T, CPU16Regs:$F), +// (SelTBteqZSltiu CPU16Regs:$T, CPU16Regs:$F, +// CPU16Regs:$lhs, immSExt16:$rhs)>; + +// signed +// x = (a < k)?x:y +// +// if !(a < k) x = y; +// +def : Mips16Pat< + (select (i32 (setlt CPU16Regs:$a, immSExt16:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBtneZSlti CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a, immSExt16:$b)>; + + +// +// +// signed +// x = (a <= b)? x : y +// +// if (b < a) x = y +// +def : Mips16Pat<(select (i32 (setle CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBteqZSlt CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$b, CPU16Regs:$a)>; + +// +// unnsigned +// x = (a <= b)? x : y +// +// if (b < a) x = y +// +def : Mips16Pat<(select (i32 (setule CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBteqZSltu CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$b, CPU16Regs:$a)>; + +// +// signed/unsigned +// x = (a == b)? x : y +// +// if (a != b) x = y +// +def : Mips16Pat<(select (i32 (seteq CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBteqZCmp CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$b, CPU16Regs:$a)>; + +// +// signed/unsigned +// x = (a == 0)? x : y +// +// if (a != 0) x = y +// +def : Mips16Pat<(select (i32 (seteq CPU16Regs:$a, 0)), + CPU16Regs:$x, CPU16Regs:$y), + (SelBeqZ CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a)>; + + +// +// signed/unsigned +// x = (a == k)? x : y +// +// if (a != k) x = y +// +def : Mips16Pat<(select (i32 (seteq CPU16Regs:$a, immZExt16:$k)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBteqZCmpi CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a, immZExt16:$k)>; + + +// +// signed/unsigned +// x = (a != b)? x : y +// +// if (a == b) x = y +// +// +def : Mips16Pat<(select (i32 (setne CPU16Regs:$a, CPU16Regs:$b)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBtneZCmp CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$b, CPU16Regs:$a)>; + +// +// signed/unsigned +// x = (a != 0)? x : y +// +// if (a == 0) x = y +// +def : Mips16Pat<(select (i32 (setne CPU16Regs:$a, 0)), + CPU16Regs:$x, CPU16Regs:$y), + (SelBneZ CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a)>; + +// signed/unsigned +// x = (a)? x : y +// +// if (!a) x = y +// +def : Mips16Pat<(select CPU16Regs:$a, + CPU16Regs:$x, CPU16Regs:$y), + (SelBneZ CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a)>; + + +// +// signed/unsigned +// x = (a != k)? x : y +// +// if (a == k) x = y +// +def : Mips16Pat<(select (i32 (setne CPU16Regs:$a, immZExt16:$k)), + CPU16Regs:$x, CPU16Regs:$y), + (SelTBtneZCmpi CPU16Regs:$x, CPU16Regs:$y, + CPU16Regs:$a, immZExt16:$k)>; + +// +// When writing C code to test setxx these patterns, +// some will be transformed into +// other things. So we test using C code but using -O3 and -O0 +// +// seteq +// +def : Mips16Pat + <(seteq CPU16Regs:$lhs,CPU16Regs:$rhs), + (SltiuCCRxImmX16 (XorRxRxRy16 CPU16Regs:$lhs, CPU16Regs:$rhs), 1)>; + +def : Mips16Pat + <(seteq CPU16Regs:$lhs, 0), + (SltiuCCRxImmX16 CPU16Regs:$lhs, 1)>; + + +// +// setge +// + +def: Mips16Pat + <(setge CPU16Regs:$lhs, CPU16Regs:$rhs), + (XorRxRxRy16 (SltCCRxRy16 CPU16Regs:$lhs, CPU16Regs:$rhs), + (LiRxImmX16 1))>; + +// +// For constants, llvm transforms this to: +// x > (k -1) and then reverses the operands to use setlt. So this pattern +// is not used now by the compiler. (Presumably checking that k-1 does not +// overflow). The compiler never uses this at a the current time, due to +// other optimizations. +// +//def: Mips16Pat +// <(setge CPU16Regs:$lhs, immSExt16:$rhs), +// (XorRxRxRy16 (SltiCCRxImmX16 CPU16Regs:$lhs, immSExt16:$rhs), +// (LiRxImmX16 1))>; + +// This catches the x >= -32768 case by transforming it to x > -32769 +// +def: Mips16Pat + <(setgt CPU16Regs:$lhs, -32769), + (XorRxRxRy16 (SltiCCRxImmX16 CPU16Regs:$lhs, -32768), + (LiRxImmX16 1))>; + +// +// setgt +// +// + +def: Mips16Pat + <(setgt CPU16Regs:$lhs, CPU16Regs:$rhs), + (SltCCRxRy16 CPU16Regs:$rhs, CPU16Regs:$lhs)>; + +// +// setle +// +def: Mips16Pat + <(setle CPU16Regs:$lhs, CPU16Regs:$rhs), + (XorRxRxRy16 (SltCCRxRy16 CPU16Regs:$rhs, CPU16Regs:$lhs), (LiRxImm16 1))>; + +// +// setlt +// +def: SetCC_R16<setlt, SltCCRxRy16>; + +def: SetCC_I16<setlt, immSExt16, SltiCCRxImmX16>; + +// +// setne +// +def : Mips16Pat + <(setne CPU16Regs:$lhs,CPU16Regs:$rhs), + (SltuCCRxRy16 (LiRxImmX16 0), + (XorRxRxRy16 CPU16Regs:$lhs, CPU16Regs:$rhs))>; + + +// +// setuge +// +def: Mips16Pat + <(setuge CPU16Regs:$lhs, CPU16Regs:$rhs), + (XorRxRxRy16 (SltuCCRxRy16 CPU16Regs:$lhs, CPU16Regs:$rhs), + (LiRxImmX16 1))>; + +// this pattern will never be used because the compiler will transform +// x >= k to x > (k - 1) and then use SLT +// +//def: Mips16Pat +// <(setuge CPU16Regs:$lhs, immZExt16:$rhs), +// (XorRxRxRy16 (SltiuCCRxImmX16 CPU16Regs:$lhs, immZExt16:$rhs), +// (LiRxImmX16 1))>; + +// +// setugt +// +def: Mips16Pat + <(setugt CPU16Regs:$lhs, CPU16Regs:$rhs), + (SltuCCRxRy16 CPU16Regs:$rhs, CPU16Regs:$lhs)>; + +// +// setule +// +def: Mips16Pat + <(setule CPU16Regs:$lhs, CPU16Regs:$rhs), + (XorRxRxRy16 (SltuCCRxRy16 CPU16Regs:$rhs, CPU16Regs:$lhs), (LiRxImmX16 1))>; + +// +// setult +// +def: SetCC_R16<setult, SltuCCRxRy16>; + +def: SetCC_I16<setult, immSExt16, SltiuCCRxImmX16>; + +def: Mips16Pat<(add CPU16Regs:$hi, (MipsLo tglobaladdr:$lo)), + (AddiuRxRxImmX16 CPU16Regs:$hi, tglobaladdr:$lo)>; + +// hi/lo relocs +def : Mips16Pat<(MipsHi tblockaddress:$in), + (SllX16 (LiRxImmX16 tblockaddress:$in), 16)>; +def : Mips16Pat<(MipsHi tglobaladdr:$in), + (SllX16 (LiRxImmX16 tglobaladdr:$in), 16)>; +def : Mips16Pat<(MipsHi tjumptable:$in), + (SllX16 (LiRxImmX16 tjumptable:$in), 16)>; +def : Mips16Pat<(MipsHi tglobaltlsaddr:$in), + (SllX16 (LiRxImmX16 tglobaltlsaddr:$in), 16)>; + +def : Mips16Pat<(MipsLo tblockaddress:$in), (LiRxImmX16 tblockaddress:$in)>; + +// wrapper_pic +class Wrapper16Pat<SDNode node, Instruction ADDiuOp, RegisterClass RC>: + Mips16Pat<(MipsWrapper RC:$gp, node:$in), + (ADDiuOp RC:$gp, node:$in)>; + + +def : Wrapper16Pat<tglobaladdr, AddiuRxRxImmX16, CPU16Regs>; +def : Wrapper16Pat<tglobaltlsaddr, AddiuRxRxImmX16, CPU16Regs>; + +def : Mips16Pat<(i32 (extloadi8 addr16:$src)), + (LbuRxRyOffMemX16 addr16:$src)>; +def : Mips16Pat<(i32 (extloadi16 addr16:$src)), + (LhuRxRyOffMemX16 addr16:$src)>; + +def: Mips16Pat<(trap), (Break16)>; + +def : Mips16Pat<(sext_inreg CPU16Regs:$val, i8), + (SebRx16 CPU16Regs:$val)>; + +def : Mips16Pat<(sext_inreg CPU16Regs:$val, i16), + (SehRx16 CPU16Regs:$val)>; + +def GotPrologue16: + MipsPseudo16< + (outs CPU16Regs:$rh, CPU16Regs:$rl), + (ins simm16:$immHi, simm16:$immLo), + ".align 2\n\tli\t$rh, $immHi\n\taddiu\t$rl, $$pc, $immLo\n ",[]> ; + +// An operand for the CONSTPOOL_ENTRY pseudo-instruction. +def cpinst_operand : Operand<i32> { + // let PrintMethod = "printCPInstOperand"; +} + +// CONSTPOOL_ENTRY - This instruction represents a floating constant pool in +// the function. The first operand is the ID# for this instruction, the second +// is the index into the MachineConstantPool that this is, the third is the +// size in bytes of this constant pool entry. +// +let neverHasSideEffects = 1, isNotDuplicable = 1 in +def CONSTPOOL_ENTRY : +MipsPseudo16<(outs), (ins cpinst_operand:$instid, cpinst_operand:$cpidx, + i32imm:$size), "foo", []>; + diff --git a/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.cpp b/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.cpp new file mode 100644 index 000000000000..9d0f2c927e4d --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.cpp @@ -0,0 +1,153 @@ +//===-- Mips16RegisterInfo.cpp - MIPS16 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 MIPS16 implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#include "Mips16RegisterInfo.h" +#include "Mips16InstrInfo.h" +#include "Mips.h" +#include "Mips16InstrInfo.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsInstrInfo.h" +#include "MipsMachineFunction.h" +#include "MipsSubtarget.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/DebugInfo.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +Mips16RegisterInfo::Mips16RegisterInfo(const MipsSubtarget &ST) + : MipsRegisterInfo(ST) {} + +bool Mips16RegisterInfo::requiresRegisterScavenging + (const MachineFunction &MF) const { + return false; +} +bool Mips16RegisterInfo::requiresFrameIndexScavenging + (const MachineFunction &MF) const { + return false; +} + +bool Mips16RegisterInfo::useFPForScavengingIndex + (const MachineFunction &MF) const { + return false; +} + +bool Mips16RegisterInfo::saveScavengerRegister + (MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + MachineBasicBlock::iterator &UseMI, + const TargetRegisterClass *RC, + unsigned Reg) const { + DebugLoc DL; + const TargetInstrInfo &TII = *MBB.getParent()->getTarget().getInstrInfo(); + TII.copyPhysReg(MBB, I, DL, Mips::T0, Reg, true); + TII.copyPhysReg(MBB, UseMI, DL, Reg, Mips::T0, true); + return true; +} + +const TargetRegisterClass * +Mips16RegisterInfo::intRegClass(unsigned Size) const { + assert(Size == 4); + return &Mips::CPU16RegsRegClass; +} + +void Mips16RegisterInfo::eliminateFI(MachineBasicBlock::iterator II, + unsigned OpNo, int FrameIndex, + uint64_t StackSize, + int64_t SPOffset) const { + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + int MinCSFI = 0; + int MaxCSFI = -1; + + if (CSI.size()) { + MinCSFI = CSI[0].getFrameIdx(); + MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); + } + + // The following stack frame objects are always + // referenced relative to $sp: + // 1. Outgoing arguments. + // 2. Pointer to dynamically allocated stack space. + // 3. Locations for callee-saved registers. + // Everything else is referenced relative to whatever register + // getFrameRegister() returns. + unsigned FrameReg; + + if (FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI) + FrameReg = Mips::SP; + else { + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + if (TFI->hasFP(MF)) { + FrameReg = Mips::S0; + } + else { + if ((MI.getNumOperands()> OpNo+2) && MI.getOperand(OpNo+2).isReg()) + FrameReg = MI.getOperand(OpNo+2).getReg(); + else + FrameReg = Mips::SP; + } + } + // Calculate final offset. + // - There is no need to change the offset if the frame object + // is one of the + // following: an outgoing argument, pointer to a dynamically allocated + // stack space or a $gp restore location, + // - If the frame object is any of the following, + // its offset must be adjusted + // by adding the size of the stack: + // incoming argument, callee-saved register location or local variable. + int64_t Offset; + bool IsKill = false; + Offset = SPOffset + (int64_t)StackSize; + Offset += MI.getOperand(OpNo + 1).getImm(); + + + DEBUG(errs() << "Offset : " << Offset << "\n" << "<--------->\n"); + + if (!MI.isDebugValue() && + !Mips16InstrInfo::validImmediate(MI.getOpcode(), FrameReg, Offset)) { + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc DL = II->getDebugLoc(); + unsigned NewImm; + const Mips16InstrInfo &TII = + *static_cast<const Mips16InstrInfo*>( + MBB.getParent()->getTarget().getInstrInfo()); + FrameReg = TII.loadImmediate(FrameReg, Offset, MBB, II, DL, NewImm); + Offset = SignExtend64<16>(NewImm); + IsKill = true; + } + MI.getOperand(OpNo).ChangeToRegister(FrameReg, false, false, IsKill); + MI.getOperand(OpNo + 1).ChangeToImmediate(Offset); + + +} diff --git a/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.h b/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.h new file mode 100644 index 000000000000..13e82a3ffba9 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips16RegisterInfo.h @@ -0,0 +1,48 @@ +//===-- Mips16RegisterInfo.h - Mips16 Register 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 Mips16 implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPS16REGISTERINFO_H +#define MIPS16REGISTERINFO_H + +#include "MipsRegisterInfo.h" + +namespace llvm { +class Mips16InstrInfo; + +class Mips16RegisterInfo : public MipsRegisterInfo { +public: + Mips16RegisterInfo(const MipsSubtarget &Subtarget); + + bool requiresRegisterScavenging(const MachineFunction &MF) const; + + bool requiresFrameIndexScavenging(const MachineFunction &MF) const; + + bool useFPForScavengingIndex(const MachineFunction &MF) const; + + bool saveScavengerRegister(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + MachineBasicBlock::iterator &UseMI, + const TargetRegisterClass *RC, + unsigned Reg) const; + + virtual const TargetRegisterClass *intRegClass(unsigned Size) const; + +private: + virtual void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo, + int FrameIndex, uint64_t StackSize, + int64_t SPOffset) const; +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td b/contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td new file mode 100644 index 000000000000..15ef654555d6 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/Mips64InstrInfo.td @@ -0,0 +1,330 @@ +//===- Mips64InstrInfo.td - Mips64 Instruction Information -*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Mips64 instructions. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Mips Operand, Complex Patterns and Transformations Definitions. +//===----------------------------------------------------------------------===// + +// Unsigned Operand +def uimm16_64 : Operand<i64> { + let PrintMethod = "printUnsignedImm"; +} + +// Transformation Function - get Imm - 32. +def Subtract32 : SDNodeXForm<imm, [{ + return getImm(N, (unsigned)N->getZExtValue() - 32); +}]>; + +// shamt must fit in 6 bits. +def immZExt6 : ImmLeaf<i32, [{return Imm == (Imm & 0x3f);}]>; + +//===----------------------------------------------------------------------===// +// Instructions specific format +//===----------------------------------------------------------------------===// +let usesCustomInserter = 1 in { + def ATOMIC_LOAD_ADD_I64 : Atomic2Ops<atomic_load_add_64, GPR64>; + def ATOMIC_LOAD_SUB_I64 : Atomic2Ops<atomic_load_sub_64, GPR64>; + def ATOMIC_LOAD_AND_I64 : Atomic2Ops<atomic_load_and_64, GPR64>; + def ATOMIC_LOAD_OR_I64 : Atomic2Ops<atomic_load_or_64, GPR64>; + def ATOMIC_LOAD_XOR_I64 : Atomic2Ops<atomic_load_xor_64, GPR64>; + def ATOMIC_LOAD_NAND_I64 : Atomic2Ops<atomic_load_nand_64, GPR64>; + def ATOMIC_SWAP_I64 : Atomic2Ops<atomic_swap_64, GPR64>; + def ATOMIC_CMP_SWAP_I64 : AtomicCmpSwap<atomic_cmp_swap_64, GPR64>; +} + +/// Pseudo instructions for loading and storing accumulator registers. +let isPseudo = 1, isCodeGenOnly = 1 in { + def LOAD_ACC128 : Load<"", ACC128>; + def STORE_ACC128 : Store<"", ACC128>; +} + +//===----------------------------------------------------------------------===// +// Instruction definition +//===----------------------------------------------------------------------===// +let DecoderNamespace = "Mips64" in { +/// Arithmetic Instructions (ALU Immediate) +def DADDi : ArithLogicI<"daddi", simm16_64, GPR64Opnd>, ADDI_FM<0x18>; +def DADDiu : ArithLogicI<"daddiu", simm16_64, GPR64Opnd, IIArith, + immSExt16, add>, + ADDI_FM<0x19>, IsAsCheapAsAMove; + +let isCodeGenOnly = 1 in { +def SLTi64 : SetCC_I<"slti", setlt, simm16_64, immSExt16, GPR64Opnd>, + SLTI_FM<0xa>; +def SLTiu64 : SetCC_I<"sltiu", setult, simm16_64, immSExt16, GPR64Opnd>, + SLTI_FM<0xb>; +def ANDi64 : ArithLogicI<"andi", uimm16_64, GPR64Opnd, IILogic, immZExt16, + and>, + ADDI_FM<0xc>; +def ORi64 : ArithLogicI<"ori", uimm16_64, GPR64Opnd, IILogic, immZExt16, + or>, + ADDI_FM<0xd>; +def XORi64 : ArithLogicI<"xori", uimm16_64, GPR64Opnd, IILogic, immZExt16, + xor>, + ADDI_FM<0xe>; +def LUi64 : LoadUpper<"lui", GPR64Opnd, uimm16_64>, LUI_FM; +} + +/// Arithmetic Instructions (3-Operand, R-Type) +def DADD : ArithLogicR<"dadd", GPR64Opnd>, ADD_FM<0, 0x2c>; +def DADDu : ArithLogicR<"daddu", GPR64Opnd, 1, IIArith, add>, + ADD_FM<0, 0x2d>; +def DSUBu : ArithLogicR<"dsubu", GPR64Opnd, 0, IIArith, sub>, + ADD_FM<0, 0x2f>; + +let isCodeGenOnly = 1 in { +def SLT64 : SetCC_R<"slt", setlt, GPR64Opnd>, ADD_FM<0, 0x2a>; +def SLTu64 : SetCC_R<"sltu", setult, GPR64Opnd>, ADD_FM<0, 0x2b>; +def AND64 : ArithLogicR<"and", GPR64Opnd, 1, IIArith, and>, ADD_FM<0, 0x24>; +def OR64 : ArithLogicR<"or", GPR64Opnd, 1, IIArith, or>, ADD_FM<0, 0x25>; +def XOR64 : ArithLogicR<"xor", GPR64Opnd, 1, IIArith, xor>, ADD_FM<0, 0x26>; +def NOR64 : LogicNOR<"nor", GPR64Opnd>, ADD_FM<0, 0x27>; +} + +/// Shift Instructions +def DSLL : shift_rotate_imm<"dsll", uimm6, GPR64Opnd, shl, immZExt6>, + SRA_FM<0x38, 0>; +def DSRL : shift_rotate_imm<"dsrl", uimm6, GPR64Opnd, srl, immZExt6>, + SRA_FM<0x3a, 0>; +def DSRA : shift_rotate_imm<"dsra", uimm6, GPR64Opnd, sra, immZExt6>, + SRA_FM<0x3b, 0>; +def DSLLV : shift_rotate_reg<"dsllv", GPR64Opnd, shl>, SRLV_FM<0x14, 0>; +def DSRLV : shift_rotate_reg<"dsrlv", GPR64Opnd, srl>, SRLV_FM<0x16, 0>; +def DSRAV : shift_rotate_reg<"dsrav", GPR64Opnd, sra>, SRLV_FM<0x17, 0>; +def DSLL32 : shift_rotate_imm<"dsll32", uimm5, GPR64Opnd>, SRA_FM<0x3c, 0>; +def DSRL32 : shift_rotate_imm<"dsrl32", uimm5, GPR64Opnd>, SRA_FM<0x3e, 0>; +def DSRA32 : shift_rotate_imm<"dsra32", uimm5, GPR64Opnd>, SRA_FM<0x3f, 0>; + +// Rotate Instructions +let Predicates = [HasMips64r2, HasStdEnc] in { + def DROTR : shift_rotate_imm<"drotr", uimm6, GPR64Opnd, rotr, immZExt6>, + SRA_FM<0x3a, 1>; + def DROTRV : shift_rotate_reg<"drotrv", GPR64Opnd, rotr>, + SRLV_FM<0x16, 1>; + def DROTR32 : shift_rotate_imm<"drotr32", uimm5, GPR64Opnd>, SRA_FM<0x3e, 1>; +} + +/// Load and Store Instructions +/// aligned +let isCodeGenOnly = 1 in { +def LB64 : Load<"lb", GPR64Opnd, sextloadi8, IILoad>, LW_FM<0x20>; +def LBu64 : Load<"lbu", GPR64Opnd, zextloadi8, IILoad>, LW_FM<0x24>; +def LH64 : Load<"lh", GPR64Opnd, sextloadi16, IILoad>, LW_FM<0x21>; +def LHu64 : Load<"lhu", GPR64Opnd, zextloadi16, IILoad>, LW_FM<0x25>; +def LW64 : Load<"lw", GPR64Opnd, sextloadi32, IILoad>, LW_FM<0x23>; +def SB64 : Store<"sb", GPR64Opnd, truncstorei8, IIStore>, LW_FM<0x28>; +def SH64 : Store<"sh", GPR64Opnd, truncstorei16, IIStore>, LW_FM<0x29>; +def SW64 : Store<"sw", GPR64Opnd, truncstorei32, IIStore>, LW_FM<0x2b>; +} + +def LWu : Load<"lwu", GPR64Opnd, zextloadi32, IILoad>, LW_FM<0x27>; +def LD : Load<"ld", GPR64Opnd, load, IILoad>, LW_FM<0x37>; +def SD : Store<"sd", GPR64Opnd, store, IIStore>, LW_FM<0x3f>; + +/// load/store left/right +let isCodeGenOnly = 1 in { +def LWL64 : LoadLeftRight<"lwl", MipsLWL, GPR64Opnd, IILoad>, LW_FM<0x22>; +def LWR64 : LoadLeftRight<"lwr", MipsLWR, GPR64Opnd, IILoad>, LW_FM<0x26>; +def SWL64 : StoreLeftRight<"swl", MipsSWL, GPR64Opnd, IIStore>, LW_FM<0x2a>; +def SWR64 : StoreLeftRight<"swr", MipsSWR, GPR64Opnd, IIStore>, LW_FM<0x2e>; +} + +def LDL : LoadLeftRight<"ldl", MipsLDL, GPR64Opnd, IILoad>, LW_FM<0x1a>; +def LDR : LoadLeftRight<"ldr", MipsLDR, GPR64Opnd, IILoad>, LW_FM<0x1b>; +def SDL : StoreLeftRight<"sdl", MipsSDL, GPR64Opnd, IIStore>, LW_FM<0x2c>; +def SDR : StoreLeftRight<"sdr", MipsSDR, GPR64Opnd, IIStore>, LW_FM<0x2d>; + +/// Load-linked, Store-conditional +def LLD : LLBase<"lld", GPR64Opnd>, LW_FM<0x34>; +def SCD : SCBase<"scd", GPR64Opnd>, LW_FM<0x3c>; + +/// Jump and Branch Instructions +let isCodeGenOnly = 1 in { +def JR64 : IndirectBranch<"jr", GPR64Opnd>, MTLO_FM<8>; +def BEQ64 : CBranch<"beq", brtarget, seteq, GPR64Opnd>, BEQ_FM<4>; +def BNE64 : CBranch<"bne", brtarget, setne, GPR64Opnd>, BEQ_FM<5>; +def BGEZ64 : CBranchZero<"bgez", brtarget, setge, GPR64Opnd>, BGEZ_FM<1, 1>; +def BGTZ64 : CBranchZero<"bgtz", brtarget, setgt, GPR64Opnd>, BGEZ_FM<7, 0>; +def BLEZ64 : CBranchZero<"blez", brtarget, setle, GPR64Opnd>, BGEZ_FM<6, 0>; +def BLTZ64 : CBranchZero<"bltz", brtarget, setlt, GPR64Opnd>, BGEZ_FM<1, 0>; +def JALR64 : JumpLinkReg<"jalr", GPR64Opnd>, JALR_FM; +def JALR64Pseudo : JumpLinkRegPseudo<GPR64Opnd, JALR, RA, GPR32Opnd>; +def TAILCALL64_R : JumpFR<"tcallr", GPR64Opnd, MipsTailCall>, + MTLO_FM<8>, IsTailCall; +} + +/// Multiply and Divide Instructions. +def DMULT : Mult<"dmult", IIImult, GPR64Opnd, [HI0_64, LO0_64]>, + MULT_FM<0, 0x1c>; +def DMULTu : Mult<"dmultu", IIImult, GPR64Opnd, [HI0_64, LO0_64]>, + MULT_FM<0, 0x1d>; +def PseudoDMULT : MultDivPseudo<DMULT, ACC128, GPR64Opnd, MipsMult, + IIImult>; +def PseudoDMULTu : MultDivPseudo<DMULTu, ACC128, GPR64Opnd, MipsMultu, + IIImult>; +def DSDIV : Div<"ddiv", IIIdiv, GPR64Opnd, [HI0_64, LO0_64]>, MULT_FM<0, 0x1e>; +def DUDIV : Div<"ddivu", IIIdiv, GPR64Opnd, [HI0_64, LO0_64]>, MULT_FM<0, 0x1f>; +def PseudoDSDIV : MultDivPseudo<DSDIV, ACC128, GPR64Opnd, MipsDivRem, + IIIdiv, 0, 1, 1>; +def PseudoDUDIV : MultDivPseudo<DUDIV, ACC128, GPR64Opnd, MipsDivRemU, + IIIdiv, 0, 1, 1>; + +let isCodeGenOnly = 1 in { +def MTHI64 : MoveToLOHI<"mthi", GPR64Opnd, [HI0_64]>, MTLO_FM<0x11>; +def MTLO64 : MoveToLOHI<"mtlo", GPR64Opnd, [LO0_64]>, MTLO_FM<0x13>; +def MFHI64 : MoveFromLOHI<"mfhi", GPR64Opnd, AC0_64>, MFLO_FM<0x10>; +def MFLO64 : MoveFromLOHI<"mflo", GPR64Opnd, AC0_64>, MFLO_FM<0x12>; +def PseudoMFHI64 : PseudoMFLOHI<GPR64, ACC128, MipsMFHI>; +def PseudoMFLO64 : PseudoMFLOHI<GPR64, ACC128, MipsMFLO>; +def PseudoMTLOHI64 : PseudoMTLOHI<ACC128, GPR64>; + +/// Sign Ext In Register Instructions. +def SEB64 : SignExtInReg<"seb", i8, GPR64Opnd>, SEB_FM<0x10, 0x20>; +def SEH64 : SignExtInReg<"seh", i16, GPR64Opnd>, SEB_FM<0x18, 0x20>; +} + +/// Count Leading +def DCLZ : CountLeading0<"dclz", GPR64Opnd>, CLO_FM<0x24>; +def DCLO : CountLeading1<"dclo", GPR64Opnd>, CLO_FM<0x25>; + +/// Double Word Swap Bytes/HalfWords +def DSBH : SubwordSwap<"dsbh", GPR64Opnd>, SEB_FM<2, 0x24>; +def DSHD : SubwordSwap<"dshd", GPR64Opnd>, SEB_FM<5, 0x24>; + +def LEA_ADDiu64 : EffectiveAddress<"daddiu", GPR64Opnd>, LW_FM<0x19>; + +let isCodeGenOnly = 1 in +def RDHWR64 : ReadHardware<GPR64Opnd, HWRegsOpnd>, RDHWR_FM; + +def DEXT : ExtBase<"dext", GPR64Opnd, uimm6, MipsExt>, EXT_FM<3>; +def DEXTU : ExtBase<"dextu", GPR64Opnd, uimm6>, EXT_FM<2>; +def DEXTM : ExtBase<"dextm", GPR64Opnd, uimm5>, EXT_FM<1>; + +def DINS : InsBase<"dins", GPR64Opnd, uimm6, MipsIns>, EXT_FM<7>; +def DINSU : InsBase<"dinsu", GPR64Opnd, uimm6>, EXT_FM<6>; +def DINSM : InsBase<"dinsm", GPR64Opnd, uimm5>, EXT_FM<5>; + +let isCodeGenOnly = 1, rs = 0, shamt = 0 in { + def DSLL64_32 : FR<0x00, 0x3c, (outs GPR64:$rd), (ins GPR32:$rt), + "dsll\t$rd, $rt, 32", [], IIArith>; + def SLL64_32 : FR<0x0, 0x00, (outs GPR64:$rd), (ins GPR32:$rt), + "sll\t$rd, $rt, 0", [], IIArith>; + def SLL64_64 : FR<0x0, 0x00, (outs GPR64:$rd), (ins GPR64:$rt), + "sll\t$rd, $rt, 0", [], IIArith>; +} +} +//===----------------------------------------------------------------------===// +// Arbitrary patterns that map to one or more instructions +//===----------------------------------------------------------------------===// + +// extended loads +let Predicates = [HasStdEnc] in { + def : MipsPat<(i64 (extloadi1 addr:$src)), (LB64 addr:$src)>; + def : MipsPat<(i64 (extloadi8 addr:$src)), (LB64 addr:$src)>; + def : MipsPat<(i64 (extloadi16 addr:$src)), (LH64 addr:$src)>; + def : MipsPat<(i64 (extloadi32 addr:$src)), (LW64 addr:$src)>; +} + +// hi/lo relocs +def : MipsPat<(MipsHi tglobaladdr:$in), (LUi64 tglobaladdr:$in)>; +def : MipsPat<(MipsHi tblockaddress:$in), (LUi64 tblockaddress:$in)>; +def : MipsPat<(MipsHi tjumptable:$in), (LUi64 tjumptable:$in)>; +def : MipsPat<(MipsHi tconstpool:$in), (LUi64 tconstpool:$in)>; +def : MipsPat<(MipsHi tglobaltlsaddr:$in), (LUi64 tglobaltlsaddr:$in)>; +def : MipsPat<(MipsHi texternalsym:$in), (LUi64 texternalsym:$in)>; + +def : MipsPat<(MipsLo tglobaladdr:$in), (DADDiu ZERO_64, tglobaladdr:$in)>; +def : MipsPat<(MipsLo tblockaddress:$in), (DADDiu ZERO_64, tblockaddress:$in)>; +def : MipsPat<(MipsLo tjumptable:$in), (DADDiu ZERO_64, tjumptable:$in)>; +def : MipsPat<(MipsLo tconstpool:$in), (DADDiu ZERO_64, tconstpool:$in)>; +def : MipsPat<(MipsLo tglobaltlsaddr:$in), + (DADDiu ZERO_64, tglobaltlsaddr:$in)>; +def : MipsPat<(MipsLo texternalsym:$in), (DADDiu ZERO_64, texternalsym:$in)>; + +def : MipsPat<(add GPR64:$hi, (MipsLo tglobaladdr:$lo)), + (DADDiu GPR64:$hi, tglobaladdr:$lo)>; +def : MipsPat<(add GPR64:$hi, (MipsLo tblockaddress:$lo)), + (DADDiu GPR64:$hi, tblockaddress:$lo)>; +def : MipsPat<(add GPR64:$hi, (MipsLo tjumptable:$lo)), + (DADDiu GPR64:$hi, tjumptable:$lo)>; +def : MipsPat<(add GPR64:$hi, (MipsLo tconstpool:$lo)), + (DADDiu GPR64:$hi, tconstpool:$lo)>; +def : MipsPat<(add GPR64:$hi, (MipsLo tglobaltlsaddr:$lo)), + (DADDiu GPR64:$hi, tglobaltlsaddr:$lo)>; + +def : WrapperPat<tglobaladdr, DADDiu, GPR64>; +def : WrapperPat<tconstpool, DADDiu, GPR64>; +def : WrapperPat<texternalsym, DADDiu, GPR64>; +def : WrapperPat<tblockaddress, DADDiu, GPR64>; +def : WrapperPat<tjumptable, DADDiu, GPR64>; +def : WrapperPat<tglobaltlsaddr, DADDiu, GPR64>; + +defm : BrcondPats<GPR64, BEQ64, BNE64, SLT64, SLTu64, SLTi64, SLTiu64, + ZERO_64>; + +def : MipsPat<(brcond (i32 (setlt i64:$lhs, 1)), bb:$dst), + (BLEZ64 i64:$lhs, bb:$dst)>; +def : MipsPat<(brcond (i32 (setgt i64:$lhs, -1)), bb:$dst), + (BGEZ64 i64:$lhs, bb:$dst)>; + +// setcc patterns +defm : SeteqPats<GPR64, SLTiu64, XOR64, SLTu64, ZERO_64>; +defm : SetlePats<GPR64, SLT64, SLTu64>; +defm : SetgtPats<GPR64, SLT64, SLTu64>; +defm : SetgePats<GPR64, SLT64, SLTu64>; +defm : SetgeImmPats<GPR64, SLTi64, SLTiu64>; + +// truncate +def : MipsPat<(i32 (trunc GPR64:$src)), + (SLL (EXTRACT_SUBREG GPR64:$src, sub_32), 0)>, + Requires<[HasStdEnc]>; + +// 32-to-64-bit extension +def : MipsPat<(i64 (anyext GPR32:$src)), (SLL64_32 GPR32:$src)>; +def : MipsPat<(i64 (zext GPR32:$src)), (DSRL (DSLL64_32 GPR32:$src), 32)>; +def : MipsPat<(i64 (sext GPR32:$src)), (SLL64_32 GPR32:$src)>; + +// Sign extend in register +def : MipsPat<(i64 (sext_inreg GPR64:$src, i32)), + (SLL64_64 GPR64:$src)>; + +// bswap MipsPattern +def : MipsPat<(bswap GPR64:$rt), (DSHD (DSBH GPR64:$rt))>; + +//===----------------------------------------------------------------------===// +// Instruction aliases +//===----------------------------------------------------------------------===// +def : InstAlias<"move $dst, $src", + (DADDu GPR64Opnd:$dst, GPR64Opnd:$src, ZERO_64), 1>, + Requires<[HasMips64]>; +def : InstAlias<"daddu $rs, $rt, $imm", + (DADDiu GPR64Opnd:$rs, GPR64Opnd:$rt, simm16_64:$imm), + 0>; +def : InstAlias<"dadd $rs, $rt, $imm", + (DADDi GPR64Opnd:$rs, GPR64Opnd:$rt, simm16_64:$imm), + 0>; + +/// Move between CPU and coprocessor registers +let DecoderNamespace = "Mips64", Predicates = [HasMips64] in { +def DMFC0 : MFC3OP<"dmfc0", GPR64Opnd>, MFC3OP_FM<0x10, 1>; +def DMTC0 : MFC3OP<"dmtc0", GPR64Opnd>, MFC3OP_FM<0x10, 5>; +def DMFC2 : MFC3OP<"dmfc2", GPR64Opnd>, MFC3OP_FM<0x12, 1>; +def DMTC2 : MFC3OP<"dmtc2", GPR64Opnd>, MFC3OP_FM<0x12, 5>; +} + +// Two operand (implicit 0 selector) versions: +def : InstAlias<"dmfc0 $rt, $rd", (DMFC0 GPR64Opnd:$rt, GPR64Opnd:$rd, 0), 0>; +def : InstAlias<"dmtc0 $rt, $rd", (DMTC0 GPR64Opnd:$rt, GPR64Opnd:$rd, 0), 0>; +def : InstAlias<"dmfc2 $rt, $rd", (DMFC2 GPR64Opnd:$rt, GPR64Opnd:$rd, 0), 0>; +def : InstAlias<"dmtc2 $rt, $rd", (DMTC2 GPR64Opnd:$rt, GPR64Opnd:$rd, 0), 0>; + diff --git a/contrib/llvm/lib/Target/Mips/MipsAnalyzeImmediate.cpp b/contrib/llvm/lib/Target/Mips/MipsAnalyzeImmediate.cpp new file mode 100644 index 000000000000..31a9b7d63983 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsAnalyzeImmediate.cpp @@ -0,0 +1,153 @@ +//===-- MipsAnalyzeImmediate.cpp - Analyze Immediates ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "MipsAnalyzeImmediate.h" +#include "Mips.h" +#include "llvm/Support/MathExtras.h" + +using namespace llvm; + +MipsAnalyzeImmediate::Inst::Inst(unsigned O, unsigned I) : Opc(O), ImmOpnd(I) {} + +// Add I to the instruction sequences. +void MipsAnalyzeImmediate::AddInstr(InstSeqLs &SeqLs, const Inst &I) { + // Add an instruction seqeunce consisting of just I. + if (SeqLs.empty()) { + SeqLs.push_back(InstSeq(1, I)); + return; + } + + for (InstSeqLs::iterator Iter = SeqLs.begin(); Iter != SeqLs.end(); ++Iter) + Iter->push_back(I); +} + +void MipsAnalyzeImmediate::GetInstSeqLsADDiu(uint64_t Imm, unsigned RemSize, + InstSeqLs &SeqLs) { + GetInstSeqLs((Imm + 0x8000ULL) & 0xffffffffffff0000ULL, RemSize, SeqLs); + AddInstr(SeqLs, Inst(ADDiu, Imm & 0xffffULL)); +} + +void MipsAnalyzeImmediate::GetInstSeqLsORi(uint64_t Imm, unsigned RemSize, + InstSeqLs &SeqLs) { + GetInstSeqLs(Imm & 0xffffffffffff0000ULL, RemSize, SeqLs); + AddInstr(SeqLs, Inst(ORi, Imm & 0xffffULL)); +} + +void MipsAnalyzeImmediate::GetInstSeqLsSLL(uint64_t Imm, unsigned RemSize, + InstSeqLs &SeqLs) { + unsigned Shamt = countTrailingZeros(Imm); + GetInstSeqLs(Imm >> Shamt, RemSize - Shamt, SeqLs); + AddInstr(SeqLs, Inst(SLL, Shamt)); +} + +void MipsAnalyzeImmediate::GetInstSeqLs(uint64_t Imm, unsigned RemSize, + InstSeqLs &SeqLs) { + uint64_t MaskedImm = Imm & (0xffffffffffffffffULL >> (64 - Size)); + + // Do nothing if Imm is 0. + if (!MaskedImm) + return; + + // A single ADDiu will do if RemSize <= 16. + if (RemSize <= 16) { + AddInstr(SeqLs, Inst(ADDiu, MaskedImm)); + return; + } + + // Shift if the lower 16-bit is cleared. + if (!(Imm & 0xffff)) { + GetInstSeqLsSLL(Imm, RemSize, SeqLs); + return; + } + + GetInstSeqLsADDiu(Imm, RemSize, SeqLs); + + // If bit 15 is cleared, it doesn't make a difference whether the last + // instruction is an ADDiu or ORi. In that case, do not call GetInstSeqLsORi. + if (Imm & 0x8000) { + InstSeqLs SeqLsORi; + GetInstSeqLsORi(Imm, RemSize, SeqLsORi); + SeqLs.insert(SeqLs.end(), SeqLsORi.begin(), SeqLsORi.end()); + } +} + +// Replace a ADDiu & SLL pair with a LUi. +// e.g. the following two instructions +// ADDiu 0x0111 +// SLL 18 +// are replaced with +// LUi 0x444 +void MipsAnalyzeImmediate::ReplaceADDiuSLLWithLUi(InstSeq &Seq) { + // Check if the first two instructions are ADDiu and SLL and the shift amount + // is at least 16. + if ((Seq.size() < 2) || (Seq[0].Opc != ADDiu) || + (Seq[1].Opc != SLL) || (Seq[1].ImmOpnd < 16)) + return; + + // Sign-extend and shift operand of ADDiu and see if it still fits in 16-bit. + int64_t Imm = SignExtend64<16>(Seq[0].ImmOpnd); + int64_t ShiftedImm = (uint64_t)Imm << (Seq[1].ImmOpnd - 16); + + if (!isInt<16>(ShiftedImm)) + return; + + // Replace the first instruction and erase the second. + Seq[0].Opc = LUi; + Seq[0].ImmOpnd = (unsigned)(ShiftedImm & 0xffff); + Seq.erase(Seq.begin() + 1); +} + +void MipsAnalyzeImmediate::GetShortestSeq(InstSeqLs &SeqLs, InstSeq &Insts) { + InstSeqLs::iterator ShortestSeq = SeqLs.end(); + // The length of an instruction sequence is at most 7. + unsigned ShortestLength = 8; + + for (InstSeqLs::iterator S = SeqLs.begin(); S != SeqLs.end(); ++S) { + ReplaceADDiuSLLWithLUi(*S); + assert(S->size() <= 7); + + if (S->size() < ShortestLength) { + ShortestSeq = S; + ShortestLength = S->size(); + } + } + + Insts.clear(); + Insts.append(ShortestSeq->begin(), ShortestSeq->end()); +} + +const MipsAnalyzeImmediate::InstSeq +&MipsAnalyzeImmediate::Analyze(uint64_t Imm, unsigned Size, + bool LastInstrIsADDiu) { + this->Size = Size; + + if (Size == 32) { + ADDiu = Mips::ADDiu; + ORi = Mips::ORi; + SLL = Mips::SLL; + LUi = Mips::LUi; + } else { + ADDiu = Mips::DADDiu; + ORi = Mips::ORi64; + SLL = Mips::DSLL; + LUi = Mips::LUi64; + } + + InstSeqLs SeqLs; + + // Get the list of instruction sequences. + if (LastInstrIsADDiu | !Imm) + GetInstSeqLsADDiu(Imm, Size, SeqLs); + else + GetInstSeqLs(Imm, Size, SeqLs); + + // Set Insts to the shortest instruction sequence. + GetShortestSeq(SeqLs, Insts); + + return Insts; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsAnalyzeImmediate.h b/contrib/llvm/lib/Target/Mips/MipsAnalyzeImmediate.h new file mode 100644 index 000000000000..cc09034a9c39 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsAnalyzeImmediate.h @@ -0,0 +1,63 @@ +//===-- MipsAnalyzeImmediate.h - Analyze Immediates ------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef MIPS_ANALYZE_IMMEDIATE_H +#define MIPS_ANALYZE_IMMEDIATE_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { + + class MipsAnalyzeImmediate { + public: + struct Inst { + unsigned Opc, ImmOpnd; + Inst(unsigned Opc, unsigned ImmOpnd); + }; + typedef SmallVector<Inst, 7 > InstSeq; + + /// Analyze - Get an instruction sequence to load immediate Imm. The last + /// instruction in the sequence must be an ADDiu if LastInstrIsADDiu is + /// true; + const InstSeq &Analyze(uint64_t Imm, unsigned Size, bool LastInstrIsADDiu); + private: + typedef SmallVector<InstSeq, 5> InstSeqLs; + + /// AddInstr - Add I to all instruction sequences in SeqLs. + void AddInstr(InstSeqLs &SeqLs, const Inst &I); + + /// GetInstSeqLsADDiu - Get instruction sequences which end with an ADDiu to + /// load immediate Imm + void GetInstSeqLsADDiu(uint64_t Imm, unsigned RemSize, InstSeqLs &SeqLs); + + /// GetInstSeqLsORi - Get instrutcion sequences which end with an ORi to + /// load immediate Imm + void GetInstSeqLsORi(uint64_t Imm, unsigned RemSize, InstSeqLs &SeqLs); + + /// GetInstSeqLsSLL - Get instruction sequences which end with a SLL to + /// load immediate Imm + void GetInstSeqLsSLL(uint64_t Imm, unsigned RemSize, InstSeqLs &SeqLs); + + /// GetInstSeqLs - Get instruction sequences to load immediate Imm. + void GetInstSeqLs(uint64_t Imm, unsigned RemSize, InstSeqLs &SeqLs); + + /// ReplaceADDiuSLLWithLUi - Replace an ADDiu & SLL pair with a LUi. + void ReplaceADDiuSLLWithLUi(InstSeq &Seq); + + /// GetShortestSeq - Find the shortest instruction sequence in SeqLs and + /// return it in Insts. + void GetShortestSeq(InstSeqLs &SeqLs, InstSeq &Insts); + + unsigned Size; + unsigned ADDiu, ORi, SLL, LUi; + InstSeq Insts; + }; +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp new file mode 100644 index 000000000000..45c439826422 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.cpp @@ -0,0 +1,708 @@ +//===-- MipsAsmPrinter.cpp - Mips LLVM Assembly Printer -------------------===// +// +// 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 MIPS assembly language. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-asm-printer" +#include "InstPrinter/MipsInstPrinter.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "Mips.h" +#include "MipsAsmPrinter.h" +#include "MipsInstrInfo.h" +#include "MipsMCInstLower.h" +#include "MipsTargetStreamer.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/Instructions.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() { + return static_cast<MipsTargetStreamer &>(OutStreamer.getTargetStreamer()); +} + +bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) { + // Initialize TargetLoweringObjectFile. + if (Subtarget->allowMixed16_32()) + const_cast<TargetLoweringObjectFile&>(getObjFileLowering()) + .Initialize(OutContext, TM); + MipsFI = MF.getInfo<MipsFunctionInfo>(); + MCP = MF.getConstantPool(); + AsmPrinter::runOnMachineFunction(MF); + return true; +} + +bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) { + MCOp = MCInstLowering.LowerOperand(MO); + return MCOp.isValid(); +} + +#include "MipsGenMCPseudoLowering.inc" + +void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { + if (MI->isDebugValue()) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + + PrintDebugValueComment(MI, OS); + return; + } + + // If we just ended a constant pool, mark it as such. + if (InConstantPool && MI->getOpcode() != Mips::CONSTPOOL_ENTRY) { + OutStreamer.EmitDataRegion(MCDR_DataRegionEnd); + InConstantPool = false; + } + if (MI->getOpcode() == Mips::CONSTPOOL_ENTRY) { + // CONSTPOOL_ENTRY - This instruction represents a floating + //constant pool in the function. The first operand is the ID# + // for this instruction, the second is the index into the + // MachineConstantPool that this is, the third is the size in + // bytes of this constant pool entry. + // The required alignment is specified on the basic block holding this MI. + // + unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); + unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); + + // If this is the first entry of the pool, mark it. + if (!InConstantPool) { + OutStreamer.EmitDataRegion(MCDR_DataRegion); + InConstantPool = true; + } + + OutStreamer.EmitLabel(GetCPISymbol(LabelId)); + + const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; + if (MCPE.isMachineConstantPoolEntry()) + EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); + else + EmitGlobalConstant(MCPE.Val.ConstVal); + return; + } + + + MachineBasicBlock::const_instr_iterator I = MI; + MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); + + do { + // Do any auto-generated pseudo lowerings. + if (emitPseudoExpansionLowering(OutStreamer, &*I)) + continue; + + // The inMips16Mode() test is not permanent. + // Some instructions are marked as pseudo right now which + // would make the test fail for the wrong reason but + // that will be fixed soon. We need this here because we are + // removing another test for this situation downstream in the + // callchain. + // + if (I->isPseudo() && !Subtarget->inMips16Mode()) + llvm_unreachable("Pseudo opcode found in EmitInstruction()"); + + MCInst TmpInst0; + MCInstLowering.Lower(I, TmpInst0); + OutStreamer.EmitInstruction(TmpInst0); + } while ((++I != E) && I->isInsideBundle()); // Delay slot check +} + +//===----------------------------------------------------------------------===// +// +// Mips Asm Directives +// +// -- Frame directive "frame Stackpointer, Stacksize, RARegister" +// Describe the stack frame. +// +// -- Mask directives "(f)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 $fp,48,$ra +// .mask 0xc0000000,-8 +// addiu $sp, $sp, -48 +// sw $ra, 40($sp) +// sw $fp, 36($sp) +// +// With a 0xc0000000 mask, the assembler knows the register 31 (RA) and +// 30 (FP) are saved at prologue. As the save order on prologue is from +// left to right, RA is saved first. A -8 offset means that after the +// stack pointer subtration, the first register in the mask (RA) will be +// saved at address 48-8=40. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Mask directives +//===----------------------------------------------------------------------===// + +// 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 MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { + // CPU and FPU Saved Registers Bitmasks + unsigned CPUBitmask = 0, FPUBitmask = 0; + int CPUTopSavedRegOff, FPUTopSavedRegOff; + + // Set the CPU and FPU Bitmasks + const MachineFrameInfo *MFI = MF->getFrameInfo(); + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + // size of stack area to which FP callee-saved regs are saved. + unsigned CPURegSize = Mips::GPR32RegClass.getSize(); + unsigned FGR32RegSize = Mips::FGR32RegClass.getSize(); + unsigned AFGR64RegSize = Mips::AFGR64RegClass.getSize(); + bool HasAFGR64Reg = false; + unsigned CSFPRegsSize = 0; + unsigned i, e = CSI.size(); + + // Set FPU Bitmask. + for (i = 0; i != e; ++i) { + unsigned Reg = CSI[i].getReg(); + if (Mips::GPR32RegClass.contains(Reg)) + break; + + unsigned RegNum = TM.getRegisterInfo()->getEncodingValue(Reg); + if (Mips::AFGR64RegClass.contains(Reg)) { + FPUBitmask |= (3 << RegNum); + CSFPRegsSize += AFGR64RegSize; + HasAFGR64Reg = true; + continue; + } + + FPUBitmask |= (1 << RegNum); + CSFPRegsSize += FGR32RegSize; + } + + // Set CPU Bitmask. + for (; i != e; ++i) { + unsigned Reg = CSI[i].getReg(); + unsigned RegNum = TM.getRegisterInfo()->getEncodingValue(Reg); + CPUBitmask |= (1 << RegNum); + } + + // FP Regs are saved right below where the virtual frame pointer points to. + FPUTopSavedRegOff = FPUBitmask ? + (HasAFGR64Reg ? -AFGR64RegSize : -FGR32RegSize) : 0; + + // CPU Regs are saved below FP Regs. + CPUTopSavedRegOff = CPUBitmask ? -CSFPRegsSize - CPURegSize : 0; + + // Print CPUBitmask + O << "\t.mask \t"; printHex32(CPUBitmask, O); + O << ',' << CPUTopSavedRegOff << '\n'; + + // Print FPUBitmask + O << "\t.fmask\t"; printHex32(FPUBitmask, O); + O << "," << FPUTopSavedRegOff << '\n'; +} + +// Print a 32 bit hex number with all numbers. +void MipsAsmPrinter::printHex32(unsigned Value, raw_ostream &O) { + O << "0x"; + for (int i = 7; i >= 0; i--) + O.write_hex((Value & (0xF << (i*4))) >> (i*4)); +} + +//===----------------------------------------------------------------------===// +// Frame and Set directives +//===----------------------------------------------------------------------===// + +/// Frame Directive +void MipsAsmPrinter::emitFrameDirective() { + const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + + unsigned stackReg = RI.getFrameRegister(*MF); + unsigned returnReg = RI.getRARegister(); + unsigned stackSize = MF->getFrameInfo()->getStackSize(); + + if (OutStreamer.hasRawTextSupport()) + OutStreamer.EmitRawText("\t.frame\t$" + + StringRef(MipsInstPrinter::getRegisterName(stackReg)).lower() + + "," + Twine(stackSize) + ",$" + + StringRef(MipsInstPrinter::getRegisterName(returnReg)).lower()); +} + +/// Emit Set directives. +const char *MipsAsmPrinter::getCurrentABIString() const { + switch (Subtarget->getTargetABI()) { + case MipsSubtarget::O32: return "abi32"; + case MipsSubtarget::N32: return "abiN32"; + case MipsSubtarget::N64: return "abi64"; + case MipsSubtarget::EABI: return "eabi32"; // TODO: handle eabi64 + default: llvm_unreachable("Unknown Mips ABI"); + } +} + +void MipsAsmPrinter::EmitFunctionEntryLabel() { + if (OutStreamer.hasRawTextSupport()) { + if (Subtarget->inMips16Mode()) + OutStreamer.EmitRawText(StringRef("\t.set\tmips16")); + else + OutStreamer.EmitRawText(StringRef("\t.set\tnomips16")); + // leave out until FSF available gas has micromips changes + // OutStreamer.EmitRawText(StringRef("\t.set\tnomicromips")); + OutStreamer.EmitRawText("\t.ent\t" + Twine(CurrentFnSym->getName())); + } + + if (Subtarget->inMicroMipsMode()) + getTargetStreamer().emitMipsHackSTOCG(CurrentFnSym, + (unsigned)ELF::STO_MIPS_MICROMIPS); + OutStreamer.EmitLabel(CurrentFnSym); +} + +/// EmitFunctionBodyStart - Targets can override this to emit stuff before +/// the first basic block in the function. +void MipsAsmPrinter::EmitFunctionBodyStart() { + MCInstLowering.Initialize(&MF->getContext()); + + bool IsNakedFunction = + MF->getFunction()-> + getAttributes().hasAttribute(AttributeSet::FunctionIndex, + Attribute::Naked); + if (!IsNakedFunction) + emitFrameDirective(); + + if (OutStreamer.hasRawTextSupport()) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + if (!IsNakedFunction) + printSavedRegsBitmask(OS); + OutStreamer.EmitRawText(OS.str()); + if (!Subtarget->inMips16Mode()) { + OutStreamer.EmitRawText(StringRef("\t.set\tnoreorder")); + OutStreamer.EmitRawText(StringRef("\t.set\tnomacro")); + OutStreamer.EmitRawText(StringRef("\t.set\tnoat")); + } + } +} + +/// EmitFunctionBodyEnd - Targets can override this to emit stuff after +/// the last basic block in the function. +void MipsAsmPrinter::EmitFunctionBodyEnd() { + // There are instruction for this macros, but they must + // always be at the function end, and we can't emit and + // break with BB logic. + if (OutStreamer.hasRawTextSupport()) { + if (!Subtarget->inMips16Mode()) { + OutStreamer.EmitRawText(StringRef("\t.set\tat")); + OutStreamer.EmitRawText(StringRef("\t.set\tmacro")); + OutStreamer.EmitRawText(StringRef("\t.set\treorder")); + } + OutStreamer.EmitRawText("\t.end\t" + Twine(CurrentFnSym->getName())); + } + // Make sure to terminate any constant pools that were at the end + // of the function. + if (!InConstantPool) + return; + InConstantPool = false; + OutStreamer.EmitDataRegion(MCDR_DataRegionEnd); +} + +/// 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 MipsAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock* + MBB) const { + // The predecessor has to be immediately before this block. + const MachineBasicBlock *Pred = *MBB->pred_begin(); + + // If the predecessor is a switch statement, assume a jump table + // implementation, so it is not a fall through. + if (const BasicBlock *bb = Pred->getBasicBlock()) + if (isa<SwitchInst>(bb->getTerminator())) + return false; + + // 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. + if (!Pred->isLayoutSuccessor(MBB)) + return false; + + // If the block is completely empty, then it definitely does fall through. + if (Pred->empty()) + return true; + + // Otherwise, check the last instruction. + // Check if the last terminator is an unconditional branch. + MachineBasicBlock::const_iterator I = Pred->end(); + while (I != Pred->begin() && !(--I)->isTerminator()) ; + + return !I->isBarrier(); +} + +// Print out an operand for an inline asm expression. +bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, + 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. + + const MachineOperand &MO = MI->getOperand(OpNum); + switch (ExtraCode[0]) { + default: + // See if this is a generic print operand + return AsmPrinter::PrintAsmOperand(MI,OpNum,AsmVariant,ExtraCode,O); + case 'X': // hex const int + if ((MO.getType()) != MachineOperand::MO_Immediate) + return true; + O << "0x" << StringRef(utohexstr(MO.getImm())).lower(); + return false; + case 'x': // hex const int (low 16 bits) + if ((MO.getType()) != MachineOperand::MO_Immediate) + return true; + O << "0x" << StringRef(utohexstr(MO.getImm() & 0xffff)).lower(); + return false; + case 'd': // decimal const int + if ((MO.getType()) != MachineOperand::MO_Immediate) + return true; + O << MO.getImm(); + return false; + case 'm': // decimal const int minus 1 + if ((MO.getType()) != MachineOperand::MO_Immediate) + return true; + O << MO.getImm() - 1; + return false; + case 'z': { + // $0 if zero, regular printing otherwise + if (MO.getType() != MachineOperand::MO_Immediate) + return true; + int64_t Val = MO.getImm(); + if (Val) + O << Val; + else + O << "$0"; + return false; + } + case 'D': // Second part of a double word register operand + case 'L': // Low order register of a double word register operand + case 'M': // High order register of a double word register operand + { + if (OpNum == 0) + return true; + const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1); + if (!FlagsOP.isImm()) + return true; + unsigned Flags = FlagsOP.getImm(); + unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags); + // Number of registers represented by this operand. We are looking + // for 2 for 32 bit mode and 1 for 64 bit mode. + if (NumVals != 2) { + if (Subtarget->isGP64bit() && NumVals == 1 && MO.isReg()) { + unsigned Reg = MO.getReg(); + O << '$' << MipsInstPrinter::getRegisterName(Reg); + return false; + } + return true; + } + + unsigned RegOp = OpNum; + if (!Subtarget->isGP64bit()){ + // Endianess reverses which register holds the high or low value + // between M and L. + switch(ExtraCode[0]) { + case 'M': + RegOp = (Subtarget->isLittle()) ? OpNum + 1 : OpNum; + break; + case 'L': + RegOp = (Subtarget->isLittle()) ? OpNum : OpNum + 1; + break; + case 'D': // Always the second part + RegOp = OpNum + 1; + } + if (RegOp >= MI->getNumOperands()) + return true; + const MachineOperand &MO = MI->getOperand(RegOp); + if (!MO.isReg()) + return true; + unsigned Reg = MO.getReg(); + O << '$' << MipsInstPrinter::getRegisterName(Reg); + return false; + } + } + case 'w': + // Print MSA registers for the 'f' constraint + // In LLVM, the 'w' modifier doesn't need to do anything. + // We can just call printOperand as normal. + break; + } + } + + printOperand(MI, OpNum, O); + return false; +} + +bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNum, unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &O) { + int Offset = 0; + // Currently we are expecting either no ExtraCode or 'D' + if (ExtraCode) { + if (ExtraCode[0] == 'D') + Offset = 4; + else + return true; // Unknown modifier. + } + + const MachineOperand &MO = MI->getOperand(OpNum); + assert(MO.isReg() && "unexpected inline asm memory operand"); + O << Offset << "($" << MipsInstPrinter::getRegisterName(MO.getReg()) << ")"; + + return false; +} + +void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + bool closeP = false; + + if (MO.getTargetFlags()) + closeP = true; + + switch(MO.getTargetFlags()) { + case MipsII::MO_GPREL: O << "%gp_rel("; break; + case MipsII::MO_GOT_CALL: O << "%call16("; break; + case MipsII::MO_GOT: O << "%got("; break; + case MipsII::MO_ABS_HI: O << "%hi("; break; + case MipsII::MO_ABS_LO: O << "%lo("; break; + case MipsII::MO_TLSGD: O << "%tlsgd("; break; + case MipsII::MO_GOTTPREL: O << "%gottprel("; break; + case MipsII::MO_TPREL_HI: O << "%tprel_hi("; break; + case MipsII::MO_TPREL_LO: O << "%tprel_lo("; break; + case MipsII::MO_GPOFF_HI: O << "%hi(%neg(%gp_rel("; break; + case MipsII::MO_GPOFF_LO: O << "%lo(%neg(%gp_rel("; break; + case MipsII::MO_GOT_DISP: O << "%got_disp("; break; + case MipsII::MO_GOT_PAGE: O << "%got_page("; break; + case MipsII::MO_GOT_OFST: O << "%got_ofst("; break; + } + + switch (MO.getType()) { + case MachineOperand::MO_Register: + O << '$' + << StringRef(MipsInstPrinter::getRegisterName(MO.getReg())).lower(); + break; + + case MachineOperand::MO_Immediate: + O << MO.getImm(); + break; + + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + return; + + case MachineOperand::MO_GlobalAddress: + O << *getSymbol(MO.getGlobal()); + break; + + case MachineOperand::MO_BlockAddress: { + MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress()); + O << BA->getName(); + 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>"); + } + + if (closeP) O << ")"; +} + +void MipsAsmPrinter::printUnsignedImm(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) + O << (unsigned short int)MO.getImm(); + else + printOperand(MI, opNum, O); +} + +void MipsAsmPrinter::printUnsignedImm8(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) + O << (unsigned short int)(unsigned char)MO.getImm(); + else + printOperand(MI, opNum, O); +} + +void MipsAsmPrinter:: +printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { + // Load/Store memory operands -- imm($reg) + // If PIC target the target is loaded as the + // pattern lw $25,%call16($28) + printOperand(MI, opNum+1, O); + O << "("; + printOperand(MI, opNum, O); + O << ")"; +} + +void MipsAsmPrinter:: +printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O) { + // when using stack locations for not load/store instructions + // print the same way as all normal 3 operand instructions. + printOperand(MI, opNum, O); + O << ", "; + printOperand(MI, opNum+1, O); + return; +} + +void MipsAsmPrinter:: +printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, + const char *Modifier) { + const MachineOperand &MO = MI->getOperand(opNum); + O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm()); +} + +void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { + // FIXME: Use SwitchSection. + + // TODO: Need to add -mabicalls and -mno-abicalls flags. + // Currently we assume that -mabicalls is the default. + if (OutStreamer.hasRawTextSupport()) { + OutStreamer.EmitRawText(StringRef("\t.abicalls")); + Reloc::Model RM = Subtarget->getRelocationModel(); + if (RM == Reloc::Static && !Subtarget->hasMips64()) + OutStreamer.EmitRawText(StringRef("\t.option\tpic0")); + } + + // Tell the assembler which ABI we are using + if (OutStreamer.hasRawTextSupport()) + OutStreamer.EmitRawText("\t.section .mdebug." + + Twine(getCurrentABIString())); + + // TODO: handle O64 ABI + if (OutStreamer.hasRawTextSupport()) { + if (Subtarget->isABI_EABI()) { + if (Subtarget->isGP32bit()) + OutStreamer.EmitRawText(StringRef("\t.section .gcc_compiled_long32")); + else + OutStreamer.EmitRawText(StringRef("\t.section .gcc_compiled_long64")); + } + } + + // return to previous section + if (OutStreamer.hasRawTextSupport()) + OutStreamer.EmitRawText(StringRef("\t.previous")); + +} + +static void emitELFHeaderFlagsCG(MipsTargetStreamer &TargetStreamer, + const MipsSubtarget &Subtarget) { + // Update e_header flags + unsigned EFlags = 0; + + // TODO: Need to add -mabicalls and -mno-abicalls flags. + // Currently we assume that -mabicalls is the default. + EFlags |= ELF::EF_MIPS_CPIC; + + if (Subtarget.inMips16Mode()) + EFlags |= ELF::EF_MIPS_ARCH_ASE_M16; + else + EFlags |= ELF::EF_MIPS_NOREORDER; + + // Architecture + if (Subtarget.hasMips64r2()) + EFlags |= ELF::EF_MIPS_ARCH_64R2; + else if (Subtarget.hasMips64()) + EFlags |= ELF::EF_MIPS_ARCH_64; + else if (Subtarget.hasMips32r2()) + EFlags |= ELF::EF_MIPS_ARCH_32R2; + else + EFlags |= ELF::EF_MIPS_ARCH_32; + + if (Subtarget.inMicroMipsMode()) + EFlags |= ELF::EF_MIPS_MICROMIPS; + + // ABI + if (Subtarget.isABI_O32()) + EFlags |= ELF::EF_MIPS_ABI_O32; + + // Relocation Model + Reloc::Model RM = Subtarget.getRelocationModel(); + if (RM == Reloc::PIC_ || RM == Reloc::Default) + EFlags |= ELF::EF_MIPS_PIC; + else if (RM == Reloc::Static) + ; // Do nothing for Reloc::Static + else + llvm_unreachable("Unsupported relocation model for e_flags"); + + TargetStreamer.emitMipsHackELFFlags(EFlags); +} + +void MipsAsmPrinter::EmitEndOfAsmFile(Module &M) { + // Emit Mips ELF register info + Subtarget->getMReginfo().emitMipsReginfoSectionCG( + OutStreamer, getObjFileLowering(), *Subtarget); + emitELFHeaderFlagsCG(getTargetStreamer(), *Subtarget); +} + +void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI, + raw_ostream &OS) { + // TODO: implement +} + +// Force static initialization. +extern "C" void LLVMInitializeMipsAsmPrinter() { + RegisterAsmPrinter<MipsAsmPrinter> X(TheMipsTarget); + RegisterAsmPrinter<MipsAsmPrinter> Y(TheMipselTarget); + RegisterAsmPrinter<MipsAsmPrinter> A(TheMips64Target); + RegisterAsmPrinter<MipsAsmPrinter> B(TheMips64elTarget); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.h b/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.h new file mode 100644 index 000000000000..11c6acd208d1 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsAsmPrinter.h @@ -0,0 +1,111 @@ +//===-- MipsAsmPrinter.h - Mips LLVM Assembly Printer ----------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Mips Assembly printer class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSASMPRINTER_H +#define MIPSASMPRINTER_H + +#include "MipsMCInstLower.h" +#include "MipsMachineFunction.h" +#include "MipsSubtarget.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +class MCStreamer; +class MachineInstr; +class MachineBasicBlock; +class MipsTargetStreamer; +class Module; +class raw_ostream; + +class LLVM_LIBRARY_VISIBILITY MipsAsmPrinter : public AsmPrinter { + MipsTargetStreamer &getTargetStreamer(); + + void EmitInstrWithMacroNoAT(const MachineInstr *MI); + +private: + // tblgen'erated function. + bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, + const MachineInstr *MI); + + // lowerOperand - Convert a MachineOperand into the equivalent MCOperand. + bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp); + + /// MCP - Keep a pointer to constantpool entries of the current + /// MachineFunction. + const MachineConstantPool *MCP; + + /// InConstantPool - Maintain state when emitting a sequence of constant + /// pool entries so we can properly mark them as data regions. + bool InConstantPool; + + bool UsingConstantPools; + +public: + + const MipsSubtarget *Subtarget; + const MipsFunctionInfo *MipsFI; + MipsMCInstLower MCInstLowering; + + explicit MipsAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer), MCP(0), InConstantPool(false), + MCInstLowering(*this) { + Subtarget = &TM.getSubtarget<MipsSubtarget>(); + UsingConstantPools = + (Subtarget->inMips16Mode() && Subtarget->useConstantIslands()); + } + + virtual const char *getPassName() const { + return "Mips Assembly Printer"; + } + + virtual bool runOnMachineFunction(MachineFunction &MF); + + virtual void EmitConstantPool() LLVM_OVERRIDE { + if (!UsingConstantPools) + AsmPrinter::EmitConstantPool(); + // we emit constant pools customly! + } + + void EmitInstruction(const MachineInstr *MI); + void printSavedRegsBitmask(raw_ostream &O); + void printHex32(unsigned int Value, raw_ostream &O); + void emitFrameDirective(); + const char *getCurrentABIString() const; + virtual void EmitFunctionEntryLabel(); + virtual void EmitFunctionBodyStart(); + virtual void EmitFunctionBodyEnd(); + virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock* + MBB) const; + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O); + bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, + 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 printUnsignedImm8(const MachineInstr *MI, int opNum, raw_ostream &O); + void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O); + void printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O); + void printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, + const char *Modifier = 0); + void EmitStartOfAsmFile(Module &M); + void EmitEndOfAsmFile(Module &M); + void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); +}; +} + +#endif + diff --git a/contrib/llvm/lib/Target/Mips/MipsCallingConv.td b/contrib/llvm/lib/Target/Mips/MipsCallingConv.td new file mode 100644 index 000000000000..66391cb9cb1e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsCallingConv.td @@ -0,0 +1,249 @@ +//===-- MipsCallingConv.td - Calling Conventions for Mips --*- 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 Mips architecture. +//===----------------------------------------------------------------------===// + +/// CCIfSubtarget - Match if the current subtarget has a feature F. +class CCIfSubtarget<string F, CCAction A>: + CCIf<!strconcat("State.getTarget().getSubtarget<MipsSubtarget>().", F), A>; + +//===----------------------------------------------------------------------===// +// Mips O32 Calling Convention +//===----------------------------------------------------------------------===// + +// Only the return rules are defined here for O32. The rules for argument +// passing are defined in MipsISelLowering.cpp. +def RetCC_MipsO32 : CallingConv<[ + // i32 are returned in registers V0, V1, A0, A1 + CCIfType<[i32], CCAssignToReg<[V0, V1, A0, A1]>>, + + // f32 are returned in registers F0, F2 + CCIfType<[f32], CCAssignToReg<[F0, F2]>>, + + // f64 arguments are returned in D0_64 and D1_64 in FP64bit mode or + // in D0 and D1 in FP32bit mode. + CCIfType<[f64], CCIfSubtarget<"isFP64bit()", CCAssignToReg<[D0_64, D1_64]>>>, + CCIfType<[f64], CCIfSubtarget<"isNotFP64bit()", CCAssignToReg<[D0, D1]>>> +]>; + +//===----------------------------------------------------------------------===// +// Mips N32/64 Calling Convention +//===----------------------------------------------------------------------===// + +def CC_MipsN : CallingConv<[ + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType<i32>>, + + // Integer arguments are passed in integer registers. + CCIfType<[i32], CCAssignToRegWithShadow<[A0, A1, A2, A3, + T0, T1, T2, T3], + [F12, F13, F14, F15, + F16, F17, F18, F19]>>, + + CCIfType<[i64], CCAssignToRegWithShadow<[A0_64, A1_64, A2_64, A3_64, + T0_64, T1_64, T2_64, T3_64], + [D12_64, D13_64, D14_64, D15_64, + D16_64, D17_64, D18_64, D19_64]>>, + + // f32 arguments are passed in single precision FP registers. + CCIfType<[f32], CCAssignToRegWithShadow<[F12, F13, F14, F15, + F16, F17, F18, F19], + [A0_64, A1_64, A2_64, A3_64, + T0_64, T1_64, T2_64, T3_64]>>, + + // f64 arguments are passed in double precision FP registers. + CCIfType<[f64], CCAssignToRegWithShadow<[D12_64, D13_64, D14_64, D15_64, + D16_64, D17_64, D18_64, D19_64], + [A0_64, A1_64, A2_64, A3_64, + T0_64, T1_64, T2_64, T3_64]>>, + + // All stack parameter slots become 64-bit doublewords and are 8-byte aligned. + CCIfType<[i32, f32], CCAssignToStack<4, 8>>, + CCIfType<[i64, f64], CCAssignToStack<8, 8>> +]>; + +// N32/64 variable arguments. +// All arguments are passed in integer registers. +def CC_MipsN_VarArg : CallingConv<[ + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType<i32>>, + + CCIfType<[i32, f32], CCAssignToReg<[A0, A1, A2, A3, T0, T1, T2, T3]>>, + + CCIfType<[i64, f64], CCAssignToReg<[A0_64, A1_64, A2_64, A3_64, + T0_64, T1_64, T2_64, T3_64]>>, + + // All stack parameter slots become 64-bit doublewords and are 8-byte aligned. + CCIfType<[i32, f32], CCAssignToStack<4, 8>>, + CCIfType<[i64, f64], CCAssignToStack<8, 8>> +]>; + +def RetCC_MipsN : CallingConv<[ + // i32 are returned in registers V0, V1 + CCIfType<[i32], CCAssignToReg<[V0, V1]>>, + + // i64 are returned in registers V0_64, V1_64 + CCIfType<[i64], CCAssignToReg<[V0_64, V1_64]>>, + + // f32 are returned in registers F0, F2 + CCIfType<[f32], CCAssignToReg<[F0, F2]>>, + + // f64 are returned in registers D0, D2 + CCIfType<[f64], CCAssignToReg<[D0_64, D2_64]>> +]>; + +// In soft-mode, register A0_64, instead of V1_64, is used to return a long +// double value. +def RetCC_F128Soft : CallingConv<[ + CCIfType<[i64], CCAssignToReg<[V0_64, A0_64]>> +]>; + +//===----------------------------------------------------------------------===// +// Mips EABI Calling Convention +//===----------------------------------------------------------------------===// + +def CC_MipsEABI : CallingConv<[ + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType<i32>>, + + // Integer arguments are passed in integer registers. + CCIfType<[i32], CCAssignToReg<[A0, A1, A2, A3, T0, T1, T2, T3]>>, + + // Single fp arguments are passed in pairs within 32-bit mode + CCIfType<[f32], CCIfSubtarget<"isSingleFloat()", + CCAssignToReg<[F12, F13, F14, F15, F16, F17, F18, F19]>>>, + + CCIfType<[f32], CCIfSubtarget<"isNotSingleFloat()", + CCAssignToReg<[F12, F14, F16, F18]>>>, + + // The first 4 double fp arguments are passed in single fp registers. + CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()", + CCAssignToReg<[D6, D7, D8, D9]>>>, + + // Integer values get stored in stack slots that are 4 bytes in + // size and 4-byte aligned. + CCIfType<[i32, f32], CCAssignToStack<4, 4>>, + + // Integer values get stored in stack slots that are 8 bytes in + // size and 8-byte aligned. + CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()", CCAssignToStack<8, 8>>> +]>; + +def RetCC_MipsEABI : CallingConv<[ + // i32 are returned in registers V0, V1 + CCIfType<[i32], CCAssignToReg<[V0, V1]>>, + + // f32 are returned in registers F0, F1 + CCIfType<[f32], CCAssignToReg<[F0, F1]>>, + + // f64 are returned in register D0 + CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()", CCAssignToReg<[D0]>>> +]>; + +//===----------------------------------------------------------------------===// +// Mips FastCC Calling Convention +//===----------------------------------------------------------------------===// +def CC_MipsO32_FastCC : CallingConv<[ + // f64 arguments are passed in double-precision floating pointer registers. + CCIfType<[f64], CCIfSubtarget<"isNotFP64bit()", + CCAssignToReg<[D0, D1, D2, D3, D4, D5, D6, D7, + D8, D9]>>>, + CCIfType<[f64], CCIfSubtarget<"isFP64bit()", + CCAssignToReg<[D0_64, D1_64, D2_64, D3_64, + D4_64, D5_64, D6_64, D7_64, + D8_64, D9_64, D10_64, D11_64, + D12_64, D13_64, D14_64, D15_64, + D16_64, D17_64, D18_64, + D19_64]>>>, + + // Stack parameter slots for f64 are 64-bit doublewords and 8-byte aligned. + CCIfType<[f64], CCAssignToStack<8, 8>> +]>; + +def CC_MipsN_FastCC : CallingConv<[ + // Integer arguments are passed in integer registers. + CCIfType<[i64], CCAssignToReg<[A0_64, A1_64, A2_64, A3_64, T0_64, T1_64, + T2_64, T3_64, T4_64, T5_64, T6_64, T7_64, + T8_64, V1_64]>>, + + // f64 arguments are passed in double-precision floating pointer registers. + CCIfType<[f64], CCAssignToReg<[D0_64, D1_64, D2_64, D3_64, D4_64, D5_64, + D6_64, D7_64, D8_64, D9_64, D10_64, D11_64, + D12_64, D13_64, D14_64, D15_64, D16_64, D17_64, + D18_64, D19_64]>>, + + // Stack parameter slots for i64 and f64 are 64-bit doublewords and + // 8-byte aligned. + CCIfType<[i64, f64], CCAssignToStack<8, 8>> +]>; + +def CC_Mips_FastCC : CallingConv<[ + // Handles byval parameters. + CCIfByVal<CCPassByVal<4, 4>>, + + // Promote i8/i16 arguments to i32. + CCIfType<[i8, i16], CCPromoteToType<i32>>, + + // Integer arguments are passed in integer registers. All scratch registers, + // except for AT, V0 and T9, are available to be used as argument registers. + CCIfType<[i32], CCAssignToReg<[A0, A1, A2, A3, T0, T1, T2, T3, T4, T5, T6, + T7, T8, V1]>>, + + // f32 arguments are passed in single-precision floating pointer registers. + CCIfType<[f32], CCAssignToReg<[F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, + F11, F12, F13, F14, F15, F16, F17, F18, F19]>>, + + // Stack parameter slots for i32 and f32 are 32-bit words and 4-byte aligned. + CCIfType<[i32, f32], CCAssignToStack<4, 4>>, + + CCIfSubtarget<"isABI_EABI()", CCDelegateTo<CC_MipsEABI>>, + CCIfSubtarget<"isABI_O32()", CCDelegateTo<CC_MipsO32_FastCC>>, + CCDelegateTo<CC_MipsN_FastCC> +]>; + +//== + +def CC_Mips16RetHelper : CallingConv<[ + // Integer arguments are passed in integer registers. + CCIfType<[i32], CCAssignToReg<[V0, V1, A0, A1]>> +]>; + +//===----------------------------------------------------------------------===// +// Mips Calling Convention Dispatch +//===----------------------------------------------------------------------===// + +def RetCC_Mips : CallingConv<[ + CCIfSubtarget<"isABI_EABI()", CCDelegateTo<RetCC_MipsEABI>>, + CCIfSubtarget<"isABI_N32()", CCDelegateTo<RetCC_MipsN>>, + CCIfSubtarget<"isABI_N64()", CCDelegateTo<RetCC_MipsN>>, + CCDelegateTo<RetCC_MipsO32> +]>; + +//===----------------------------------------------------------------------===// +// Callee-saved register lists. +//===----------------------------------------------------------------------===// + +def CSR_SingleFloatOnly : CalleeSavedRegs<(add (sequence "F%u", 31, 20), RA, FP, + (sequence "S%u", 7, 0))>; + +def CSR_O32 : CalleeSavedRegs<(add (sequence "D%u", 15, 10), RA, FP, + (sequence "S%u", 7, 0))>; + +def CSR_O32_FP64 : CalleeSavedRegs<(add (sequence "D%u_64", 31, 20), RA, FP, + (sequence "S%u", 7, 0))>; + +def CSR_N32 : CalleeSavedRegs<(add D31_64, D29_64, D27_64, D25_64, D24_64, + D23_64, D22_64, D21_64, RA_64, FP_64, GP_64, + (sequence "S%u_64", 7, 0))>; + +def CSR_N64 : CalleeSavedRegs<(add (sequence "D%u_64", 31, 24), RA_64, FP_64, + GP_64, (sequence "S%u_64", 7, 0))>; + +def CSR_Mips16RetHelper : + CalleeSavedRegs<(add V0, V1, (sequence "A%u", 3, 0), S0, S1)>; diff --git a/contrib/llvm/lib/Target/Mips/MipsCodeEmitter.cpp b/contrib/llvm/lib/Target/Mips/MipsCodeEmitter.cpp new file mode 100644 index 000000000000..ca4163d4e58c --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsCodeEmitter.cpp @@ -0,0 +1,399 @@ +//===-- Mips/MipsCodeEmitter.cpp - Convert Mips 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 contains the pass that transforms the Mips machine instructions +// into relocatable machine code. +// +//===---------------------------------------------------------------------===// + +#define DEBUG_TYPE "jit" +#include "Mips.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsInstrInfo.h" +#include "MipsRelocations.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/JITCodeEmitter.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/PassManager.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#ifndef NDEBUG +#include <iomanip> +#endif + +using namespace llvm; + +STATISTIC(NumEmitted, "Number of machine instructions emitted"); + +namespace { + +class MipsCodeEmitter : public MachineFunctionPass { + MipsJITInfo *JTI; + const MipsInstrInfo *II; + const DataLayout *TD; + const MipsSubtarget *Subtarget; + TargetMachine &TM; + JITCodeEmitter &MCE; + const std::vector<MachineConstantPoolEntry> *MCPEs; + const std::vector<MachineJumpTableEntry> *MJTEs; + bool IsPIC; + + void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<MachineModuleInfo> (); + MachineFunctionPass::getAnalysisUsage(AU); + } + + static char ID; + +public: + MipsCodeEmitter(TargetMachine &tm, JITCodeEmitter &mce) + : MachineFunctionPass(ID), JTI(0), II(0), TD(0), + TM(tm), MCE(mce), MCPEs(0), MJTEs(0), + IsPIC(TM.getRelocationModel() == Reloc::PIC_) {} + + bool runOnMachineFunction(MachineFunction &MF); + + virtual const char *getPassName() const { + return "Mips Machine Code Emitter"; + } + + /// getBinaryCodeForInstr - This function, generated by the + /// CodeEmitterGenerator using TableGen, produces the binary encoding for + /// machine instructions. + uint64_t getBinaryCodeForInstr(const MachineInstr &MI) const; + + void emitInstruction(MachineBasicBlock::instr_iterator MI, + MachineBasicBlock &MBB); + +private: + + void emitWord(unsigned Word); + + /// Routines that handle operands which add machine relocations which are + /// fixed up by the relocation stage. + void emitGlobalAddress(const GlobalValue *GV, unsigned Reloc, + bool MayNeedFarStub) const; + void emitExternalSymbolAddress(const char *ES, unsigned Reloc) const; + void emitConstPoolAddress(unsigned CPI, unsigned Reloc) const; + void emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) const; + void emitMachineBasicBlock(MachineBasicBlock *BB, unsigned Reloc) const; + + /// getMachineOpValue - Return binary encoding of operand. If the machine + /// operand requires relocation, record the relocation and return zero. + unsigned getMachineOpValue(const MachineInstr &MI, + const MachineOperand &MO) const; + + unsigned getRelocation(const MachineInstr &MI, + const MachineOperand &MO) const; + + unsigned getJumpTargetOpValue(const MachineInstr &MI, unsigned OpNo) const; + unsigned getJumpTargetOpValueMM(const MachineInstr &MI, unsigned OpNo) const; + unsigned getBranchTargetOpValueMM(const MachineInstr &MI, + unsigned OpNo) const; + + unsigned getBranchTargetOpValue(const MachineInstr &MI, unsigned OpNo) const; + unsigned getMemEncoding(const MachineInstr &MI, unsigned OpNo) const; + unsigned getMemEncodingMMImm12(const MachineInstr &MI, unsigned OpNo) const; + unsigned getSizeExtEncoding(const MachineInstr &MI, unsigned OpNo) const; + unsigned getSizeInsEncoding(const MachineInstr &MI, unsigned OpNo) const; + unsigned getLSAImmEncoding(const MachineInstr &MI, unsigned OpNo) const; + + void emitGlobalAddressUnaligned(const GlobalValue *GV, unsigned Reloc, + int Offset) const; + + /// Expand pseudo instructions with accumulator register operands. + void expandACCInstr(MachineBasicBlock::instr_iterator MI, + MachineBasicBlock &MBB, unsigned Opc) const; + + /// \brief Expand pseudo instruction. Return true if MI was expanded. + bool expandPseudos(MachineBasicBlock::instr_iterator &MI, + MachineBasicBlock &MBB) const; +}; +} + +char MipsCodeEmitter::ID = 0; + +bool MipsCodeEmitter::runOnMachineFunction(MachineFunction &MF) { + MipsTargetMachine &Target = static_cast<MipsTargetMachine &>( + const_cast<TargetMachine &>(MF.getTarget())); + + JTI = Target.getJITInfo(); + II = Target.getInstrInfo(); + TD = Target.getDataLayout(); + Subtarget = &TM.getSubtarget<MipsSubtarget> (); + MCPEs = &MF.getConstantPool()->getConstants(); + MJTEs = 0; + if (MF.getJumpTableInfo()) MJTEs = &MF.getJumpTableInfo()->getJumpTables(); + JTI->Initialize(MF, IsPIC, Subtarget->isLittle()); + MCE.setModuleInfo(&getAnalysis<MachineModuleInfo> ()); + + do { + DEBUG(errs() << "JITTing function '" + << MF.getName() << "'\n"); + MCE.startFunction(MF); + + for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); + MBB != E; ++MBB){ + MCE.StartMachineBasicBlock(MBB); + for (MachineBasicBlock::instr_iterator I = MBB->instr_begin(), + E = MBB->instr_end(); I != E;) + emitInstruction(*I++, *MBB); + } + } while (MCE.finishFunction(MF)); + + return false; +} + +unsigned MipsCodeEmitter::getRelocation(const MachineInstr &MI, + const MachineOperand &MO) const { + // NOTE: This relocations are for static. + uint64_t TSFlags = MI.getDesc().TSFlags; + uint64_t Form = TSFlags & MipsII::FormMask; + if (Form == MipsII::FrmJ) + return Mips::reloc_mips_26; + if ((Form == MipsII::FrmI || Form == MipsII::FrmFI) + && MI.isBranch()) + return Mips::reloc_mips_pc16; + if (Form == MipsII::FrmI && MI.getOpcode() == Mips::LUi) + return Mips::reloc_mips_hi; + return Mips::reloc_mips_lo; +} + +unsigned MipsCodeEmitter::getJumpTargetOpValue(const MachineInstr &MI, + unsigned OpNo) const { + MachineOperand MO = MI.getOperand(OpNo); + if (MO.isGlobal()) + emitGlobalAddress(MO.getGlobal(), getRelocation(MI, MO), true); + else if (MO.isSymbol()) + emitExternalSymbolAddress(MO.getSymbolName(), getRelocation(MI, MO)); + else if (MO.isMBB()) + emitMachineBasicBlock(MO.getMBB(), getRelocation(MI, MO)); + else + llvm_unreachable("Unexpected jump target operand kind."); + return 0; +} + +unsigned MipsCodeEmitter::getJumpTargetOpValueMM(const MachineInstr &MI, + unsigned OpNo) const { + llvm_unreachable("Unimplemented function."); + return 0; +} + +unsigned MipsCodeEmitter::getBranchTargetOpValueMM(const MachineInstr &MI, + unsigned OpNo) const { + llvm_unreachable("Unimplemented function."); + return 0; +} + +unsigned MipsCodeEmitter::getBranchTargetOpValue(const MachineInstr &MI, + unsigned OpNo) const { + MachineOperand MO = MI.getOperand(OpNo); + emitMachineBasicBlock(MO.getMBB(), getRelocation(MI, MO)); + return 0; +} + +unsigned MipsCodeEmitter::getMemEncoding(const MachineInstr &MI, + unsigned OpNo) const { + // Base register is encoded in bits 20-16, offset is encoded in bits 15-0. + assert(MI.getOperand(OpNo).isReg()); + unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo)) << 16; + return (getMachineOpValue(MI, MI.getOperand(OpNo+1)) & 0xFFFF) | RegBits; +} + +unsigned MipsCodeEmitter::getMemEncodingMMImm12(const MachineInstr &MI, + unsigned OpNo) const { + llvm_unreachable("Unimplemented function."); + return 0; +} + +unsigned MipsCodeEmitter::getSizeExtEncoding(const MachineInstr &MI, + unsigned OpNo) const { + // size is encoded as size-1. + return getMachineOpValue(MI, MI.getOperand(OpNo)) - 1; +} + +unsigned MipsCodeEmitter::getSizeInsEncoding(const MachineInstr &MI, + unsigned OpNo) const { + // size is encoded as pos+size-1. + return getMachineOpValue(MI, MI.getOperand(OpNo-1)) + + getMachineOpValue(MI, MI.getOperand(OpNo)) - 1; +} + +unsigned MipsCodeEmitter::getLSAImmEncoding(const MachineInstr &MI, + unsigned OpNo) const { + llvm_unreachable("Unimplemented function."); + return 0; +} + +/// getMachineOpValue - Return binary encoding of operand. If the machine +/// operand requires relocation, record the relocation and return zero. +unsigned MipsCodeEmitter::getMachineOpValue(const MachineInstr &MI, + const MachineOperand &MO) const { + if (MO.isReg()) + return TM.getRegisterInfo()->getEncodingValue(MO.getReg()); + else if (MO.isImm()) + return static_cast<unsigned>(MO.getImm()); + else if (MO.isGlobal()) + emitGlobalAddress(MO.getGlobal(), getRelocation(MI, MO), true); + else if (MO.isSymbol()) + emitExternalSymbolAddress(MO.getSymbolName(), getRelocation(MI, MO)); + else if (MO.isCPI()) + emitConstPoolAddress(MO.getIndex(), getRelocation(MI, MO)); + else if (MO.isJTI()) + emitJumpTableAddress(MO.getIndex(), getRelocation(MI, MO)); + else if (MO.isMBB()) + emitMachineBasicBlock(MO.getMBB(), getRelocation(MI, MO)); + else + llvm_unreachable("Unable to encode MachineOperand!"); + return 0; +} + +void MipsCodeEmitter::emitGlobalAddress(const GlobalValue *GV, unsigned Reloc, + bool MayNeedFarStub) const { + MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc, + const_cast<GlobalValue *>(GV), 0, + MayNeedFarStub)); +} + +void MipsCodeEmitter::emitGlobalAddressUnaligned(const GlobalValue *GV, + unsigned Reloc, int Offset) const { + MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset(), Reloc, + const_cast<GlobalValue *>(GV), 0, false)); + MCE.addRelocation(MachineRelocation::getGV(MCE.getCurrentPCOffset() + Offset, + Reloc, const_cast<GlobalValue *>(GV), 0, false)); +} + +void MipsCodeEmitter:: +emitExternalSymbolAddress(const char *ES, unsigned Reloc) const { + MCE.addRelocation(MachineRelocation::getExtSym(MCE.getCurrentPCOffset(), + Reloc, ES, 0, 0)); +} + +void MipsCodeEmitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc) const { + MCE.addRelocation(MachineRelocation::getConstPool(MCE.getCurrentPCOffset(), + Reloc, CPI, 0, false)); +} + +void MipsCodeEmitter:: +emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) const { + MCE.addRelocation(MachineRelocation::getJumpTable(MCE.getCurrentPCOffset(), + Reloc, JTIndex, 0, false)); +} + +void MipsCodeEmitter::emitMachineBasicBlock(MachineBasicBlock *BB, + unsigned Reloc) const { + MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(), + Reloc, BB)); +} + +void MipsCodeEmitter::emitInstruction(MachineBasicBlock::instr_iterator MI, + MachineBasicBlock &MBB) { + DEBUG(errs() << "JIT: " << (void*)MCE.getCurrentPCValue() << ":\t" << *MI); + + // Expand pseudo instruction. Skip if MI was not expanded. + if (((MI->getDesc().TSFlags & MipsII::FormMask) == MipsII::Pseudo) && + !expandPseudos(MI, MBB)) + return; + + MCE.processDebugLoc(MI->getDebugLoc(), true); + + emitWord(getBinaryCodeForInstr(*MI)); + ++NumEmitted; // Keep track of the # of mi's emitted + + MCE.processDebugLoc(MI->getDebugLoc(), false); +} + +void MipsCodeEmitter::emitWord(unsigned Word) { + DEBUG(errs() << " 0x"; + errs().write_hex(Word) << "\n"); + if (Subtarget->isLittle()) + MCE.emitWordLE(Word); + else + MCE.emitWordBE(Word); +} + +void MipsCodeEmitter::expandACCInstr(MachineBasicBlock::instr_iterator MI, + MachineBasicBlock &MBB, + unsigned Opc) const { + // Expand "pseudomult $ac0, $t0, $t1" to "mult $t0, $t1". + BuildMI(MBB, &*MI, MI->getDebugLoc(), II->get(Opc)) + .addReg(MI->getOperand(1).getReg()).addReg(MI->getOperand(2).getReg()); +} + +bool MipsCodeEmitter::expandPseudos(MachineBasicBlock::instr_iterator &MI, + MachineBasicBlock &MBB) const { + switch (MI->getOpcode()) { + case Mips::NOP: + BuildMI(MBB, &*MI, MI->getDebugLoc(), II->get(Mips::SLL), Mips::ZERO) + .addReg(Mips::ZERO).addImm(0); + break; + case Mips::B: + BuildMI(MBB, &*MI, MI->getDebugLoc(), II->get(Mips::BEQ)).addReg(Mips::ZERO) + .addReg(Mips::ZERO).addOperand(MI->getOperand(0)); + break; + case Mips::TRAP: + BuildMI(MBB, &*MI, MI->getDebugLoc(), II->get(Mips::BREAK)).addImm(0) + .addImm(0); + break; + case Mips::JALRPseudo: + BuildMI(MBB, &*MI, MI->getDebugLoc(), II->get(Mips::JALR), Mips::RA) + .addReg(MI->getOperand(0).getReg()); + break; + case Mips::PseudoMULT: + expandACCInstr(MI, MBB, Mips::MULT); + break; + case Mips::PseudoMULTu: + expandACCInstr(MI, MBB, Mips::MULTu); + break; + case Mips::PseudoSDIV: + expandACCInstr(MI, MBB, Mips::SDIV); + break; + case Mips::PseudoUDIV: + expandACCInstr(MI, MBB, Mips::UDIV); + break; + case Mips::PseudoMADD: + expandACCInstr(MI, MBB, Mips::MADD); + break; + case Mips::PseudoMADDU: + expandACCInstr(MI, MBB, Mips::MADDU); + break; + case Mips::PseudoMSUB: + expandACCInstr(MI, MBB, Mips::MSUB); + break; + case Mips::PseudoMSUBU: + expandACCInstr(MI, MBB, Mips::MSUBU); + break; + default: + return false; + } + + (MI--)->eraseFromBundle(); + return true; +} + +/// createMipsJITCodeEmitterPass - Return a pass that emits the collected Mips +/// code to the specified MCE object. +FunctionPass *llvm::createMipsJITCodeEmitterPass(MipsTargetMachine &TM, + JITCodeEmitter &JCE) { + return new MipsCodeEmitter(TM, JCE); +} + +#include "MipsGenCodeEmitter.inc" diff --git a/contrib/llvm/lib/Target/Mips/MipsCondMov.td b/contrib/llvm/lib/Target/Mips/MipsCondMov.td new file mode 100644 index 000000000000..2de1430a395f --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsCondMov.td @@ -0,0 +1,245 @@ +//===-- MipsCondMov.td - Describe Mips Conditional Moves --*- 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 Conditional Moves implementation. +// +//===----------------------------------------------------------------------===// + +// Conditional moves: +// These instructions are expanded in +// MipsISelLowering::EmitInstrWithCustomInserter if target does not have +// conditional move instructions. +// cond:int, data:int +class CMov_I_I_FT<string opstr, RegisterOperand CRC, RegisterOperand DRC, + InstrItinClass Itin> : + InstSE<(outs DRC:$rd), (ins DRC:$rs, CRC:$rt, DRC:$F), + !strconcat(opstr, "\t$rd, $rs, $rt"), [], Itin, FrmFR, opstr> { + let Constraints = "$F = $rd"; +} + +// cond:int, data:float +class CMov_I_F_FT<string opstr, RegisterOperand CRC, RegisterOperand DRC, + InstrItinClass Itin> : + InstSE<(outs DRC:$fd), (ins DRC:$fs, CRC:$rt, DRC:$F), + !strconcat(opstr, "\t$fd, $fs, $rt"), [], Itin, FrmFR> { + let Constraints = "$F = $fd"; +} + +// cond:float, data:int +class CMov_F_I_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, + SDPatternOperator OpNode = null_frag> : + InstSE<(outs RC:$rd), (ins RC:$rs, FCCRegsOpnd:$fcc, RC:$F), + !strconcat(opstr, "\t$rd, $rs, $fcc"), + [(set RC:$rd, (OpNode RC:$rs, FCCRegsOpnd:$fcc, RC:$F))], + Itin, FrmFR, opstr> { + let Constraints = "$F = $rd"; +} + +// cond:float, data:float +class CMov_F_F_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, + SDPatternOperator OpNode = null_frag> : + InstSE<(outs RC:$fd), (ins RC:$fs, FCCRegsOpnd:$fcc, RC:$F), + !strconcat(opstr, "\t$fd, $fs, $fcc"), + [(set RC:$fd, (OpNode RC:$fs, FCCRegsOpnd:$fcc, RC:$F))], + Itin, FrmFR> { + let Constraints = "$F = $fd"; +} + +// select patterns +multiclass MovzPats0<RegisterClass CRC, RegisterClass DRC, + Instruction MOVZInst, Instruction SLTOp, + Instruction SLTuOp, Instruction SLTiOp, + Instruction SLTiuOp> { + def : MipsPat<(select (i32 (setge CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTOp CRC:$lhs, CRC:$rhs), DRC:$F)>; + def : MipsPat<(select (i32 (setuge CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTuOp CRC:$lhs, CRC:$rhs), DRC:$F)>; + def : MipsPat<(select (i32 (setge CRC:$lhs, immSExt16:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTiOp CRC:$lhs, immSExt16:$rhs), DRC:$F)>; + def : MipsPat<(select (i32 (setuge CRC:$lh, immSExt16:$rh)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTiuOp CRC:$lh, immSExt16:$rh), DRC:$F)>; + def : MipsPat<(select (i32 (setle CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTOp CRC:$rhs, CRC:$lhs), DRC:$F)>; + def : MipsPat<(select (i32 (setule CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTuOp CRC:$rhs, CRC:$lhs), DRC:$F)>; + def : MipsPat<(select (i32 (setgt CRC:$lhs, immSExt16Plus1:$rhs)), + DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTiOp CRC:$lhs, (Plus1 imm:$rhs)), DRC:$F)>; + def : MipsPat<(select (i32 (setugt CRC:$lhs, immSExt16Plus1:$rhs)), + DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (SLTiuOp CRC:$lhs, (Plus1 imm:$rhs)), + DRC:$F)>; +} + +multiclass MovzPats1<RegisterClass CRC, RegisterClass DRC, + Instruction MOVZInst, Instruction XOROp> { + def : MipsPat<(select (i32 (seteq CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (XOROp CRC:$lhs, CRC:$rhs), DRC:$F)>; + def : MipsPat<(select (i32 (seteq CRC:$lhs, 0)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, CRC:$lhs, DRC:$F)>; +} + +multiclass MovzPats2<RegisterClass CRC, RegisterClass DRC, + Instruction MOVZInst, Instruction XORiOp> { + def : MipsPat< + (select (i32 (seteq CRC:$lhs, immZExt16:$uimm16)), DRC:$T, DRC:$F), + (MOVZInst DRC:$T, (XORiOp CRC:$lhs, immZExt16:$uimm16), DRC:$F)>; +} + +multiclass MovnPats<RegisterClass CRC, RegisterClass DRC, Instruction MOVNInst, + Instruction XOROp> { + def : MipsPat<(select (i32 (setne CRC:$lhs, CRC:$rhs)), DRC:$T, DRC:$F), + (MOVNInst DRC:$T, (XOROp CRC:$lhs, CRC:$rhs), DRC:$F)>; + def : MipsPat<(select CRC:$cond, DRC:$T, DRC:$F), + (MOVNInst DRC:$T, CRC:$cond, DRC:$F)>; + def : MipsPat<(select (i32 (setne CRC:$lhs, 0)),DRC:$T, DRC:$F), + (MOVNInst DRC:$T, CRC:$lhs, DRC:$F)>; +} + +// Instantiation of instructions. +def MOVZ_I_I : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd, IIArith>, + ADD_FM<0, 0xa>; + +let Predicates = [HasStdEnc], isCodeGenOnly = 1 in { + def MOVZ_I_I64 : CMov_I_I_FT<"movz", GPR32Opnd, GPR64Opnd, IIArith>, + ADD_FM<0, 0xa>; + def MOVZ_I64_I : CMov_I_I_FT<"movz", GPR64Opnd, GPR32Opnd, IIArith>, + ADD_FM<0, 0xa>; + def MOVZ_I64_I64 : CMov_I_I_FT<"movz", GPR64Opnd, GPR64Opnd, IIArith>, + ADD_FM<0, 0xa>; +} + +def MOVN_I_I : MMRel, CMov_I_I_FT<"movn", GPR32Opnd, GPR32Opnd, IIArith>, + ADD_FM<0, 0xb>; + +let Predicates = [HasStdEnc], isCodeGenOnly = 1 in { + def MOVN_I_I64 : CMov_I_I_FT<"movn", GPR32Opnd, GPR64Opnd, IIArith>, + ADD_FM<0, 0xb>; + def MOVN_I64_I : CMov_I_I_FT<"movn", GPR64Opnd, GPR32Opnd, IIArith>, + ADD_FM<0, 0xb>; + def MOVN_I64_I64 : CMov_I_I_FT<"movn", GPR64Opnd, GPR64Opnd, IIArith>, + ADD_FM<0, 0xb>; +} + +def MOVZ_I_S : CMov_I_F_FT<"movz.s", GPR32Opnd, FGR32Opnd, IIFmove>, + CMov_I_F_FM<18, 16>; + +let isCodeGenOnly = 1 in +def MOVZ_I64_S : CMov_I_F_FT<"movz.s", GPR64Opnd, FGR32Opnd, IIFmove>, + CMov_I_F_FM<18, 16>, Requires<[HasMips64, HasStdEnc]>; + +def MOVN_I_S : CMov_I_F_FT<"movn.s", GPR32Opnd, FGR32Opnd, IIFmove>, + CMov_I_F_FM<19, 16>; + +let isCodeGenOnly = 1 in +def MOVN_I64_S : CMov_I_F_FT<"movn.s", GPR64Opnd, FGR32Opnd, IIFmove>, + CMov_I_F_FM<19, 16>, Requires<[HasMips64, HasStdEnc]>; + +let Predicates = [NotFP64bit, HasStdEnc] in { + def MOVZ_I_D32 : CMov_I_F_FT<"movz.d", GPR32Opnd, AFGR64Opnd, IIFmove>, + CMov_I_F_FM<18, 17>; + def MOVN_I_D32 : CMov_I_F_FT<"movn.d", GPR32Opnd, AFGR64Opnd, IIFmove>, + CMov_I_F_FM<19, 17>; +} + +let Predicates = [IsFP64bit, HasStdEnc], DecoderNamespace = "Mips64" in { + def MOVZ_I_D64 : CMov_I_F_FT<"movz.d", GPR32Opnd, FGR64Opnd, IIFmove>, + CMov_I_F_FM<18, 17>; + def MOVN_I_D64 : CMov_I_F_FT<"movn.d", GPR32Opnd, FGR64Opnd, IIFmove>, + CMov_I_F_FM<19, 17>; + let isCodeGenOnly = 1 in { + def MOVZ_I64_D64 : CMov_I_F_FT<"movz.d", GPR64Opnd, FGR64Opnd, + IIFmove>, CMov_I_F_FM<18, 17>; + def MOVN_I64_D64 : CMov_I_F_FT<"movn.d", GPR64Opnd, FGR64Opnd, + IIFmove>, CMov_I_F_FM<19, 17>; + } +} + +def MOVT_I : MMRel, CMov_F_I_FT<"movt", GPR32Opnd, IIArith, MipsCMovFP_T>, + CMov_F_I_FM<1>; + +let isCodeGenOnly = 1 in +def MOVT_I64 : CMov_F_I_FT<"movt", GPR64Opnd, IIArith, MipsCMovFP_T>, + CMov_F_I_FM<1>, Requires<[HasMips64, HasStdEnc]>; + +def MOVF_I : MMRel, CMov_F_I_FT<"movf", GPR32Opnd, IIArith, MipsCMovFP_F>, + CMov_F_I_FM<0>; + +let isCodeGenOnly = 1 in +def MOVF_I64 : CMov_F_I_FT<"movf", GPR64Opnd, IIArith, MipsCMovFP_F>, + CMov_F_I_FM<0>, Requires<[HasMips64, HasStdEnc]>; + +def MOVT_S : CMov_F_F_FT<"movt.s", FGR32Opnd, IIFmove, MipsCMovFP_T>, + CMov_F_F_FM<16, 1>; +def MOVF_S : CMov_F_F_FT<"movf.s", FGR32Opnd, IIFmove, MipsCMovFP_F>, + CMov_F_F_FM<16, 0>; + +let Predicates = [NotFP64bit, HasStdEnc] in { + def MOVT_D32 : CMov_F_F_FT<"movt.d", AFGR64Opnd, IIFmove, MipsCMovFP_T>, + CMov_F_F_FM<17, 1>; + def MOVF_D32 : CMov_F_F_FT<"movf.d", AFGR64Opnd, IIFmove, MipsCMovFP_F>, + CMov_F_F_FM<17, 0>; +} + +let Predicates = [IsFP64bit, HasStdEnc], DecoderNamespace = "Mips64" in { + def MOVT_D64 : CMov_F_F_FT<"movt.d", FGR64Opnd, IIFmove, MipsCMovFP_T>, + CMov_F_F_FM<17, 1>; + def MOVF_D64 : CMov_F_F_FT<"movf.d", FGR64Opnd, IIFmove, MipsCMovFP_F>, + CMov_F_F_FM<17, 0>; +} + +// Instantiation of conditional move patterns. +defm : MovzPats0<GPR32, GPR32, MOVZ_I_I, SLT, SLTu, SLTi, SLTiu>; +defm : MovzPats1<GPR32, GPR32, MOVZ_I_I, XOR>; +defm : MovzPats2<GPR32, GPR32, MOVZ_I_I, XORi>; +let Predicates = [HasMips64, HasStdEnc] in { + defm : MovzPats0<GPR32, GPR64, MOVZ_I_I64, SLT, SLTu, SLTi, SLTiu>; + defm : MovzPats0<GPR64, GPR32, MOVZ_I_I, SLT64, SLTu64, SLTi64, + SLTiu64>; + defm : MovzPats0<GPR64, GPR64, MOVZ_I_I64, SLT64, SLTu64, SLTi64, + SLTiu64>; + defm : MovzPats1<GPR32, GPR64, MOVZ_I_I64, XOR>; + defm : MovzPats1<GPR64, GPR32, MOVZ_I64_I, XOR64>; + defm : MovzPats1<GPR64, GPR64, MOVZ_I64_I64, XOR64>; + defm : MovzPats2<GPR32, GPR64, MOVZ_I_I64, XORi>; + defm : MovzPats2<GPR64, GPR32, MOVZ_I64_I, XORi64>; + defm : MovzPats2<GPR64, GPR64, MOVZ_I64_I64, XORi64>; +} + +defm : MovnPats<GPR32, GPR32, MOVN_I_I, XOR>; +let Predicates = [HasMips64, HasStdEnc] in { + defm : MovnPats<GPR32, GPR64, MOVN_I_I64, XOR>; + defm : MovnPats<GPR64, GPR32, MOVN_I64_I, XOR64>; + defm : MovnPats<GPR64, GPR64, MOVN_I64_I64, XOR64>; +} + +defm : MovzPats0<GPR32, FGR32, MOVZ_I_S, SLT, SLTu, SLTi, SLTiu>; +defm : MovzPats1<GPR32, FGR32, MOVZ_I_S, XOR>; +defm : MovnPats<GPR32, FGR32, MOVN_I_S, XOR>; +let Predicates = [HasMips64, HasStdEnc] in { + defm : MovzPats0<GPR64, FGR32, MOVZ_I_S, SLT64, SLTu64, SLTi64, + SLTiu64>; + defm : MovzPats1<GPR64, FGR32, MOVZ_I64_S, XOR64>; + defm : MovnPats<GPR64, FGR32, MOVN_I64_S, XOR64>; +} + +let Predicates = [NotFP64bit, HasStdEnc] in { + defm : MovzPats0<GPR32, AFGR64, MOVZ_I_D32, SLT, SLTu, SLTi, SLTiu>; + defm : MovzPats1<GPR32, AFGR64, MOVZ_I_D32, XOR>; + defm : MovnPats<GPR32, AFGR64, MOVN_I_D32, XOR>; +} +let Predicates = [IsFP64bit, HasStdEnc] in { + defm : MovzPats0<GPR32, FGR64, MOVZ_I_D64, SLT, SLTu, SLTi, SLTiu>; + defm : MovzPats0<GPR64, FGR64, MOVZ_I_D64, SLT64, SLTu64, SLTi64, + SLTiu64>; + defm : MovzPats1<GPR32, FGR64, MOVZ_I_D64, XOR>; + defm : MovzPats1<GPR64, FGR64, MOVZ_I64_D64, XOR64>; + defm : MovnPats<GPR32, FGR64, MOVN_I_D64, XOR>; + defm : MovnPats<GPR64, FGR64, MOVN_I64_D64, XOR64>; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp b/contrib/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp new file mode 100644 index 000000000000..c46bbacf6585 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsConstantIslandPass.cpp @@ -0,0 +1,1533 @@ +//===-- MipsConstantIslandPass.cpp - Emit Pc Relative loads----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// This pass is used to make Pc relative loads of constants. +// For now, only Mips16 will use this. +// +// Loading constants inline is expensive on Mips16 and it's in general better +// to place the constant nearby in code space and then it can be loaded with a +// simple 16 bit load instruction. +// +// The constants can be not just numbers but addresses of functions and labels. +// This can be particularly helpful in static relocation mode for embedded +// non linux targets. +// +// + +#define DEBUG_TYPE "mips-constant-islands" + +#include "Mips.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "Mips16InstrInfo.h" +#include "MipsMachineFunction.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/InstIterator.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Support/Format.h" +#include <algorithm> + +using namespace llvm; + +STATISTIC(NumCPEs, "Number of constpool entries"); +STATISTIC(NumSplit, "Number of uncond branches inserted"); +STATISTIC(NumCBrFixed, "Number of cond branches fixed"); +STATISTIC(NumUBrFixed, "Number of uncond branches fixed"); + +// FIXME: This option should be removed once it has received sufficient testing. +static cl::opt<bool> +AlignConstantIslands("mips-align-constant-islands", cl::Hidden, cl::init(true), + cl::desc("Align constant islands in code")); + + +// Rather than do make check tests with huge amounts of code, we force +// the test to use this amount. +// +static cl::opt<int> ConstantIslandsSmallOffset( + "mips-constant-islands-small-offset", + cl::init(0), + cl::desc("Make small offsets be this amount for testing purposes"), + cl::Hidden); + +// +// For testing purposes we tell it to not use relaxed load forms so that it +// will split blocks. +// +static cl::opt<bool> NoLoadRelaxation( + "mips-constant-islands-no-load-relaxation", + cl::init(false), + cl::desc("Don't relax loads to long loads - for testing purposes"), + cl::Hidden); + + +namespace { + + + typedef MachineBasicBlock::iterator Iter; + typedef MachineBasicBlock::reverse_iterator ReverseIter; + + /// MipsConstantIslands - Due to limited PC-relative displacements, Mips + /// requires constant pool entries to be scattered among the instructions + /// inside a function. To do this, it completely ignores the normal LLVM + /// constant pool; instead, it places constants wherever it feels like with + /// special instructions. + /// + /// The terminology used in this pass includes: + /// Islands - Clumps of constants placed in the function. + /// Water - Potential places where an island could be formed. + /// CPE - A constant pool entry that has been placed somewhere, which + /// tracks a list of users. + + class MipsConstantIslands : public MachineFunctionPass { + + /// BasicBlockInfo - Information about the offset and size of a single + /// basic block. + struct BasicBlockInfo { + /// Offset - Distance from the beginning of the function to the beginning + /// of this basic block. + /// + /// Offsets are computed assuming worst case padding before an aligned + /// block. This means that subtracting basic block offsets always gives a + /// conservative estimate of the real distance which may be smaller. + /// + /// Because worst case padding is used, the computed offset of an aligned + /// block may not actually be aligned. + unsigned Offset; + + /// Size - Size of the basic block in bytes. If the block contains + /// inline assembly, this is a worst case estimate. + /// + /// The size does not include any alignment padding whether from the + /// beginning of the block, or from an aligned jump table at the end. + unsigned Size; + + // FIXME: ignore LogAlign for this patch + // + unsigned postOffset(unsigned LogAlign = 0) const { + unsigned PO = Offset + Size; + return PO; + } + + BasicBlockInfo() : Offset(0), Size(0) {} + + }; + + std::vector<BasicBlockInfo> BBInfo; + + /// WaterList - A sorted list of basic blocks where islands could be placed + /// (i.e. blocks that don't fall through to the following block, due + /// to a return, unreachable, or unconditional branch). + std::vector<MachineBasicBlock*> WaterList; + + /// NewWaterList - The subset of WaterList that was created since the + /// previous iteration by inserting unconditional branches. + SmallSet<MachineBasicBlock*, 4> NewWaterList; + + typedef std::vector<MachineBasicBlock*>::iterator water_iterator; + + /// CPUser - One user of a constant pool, keeping the machine instruction + /// pointer, the constant pool being referenced, and the max displacement + /// allowed from the instruction to the CP. The HighWaterMark records the + /// highest basic block where a new CPEntry can be placed. To ensure this + /// pass terminates, the CP entries are initially placed at the end of the + /// function and then move monotonically to lower addresses. The + /// exception to this rule is when the current CP entry for a particular + /// CPUser is out of range, but there is another CP entry for the same + /// constant value in range. We want to use the existing in-range CP + /// entry, but if it later moves out of range, the search for new water + /// should resume where it left off. The HighWaterMark is used to record + /// that point. + struct CPUser { + MachineInstr *MI; + MachineInstr *CPEMI; + MachineBasicBlock *HighWaterMark; + private: + unsigned MaxDisp; + unsigned LongFormMaxDisp; // mips16 has 16/32 bit instructions + // with different displacements + unsigned LongFormOpcode; + public: + bool NegOk; + CPUser(MachineInstr *mi, MachineInstr *cpemi, unsigned maxdisp, + bool neg, + unsigned longformmaxdisp, unsigned longformopcode) + : MI(mi), CPEMI(cpemi), MaxDisp(maxdisp), + LongFormMaxDisp(longformmaxdisp), LongFormOpcode(longformopcode), + NegOk(neg){ + HighWaterMark = CPEMI->getParent(); + } + /// getMaxDisp - Returns the maximum displacement supported by MI. + unsigned getMaxDisp() const { + unsigned xMaxDisp = ConstantIslandsSmallOffset? + ConstantIslandsSmallOffset: MaxDisp; + return xMaxDisp; + } + void setMaxDisp(unsigned val) { + MaxDisp = val; + } + unsigned getLongFormMaxDisp() const { + return LongFormMaxDisp; + } + unsigned getLongFormOpcode() const { + return LongFormOpcode; + } + }; + + /// CPUsers - Keep track of all of the machine instructions that use various + /// constant pools and their max displacement. + std::vector<CPUser> CPUsers; + + /// CPEntry - One per constant pool entry, keeping the machine instruction + /// pointer, the constpool index, and the number of CPUser's which + /// reference this entry. + struct CPEntry { + MachineInstr *CPEMI; + unsigned CPI; + unsigned RefCount; + CPEntry(MachineInstr *cpemi, unsigned cpi, unsigned rc = 0) + : CPEMI(cpemi), CPI(cpi), RefCount(rc) {} + }; + + /// CPEntries - Keep track of all of the constant pool entry machine + /// instructions. For each original constpool index (i.e. those that + /// existed upon entry to this pass), it keeps a vector of entries. + /// Original elements are cloned as we go along; the clones are + /// put in the vector of the original element, but have distinct CPIs. + std::vector<std::vector<CPEntry> > CPEntries; + + /// ImmBranch - One per immediate branch, keeping the machine instruction + /// pointer, conditional or unconditional, the max displacement, + /// and (if isCond is true) the corresponding unconditional branch + /// opcode. + struct ImmBranch { + MachineInstr *MI; + unsigned MaxDisp : 31; + bool isCond : 1; + int UncondBr; + ImmBranch(MachineInstr *mi, unsigned maxdisp, bool cond, int ubr) + : MI(mi), MaxDisp(maxdisp), isCond(cond), UncondBr(ubr) {} + }; + + /// ImmBranches - Keep track of all the immediate branch instructions. + /// + std::vector<ImmBranch> ImmBranches; + + /// HasFarJump - True if any far jump instruction has been emitted during + /// the branch fix up pass. + bool HasFarJump; + + const TargetMachine &TM; + bool IsPIC; + unsigned ABI; + const MipsSubtarget *STI; + const Mips16InstrInfo *TII; + MipsFunctionInfo *MFI; + MachineFunction *MF; + MachineConstantPool *MCP; + + unsigned PICLabelUId; + bool PrescannedForConstants; + + void initPICLabelUId(unsigned UId) { + PICLabelUId = UId; + } + + + unsigned createPICLabelUId() { + return PICLabelUId++; + } + + public: + static char ID; + MipsConstantIslands(TargetMachine &tm) + : MachineFunctionPass(ID), TM(tm), + IsPIC(TM.getRelocationModel() == Reloc::PIC_), + ABI(TM.getSubtarget<MipsSubtarget>().getTargetABI()), + STI(&TM.getSubtarget<MipsSubtarget>()), MF(0), MCP(0), + PrescannedForConstants(false){} + + virtual const char *getPassName() const { + return "Mips Constant Islands"; + } + + bool runOnMachineFunction(MachineFunction &F); + + void doInitialPlacement(std::vector<MachineInstr*> &CPEMIs); + CPEntry *findConstPoolEntry(unsigned CPI, const MachineInstr *CPEMI); + unsigned getCPELogAlign(const MachineInstr *CPEMI); + void initializeFunctionInfo(const std::vector<MachineInstr*> &CPEMIs); + unsigned getOffsetOf(MachineInstr *MI) const; + unsigned getUserOffset(CPUser&) const; + void dumpBBs(); + void verify(); + + bool isOffsetInRange(unsigned UserOffset, unsigned TrialOffset, + unsigned Disp, bool NegativeOK); + bool isOffsetInRange(unsigned UserOffset, unsigned TrialOffset, + const CPUser &U); + + bool isLongFormOffsetInRange(unsigned UserOffset, unsigned TrialOffset, + const CPUser &U); + + void computeBlockSize(MachineBasicBlock *MBB); + MachineBasicBlock *splitBlockBeforeInstr(MachineInstr *MI); + void updateForInsertedWaterBlock(MachineBasicBlock *NewBB); + void adjustBBOffsetsAfter(MachineBasicBlock *BB); + bool decrementCPEReferenceCount(unsigned CPI, MachineInstr* CPEMI); + int findInRangeCPEntry(CPUser& U, unsigned UserOffset); + int findLongFormInRangeCPEntry(CPUser& U, unsigned UserOffset); + bool findAvailableWater(CPUser&U, unsigned UserOffset, + water_iterator &WaterIter); + void createNewWater(unsigned CPUserIndex, unsigned UserOffset, + MachineBasicBlock *&NewMBB); + bool handleConstantPoolUser(unsigned CPUserIndex); + void removeDeadCPEMI(MachineInstr *CPEMI); + bool removeUnusedCPEntries(); + bool isCPEntryInRange(MachineInstr *MI, unsigned UserOffset, + MachineInstr *CPEMI, unsigned Disp, bool NegOk, + bool DoDump = false); + bool isWaterInRange(unsigned UserOffset, MachineBasicBlock *Water, + CPUser &U, unsigned &Growth); + bool isBBInRange(MachineInstr *MI, MachineBasicBlock *BB, unsigned Disp); + bool fixupImmediateBr(ImmBranch &Br); + bool fixupConditionalBr(ImmBranch &Br); + bool fixupUnconditionalBr(ImmBranch &Br); + + void prescanForConstants(); + + private: + + }; + + char MipsConstantIslands::ID = 0; +} // end of anonymous namespace + + +bool MipsConstantIslands::isLongFormOffsetInRange + (unsigned UserOffset, unsigned TrialOffset, + const CPUser &U) { + return isOffsetInRange(UserOffset, TrialOffset, + U.getLongFormMaxDisp(), U.NegOk); +} + +bool MipsConstantIslands::isOffsetInRange + (unsigned UserOffset, unsigned TrialOffset, + const CPUser &U) { + return isOffsetInRange(UserOffset, TrialOffset, + U.getMaxDisp(), U.NegOk); +} +/// print block size and offset information - debugging +void MipsConstantIslands::dumpBBs() { + DEBUG({ + for (unsigned J = 0, E = BBInfo.size(); J !=E; ++J) { + const BasicBlockInfo &BBI = BBInfo[J]; + dbgs() << format("%08x BB#%u\t", BBI.Offset, J) + << format(" size=%#x\n", BBInfo[J].Size); + } + }); +} +/// createMipsLongBranchPass - Returns a pass that converts branches to long +/// branches. +FunctionPass *llvm::createMipsConstantIslandPass(MipsTargetMachine &tm) { + return new MipsConstantIslands(tm); +} + +bool MipsConstantIslands::runOnMachineFunction(MachineFunction &mf) { + // The intention is for this to be a mips16 only pass for now + // FIXME: + MF = &mf; + MCP = mf.getConstantPool(); + DEBUG(dbgs() << "constant island machine function " << "\n"); + if (!TM.getSubtarget<MipsSubtarget>().inMips16Mode() || + !MipsSubtarget::useConstantIslands()) { + return false; + } + TII = (const Mips16InstrInfo*)MF->getTarget().getInstrInfo(); + MFI = MF->getInfo<MipsFunctionInfo>(); + DEBUG(dbgs() << "constant island processing " << "\n"); + // + // will need to make predermination if there is any constants we need to + // put in constant islands. TBD. + // + if (!PrescannedForConstants) prescanForConstants(); + + HasFarJump = false; + // This pass invalidates liveness information when it splits basic blocks. + MF->getRegInfo().invalidateLiveness(); + + // Renumber all of the machine basic blocks in the function, guaranteeing that + // the numbers agree with the position of the block in the function. + MF->RenumberBlocks(); + + bool MadeChange = false; + + // Perform the initial placement of the constant pool entries. To start with, + // we put them all at the end of the function. + std::vector<MachineInstr*> CPEMIs; + if (!MCP->isEmpty()) + doInitialPlacement(CPEMIs); + + /// The next UID to take is the first unused one. + initPICLabelUId(CPEMIs.size()); + + // Do the initial scan of the function, building up information about the + // sizes of each block, the location of all the water, and finding all of the + // constant pool users. + initializeFunctionInfo(CPEMIs); + CPEMIs.clear(); + DEBUG(dumpBBs()); + + /// Remove dead constant pool entries. + MadeChange |= removeUnusedCPEntries(); + + // Iteratively place constant pool entries and fix up branches until there + // is no change. + unsigned NoCPIters = 0, NoBRIters = 0; + (void)NoBRIters; + while (true) { + DEBUG(dbgs() << "Beginning CP iteration #" << NoCPIters << '\n'); + bool CPChange = false; + for (unsigned i = 0, e = CPUsers.size(); i != e; ++i) + CPChange |= handleConstantPoolUser(i); + if (CPChange && ++NoCPIters > 30) + report_fatal_error("Constant Island pass failed to converge!"); + DEBUG(dumpBBs()); + + // Clear NewWaterList now. If we split a block for branches, it should + // appear as "new water" for the next iteration of constant pool placement. + NewWaterList.clear(); + + DEBUG(dbgs() << "Beginning BR iteration #" << NoBRIters << '\n'); + bool BRChange = false; + for (unsigned i = 0, e = ImmBranches.size(); i != e; ++i) + BRChange |= fixupImmediateBr(ImmBranches[i]); + if (BRChange && ++NoBRIters > 30) + report_fatal_error("Branch Fix Up pass failed to converge!"); + DEBUG(dumpBBs()); + if (!CPChange && !BRChange) + break; + MadeChange = true; + } + + DEBUG(dbgs() << '\n'; dumpBBs()); + + BBInfo.clear(); + WaterList.clear(); + CPUsers.clear(); + CPEntries.clear(); + ImmBranches.clear(); + return MadeChange; +} + +/// doInitialPlacement - Perform the initial placement of the constant pool +/// entries. To start with, we put them all at the end of the function. +void +MipsConstantIslands::doInitialPlacement(std::vector<MachineInstr*> &CPEMIs) { + // Create the basic block to hold the CPE's. + MachineBasicBlock *BB = MF->CreateMachineBasicBlock(); + MF->push_back(BB); + + + // MachineConstantPool measures alignment in bytes. We measure in log2(bytes). + unsigned MaxAlign = Log2_32(MCP->getConstantPoolAlignment()); + + // Mark the basic block as required by the const-pool. + // If AlignConstantIslands isn't set, use 4-byte alignment for everything. + BB->setAlignment(AlignConstantIslands ? MaxAlign : 2); + + // The function needs to be as aligned as the basic blocks. The linker may + // move functions around based on their alignment. + MF->ensureAlignment(BB->getAlignment()); + + // Order the entries in BB by descending alignment. That ensures correct + // alignment of all entries as long as BB is sufficiently aligned. Keep + // track of the insertion point for each alignment. We are going to bucket + // sort the entries as they are created. + SmallVector<MachineBasicBlock::iterator, 8> InsPoint(MaxAlign + 1, BB->end()); + + // Add all of the constants from the constant pool to the end block, use an + // identity mapping of CPI's to CPE's. + const std::vector<MachineConstantPoolEntry> &CPs = MCP->getConstants(); + + const DataLayout &TD = *MF->getTarget().getDataLayout(); + for (unsigned i = 0, e = CPs.size(); i != e; ++i) { + unsigned Size = TD.getTypeAllocSize(CPs[i].getType()); + assert(Size >= 4 && "Too small constant pool entry"); + unsigned Align = CPs[i].getAlignment(); + assert(isPowerOf2_32(Align) && "Invalid alignment"); + // Verify that all constant pool entries are a multiple of their alignment. + // If not, we would have to pad them out so that instructions stay aligned. + assert((Size % Align) == 0 && "CP Entry not multiple of 4 bytes!"); + + // Insert CONSTPOOL_ENTRY before entries with a smaller alignment. + unsigned LogAlign = Log2_32(Align); + MachineBasicBlock::iterator InsAt = InsPoint[LogAlign]; + + MachineInstr *CPEMI = + BuildMI(*BB, InsAt, DebugLoc(), TII->get(Mips::CONSTPOOL_ENTRY)) + .addImm(i).addConstantPoolIndex(i).addImm(Size); + + CPEMIs.push_back(CPEMI); + + // Ensure that future entries with higher alignment get inserted before + // CPEMI. This is bucket sort with iterators. + for (unsigned a = LogAlign + 1; a <= MaxAlign; ++a) + if (InsPoint[a] == InsAt) + InsPoint[a] = CPEMI; + // Add a new CPEntry, but no corresponding CPUser yet. + std::vector<CPEntry> CPEs; + CPEs.push_back(CPEntry(CPEMI, i)); + CPEntries.push_back(CPEs); + ++NumCPEs; + DEBUG(dbgs() << "Moved CPI#" << i << " to end of function, size = " + << Size << ", align = " << Align <<'\n'); + } + DEBUG(BB->dump()); +} + +/// BBHasFallthrough - Return true if the specified basic block can fallthrough +/// into the block immediately after it. +static bool BBHasFallthrough(MachineBasicBlock *MBB) { + // Get the next machine basic block in the function. + MachineFunction::iterator MBBI = MBB; + // Can't fall off end of function. + if (llvm::next(MBBI) == MBB->getParent()->end()) + return false; + + MachineBasicBlock *NextBB = llvm::next(MBBI); + for (MachineBasicBlock::succ_iterator I = MBB->succ_begin(), + E = MBB->succ_end(); I != E; ++I) + if (*I == NextBB) + return true; + + return false; +} + +/// findConstPoolEntry - Given the constpool index and CONSTPOOL_ENTRY MI, +/// look up the corresponding CPEntry. +MipsConstantIslands::CPEntry +*MipsConstantIslands::findConstPoolEntry(unsigned CPI, + const MachineInstr *CPEMI) { + std::vector<CPEntry> &CPEs = CPEntries[CPI]; + // Number of entries per constpool index should be small, just do a + // linear search. + for (unsigned i = 0, e = CPEs.size(); i != e; ++i) { + if (CPEs[i].CPEMI == CPEMI) + return &CPEs[i]; + } + return NULL; +} + +/// getCPELogAlign - Returns the required alignment of the constant pool entry +/// represented by CPEMI. Alignment is measured in log2(bytes) units. +unsigned MipsConstantIslands::getCPELogAlign(const MachineInstr *CPEMI) { + assert(CPEMI && CPEMI->getOpcode() == Mips::CONSTPOOL_ENTRY); + + // Everything is 4-byte aligned unless AlignConstantIslands is set. + if (!AlignConstantIslands) + return 2; + + unsigned CPI = CPEMI->getOperand(1).getIndex(); + assert(CPI < MCP->getConstants().size() && "Invalid constant pool index."); + unsigned Align = MCP->getConstants()[CPI].getAlignment(); + assert(isPowerOf2_32(Align) && "Invalid CPE alignment"); + return Log2_32(Align); +} + +/// initializeFunctionInfo - Do the initial scan of the function, building up +/// information about the sizes of each block, the location of all the water, +/// and finding all of the constant pool users. +void MipsConstantIslands:: +initializeFunctionInfo(const std::vector<MachineInstr*> &CPEMIs) { + BBInfo.clear(); + BBInfo.resize(MF->getNumBlockIDs()); + + // First thing, compute the size of all basic blocks, and see if the function + // has any inline assembly in it. If so, we have to be conservative about + // alignment assumptions, as we don't know for sure the size of any + // instructions in the inline assembly. + for (MachineFunction::iterator I = MF->begin(), E = MF->end(); I != E; ++I) + computeBlockSize(I); + + + // Compute block offsets. + adjustBBOffsetsAfter(MF->begin()); + + // Now go back through the instructions and build up our data structures. + for (MachineFunction::iterator MBBI = MF->begin(), E = MF->end(); + MBBI != E; ++MBBI) { + MachineBasicBlock &MBB = *MBBI; + + // If this block doesn't fall through into the next MBB, then this is + // 'water' that a constant pool island could be placed. + if (!BBHasFallthrough(&MBB)) + WaterList.push_back(&MBB); + for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); + I != E; ++I) { + if (I->isDebugValue()) + continue; + + int Opc = I->getOpcode(); + if (I->isBranch()) { + bool isCond = false; + unsigned Bits = 0; + unsigned Scale = 1; + int UOpc = Opc; + switch (Opc) { + default: + continue; // Ignore other branches for now + case Mips::Bimm16: + Bits = 11; + Scale = 2; + isCond = false; + break; + case Mips::BimmX16: + Bits = 16; + Scale = 2; + isCond = false; + } + // Record this immediate branch. + unsigned MaxOffs = ((1 << (Bits-1))-1) * Scale; + ImmBranches.push_back(ImmBranch(I, MaxOffs, isCond, UOpc)); + } + + if (Opc == Mips::CONSTPOOL_ENTRY) + continue; + + + // Scan the instructions for constant pool operands. + for (unsigned op = 0, e = I->getNumOperands(); op != e; ++op) + if (I->getOperand(op).isCPI()) { + + // We found one. The addressing mode tells us the max displacement + // from the PC that this instruction permits. + + // Basic size info comes from the TSFlags field. + unsigned Bits = 0; + unsigned Scale = 1; + bool NegOk = false; + unsigned LongFormBits = 0; + unsigned LongFormScale = 0; + unsigned LongFormOpcode = 0; + switch (Opc) { + default: + llvm_unreachable("Unknown addressing mode for CP reference!"); + case Mips::LwRxPcTcp16: + Bits = 8; + Scale = 4; + LongFormOpcode = Mips::LwRxPcTcpX16; + LongFormBits = 16; + LongFormScale = 1; + break; + case Mips::LwRxPcTcpX16: + Bits = 16; + Scale = 1; + NegOk = true; + break; + } + // Remember that this is a user of a CP entry. + unsigned CPI = I->getOperand(op).getIndex(); + MachineInstr *CPEMI = CPEMIs[CPI]; + unsigned MaxOffs = ((1 << Bits)-1) * Scale; + unsigned LongFormMaxOffs = ((1 << LongFormBits)-1) * LongFormScale; + CPUsers.push_back(CPUser(I, CPEMI, MaxOffs, NegOk, + LongFormMaxOffs, LongFormOpcode)); + + // Increment corresponding CPEntry reference count. + CPEntry *CPE = findConstPoolEntry(CPI, CPEMI); + assert(CPE && "Cannot find a corresponding CPEntry!"); + CPE->RefCount++; + + // Instructions can only use one CP entry, don't bother scanning the + // rest of the operands. + break; + + } + + } + } + +} + +/// computeBlockSize - Compute the size and some alignment information for MBB. +/// This function updates BBInfo directly. +void MipsConstantIslands::computeBlockSize(MachineBasicBlock *MBB) { + BasicBlockInfo &BBI = BBInfo[MBB->getNumber()]; + BBI.Size = 0; + + for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; + ++I) + BBI.Size += TII->GetInstSizeInBytes(I); + +} + +/// getOffsetOf - Return the current offset of the specified machine instruction +/// from the start of the function. This offset changes as stuff is moved +/// around inside the function. +unsigned MipsConstantIslands::getOffsetOf(MachineInstr *MI) const { + MachineBasicBlock *MBB = MI->getParent(); + + // The offset is composed of two things: the sum of the sizes of all MBB's + // before this instruction's block, and the offset from the start of the block + // it is in. + unsigned Offset = BBInfo[MBB->getNumber()].Offset; + + // Sum instructions before MI in MBB. + for (MachineBasicBlock::iterator I = MBB->begin(); &*I != MI; ++I) { + assert(I != MBB->end() && "Didn't find MI in its own basic block?"); + Offset += TII->GetInstSizeInBytes(I); + } + return Offset; +} + +/// CompareMBBNumbers - Little predicate function to sort the WaterList by MBB +/// ID. +static bool CompareMBBNumbers(const MachineBasicBlock *LHS, + const MachineBasicBlock *RHS) { + return LHS->getNumber() < RHS->getNumber(); +} + +/// updateForInsertedWaterBlock - When a block is newly inserted into the +/// machine function, it upsets all of the block numbers. Renumber the blocks +/// and update the arrays that parallel this numbering. +void MipsConstantIslands::updateForInsertedWaterBlock + (MachineBasicBlock *NewBB) { + // Renumber the MBB's to keep them consecutive. + NewBB->getParent()->RenumberBlocks(NewBB); + + // Insert an entry into BBInfo to align it properly with the (newly + // renumbered) block numbers. + BBInfo.insert(BBInfo.begin() + NewBB->getNumber(), BasicBlockInfo()); + + // Next, update WaterList. Specifically, we need to add NewMBB as having + // available water after it. + water_iterator IP = + std::lower_bound(WaterList.begin(), WaterList.end(), NewBB, + CompareMBBNumbers); + WaterList.insert(IP, NewBB); +} + +unsigned MipsConstantIslands::getUserOffset(CPUser &U) const { + return getOffsetOf(U.MI); +} + +/// Split the basic block containing MI into two blocks, which are joined by +/// an unconditional branch. Update data structures and renumber blocks to +/// account for this change and returns the newly created block. +MachineBasicBlock *MipsConstantIslands::splitBlockBeforeInstr + (MachineInstr *MI) { + MachineBasicBlock *OrigBB = MI->getParent(); + + // Create a new MBB for the code after the OrigBB. + MachineBasicBlock *NewBB = + MF->CreateMachineBasicBlock(OrigBB->getBasicBlock()); + MachineFunction::iterator MBBI = OrigBB; ++MBBI; + MF->insert(MBBI, NewBB); + + // Splice the instructions starting with MI over to NewBB. + NewBB->splice(NewBB->end(), OrigBB, MI, OrigBB->end()); + + // Add an unconditional branch from OrigBB to NewBB. + // Note the new unconditional branch is not being recorded. + // There doesn't seem to be meaningful DebugInfo available; this doesn't + // correspond to anything in the source. + BuildMI(OrigBB, DebugLoc(), TII->get(Mips::Bimm16)).addMBB(NewBB); + ++NumSplit; + + // Update the CFG. All succs of OrigBB are now succs of NewBB. + NewBB->transferSuccessors(OrigBB); + + // OrigBB branches to NewBB. + OrigBB->addSuccessor(NewBB); + + // Update internal data structures to account for the newly inserted MBB. + // This is almost the same as updateForInsertedWaterBlock, except that + // the Water goes after OrigBB, not NewBB. + MF->RenumberBlocks(NewBB); + + // Insert an entry into BBInfo to align it properly with the (newly + // renumbered) block numbers. + BBInfo.insert(BBInfo.begin() + NewBB->getNumber(), BasicBlockInfo()); + + // Next, update WaterList. Specifically, we need to add OrigMBB as having + // available water after it (but not if it's already there, which happens + // when splitting before a conditional branch that is followed by an + // unconditional branch - in that case we want to insert NewBB). + water_iterator IP = + std::lower_bound(WaterList.begin(), WaterList.end(), OrigBB, + CompareMBBNumbers); + MachineBasicBlock* WaterBB = *IP; + if (WaterBB == OrigBB) + WaterList.insert(llvm::next(IP), NewBB); + else + WaterList.insert(IP, OrigBB); + NewWaterList.insert(OrigBB); + + // Figure out how large the OrigBB is. As the first half of the original + // block, it cannot contain a tablejump. The size includes + // the new jump we added. (It should be possible to do this without + // recounting everything, but it's very confusing, and this is rarely + // executed.) + computeBlockSize(OrigBB); + + // Figure out how large the NewMBB is. As the second half of the original + // block, it may contain a tablejump. + computeBlockSize(NewBB); + + // All BBOffsets following these blocks must be modified. + adjustBBOffsetsAfter(OrigBB); + + return NewBB; +} + + + +/// isOffsetInRange - Checks whether UserOffset (the location of a constant pool +/// reference) is within MaxDisp of TrialOffset (a proposed location of a +/// constant pool entry). +bool MipsConstantIslands::isOffsetInRange(unsigned UserOffset, + unsigned TrialOffset, unsigned MaxDisp, + bool NegativeOK) { + if (UserOffset <= TrialOffset) { + // User before the Trial. + if (TrialOffset - UserOffset <= MaxDisp) + return true; + } else if (NegativeOK) { + if (UserOffset - TrialOffset <= MaxDisp) + return true; + } + return false; +} + +/// isWaterInRange - Returns true if a CPE placed after the specified +/// Water (a basic block) will be in range for the specific MI. +/// +/// Compute how much the function will grow by inserting a CPE after Water. +bool MipsConstantIslands::isWaterInRange(unsigned UserOffset, + MachineBasicBlock* Water, CPUser &U, + unsigned &Growth) { + unsigned CPELogAlign = getCPELogAlign(U.CPEMI); + unsigned CPEOffset = BBInfo[Water->getNumber()].postOffset(CPELogAlign); + unsigned NextBlockOffset, NextBlockAlignment; + MachineFunction::const_iterator NextBlock = Water; + if (++NextBlock == MF->end()) { + NextBlockOffset = BBInfo[Water->getNumber()].postOffset(); + NextBlockAlignment = 0; + } else { + NextBlockOffset = BBInfo[NextBlock->getNumber()].Offset; + NextBlockAlignment = NextBlock->getAlignment(); + } + unsigned Size = U.CPEMI->getOperand(2).getImm(); + unsigned CPEEnd = CPEOffset + Size; + + // The CPE may be able to hide in the alignment padding before the next + // block. It may also cause more padding to be required if it is more aligned + // that the next block. + if (CPEEnd > NextBlockOffset) { + Growth = CPEEnd - NextBlockOffset; + // Compute the padding that would go at the end of the CPE to align the next + // block. + Growth += OffsetToAlignment(CPEEnd, 1u << NextBlockAlignment); + + // If the CPE is to be inserted before the instruction, that will raise + // the offset of the instruction. Also account for unknown alignment padding + // in blocks between CPE and the user. + if (CPEOffset < UserOffset) + UserOffset += Growth; + } else + // CPE fits in existing padding. + Growth = 0; + + return isOffsetInRange(UserOffset, CPEOffset, U); +} + +/// isCPEntryInRange - Returns true if the distance between specific MI and +/// specific ConstPool entry instruction can fit in MI's displacement field. +bool MipsConstantIslands::isCPEntryInRange + (MachineInstr *MI, unsigned UserOffset, + MachineInstr *CPEMI, unsigned MaxDisp, + bool NegOk, bool DoDump) { + unsigned CPEOffset = getOffsetOf(CPEMI); + + if (DoDump) { + DEBUG({ + unsigned Block = MI->getParent()->getNumber(); + const BasicBlockInfo &BBI = BBInfo[Block]; + dbgs() << "User of CPE#" << CPEMI->getOperand(0).getImm() + << " max delta=" << MaxDisp + << format(" insn address=%#x", UserOffset) + << " in BB#" << Block << ": " + << format("%#x-%x\t", BBI.Offset, BBI.postOffset()) << *MI + << format("CPE address=%#x offset=%+d: ", CPEOffset, + int(CPEOffset-UserOffset)); + }); + } + + return isOffsetInRange(UserOffset, CPEOffset, MaxDisp, NegOk); +} + +#ifndef NDEBUG +/// BBIsJumpedOver - Return true of the specified basic block's only predecessor +/// unconditionally branches to its only successor. +static bool BBIsJumpedOver(MachineBasicBlock *MBB) { + if (MBB->pred_size() != 1 || MBB->succ_size() != 1) + return false; + MachineBasicBlock *Succ = *MBB->succ_begin(); + MachineBasicBlock *Pred = *MBB->pred_begin(); + MachineInstr *PredMI = &Pred->back(); + if (PredMI->getOpcode() == Mips::Bimm16) + return PredMI->getOperand(0).getMBB() == Succ; + return false; +} +#endif + +void MipsConstantIslands::adjustBBOffsetsAfter(MachineBasicBlock *BB) { + unsigned BBNum = BB->getNumber(); + for(unsigned i = BBNum + 1, e = MF->getNumBlockIDs(); i < e; ++i) { + // Get the offset and known bits at the end of the layout predecessor. + // Include the alignment of the current block. + unsigned Offset = BBInfo[i - 1].Offset + BBInfo[i - 1].Size; + BBInfo[i].Offset = Offset; + } +} + +/// decrementCPEReferenceCount - find the constant pool entry with index CPI +/// and instruction CPEMI, and decrement its refcount. If the refcount +/// becomes 0 remove the entry and instruction. Returns true if we removed +/// the entry, false if we didn't. + +bool MipsConstantIslands::decrementCPEReferenceCount(unsigned CPI, + MachineInstr *CPEMI) { + // Find the old entry. Eliminate it if it is no longer used. + CPEntry *CPE = findConstPoolEntry(CPI, CPEMI); + assert(CPE && "Unexpected!"); + if (--CPE->RefCount == 0) { + removeDeadCPEMI(CPEMI); + CPE->CPEMI = NULL; + --NumCPEs; + return true; + } + return false; +} + +/// LookForCPEntryInRange - see if the currently referenced CPE is in range; +/// if not, see if an in-range clone of the CPE is in range, and if so, +/// change the data structures so the user references the clone. Returns: +/// 0 = no existing entry found +/// 1 = entry found, and there were no code insertions or deletions +/// 2 = entry found, and there were code insertions or deletions +int MipsConstantIslands::findInRangeCPEntry(CPUser& U, unsigned UserOffset) +{ + MachineInstr *UserMI = U.MI; + MachineInstr *CPEMI = U.CPEMI; + + // Check to see if the CPE is already in-range. + if (isCPEntryInRange(UserMI, UserOffset, CPEMI, U.getMaxDisp(), U.NegOk, + true)) { + DEBUG(dbgs() << "In range\n"); + return 1; + } + + // No. Look for previously created clones of the CPE that are in range. + unsigned CPI = CPEMI->getOperand(1).getIndex(); + std::vector<CPEntry> &CPEs = CPEntries[CPI]; + for (unsigned i = 0, e = CPEs.size(); i != e; ++i) { + // We already tried this one + if (CPEs[i].CPEMI == CPEMI) + continue; + // Removing CPEs can leave empty entries, skip + if (CPEs[i].CPEMI == NULL) + continue; + if (isCPEntryInRange(UserMI, UserOffset, CPEs[i].CPEMI, U.getMaxDisp(), + U.NegOk)) { + DEBUG(dbgs() << "Replacing CPE#" << CPI << " with CPE#" + << CPEs[i].CPI << "\n"); + // Point the CPUser node to the replacement + U.CPEMI = CPEs[i].CPEMI; + // Change the CPI in the instruction operand to refer to the clone. + for (unsigned j = 0, e = UserMI->getNumOperands(); j != e; ++j) + if (UserMI->getOperand(j).isCPI()) { + UserMI->getOperand(j).setIndex(CPEs[i].CPI); + break; + } + // Adjust the refcount of the clone... + CPEs[i].RefCount++; + // ...and the original. If we didn't remove the old entry, none of the + // addresses changed, so we don't need another pass. + return decrementCPEReferenceCount(CPI, CPEMI) ? 2 : 1; + } + } + return 0; +} + +/// LookForCPEntryInRange - see if the currently referenced CPE is in range; +/// This version checks if the longer form of the instruction can be used to +/// to satisfy things. +/// if not, see if an in-range clone of the CPE is in range, and if so, +/// change the data structures so the user references the clone. Returns: +/// 0 = no existing entry found +/// 1 = entry found, and there were no code insertions or deletions +/// 2 = entry found, and there were code insertions or deletions +int MipsConstantIslands::findLongFormInRangeCPEntry + (CPUser& U, unsigned UserOffset) +{ + MachineInstr *UserMI = U.MI; + MachineInstr *CPEMI = U.CPEMI; + + // Check to see if the CPE is already in-range. + if (isCPEntryInRange(UserMI, UserOffset, CPEMI, + U.getLongFormMaxDisp(), U.NegOk, + true)) { + DEBUG(dbgs() << "In range\n"); + UserMI->setDesc(TII->get(U.getLongFormOpcode())); + U.setMaxDisp(U.getLongFormMaxDisp()); + return 2; // instruction is longer length now + } + + // No. Look for previously created clones of the CPE that are in range. + unsigned CPI = CPEMI->getOperand(1).getIndex(); + std::vector<CPEntry> &CPEs = CPEntries[CPI]; + for (unsigned i = 0, e = CPEs.size(); i != e; ++i) { + // We already tried this one + if (CPEs[i].CPEMI == CPEMI) + continue; + // Removing CPEs can leave empty entries, skip + if (CPEs[i].CPEMI == NULL) + continue; + if (isCPEntryInRange(UserMI, UserOffset, CPEs[i].CPEMI, + U.getLongFormMaxDisp(), U.NegOk)) { + DEBUG(dbgs() << "Replacing CPE#" << CPI << " with CPE#" + << CPEs[i].CPI << "\n"); + // Point the CPUser node to the replacement + U.CPEMI = CPEs[i].CPEMI; + // Change the CPI in the instruction operand to refer to the clone. + for (unsigned j = 0, e = UserMI->getNumOperands(); j != e; ++j) + if (UserMI->getOperand(j).isCPI()) { + UserMI->getOperand(j).setIndex(CPEs[i].CPI); + break; + } + // Adjust the refcount of the clone... + CPEs[i].RefCount++; + // ...and the original. If we didn't remove the old entry, none of the + // addresses changed, so we don't need another pass. + return decrementCPEReferenceCount(CPI, CPEMI) ? 2 : 1; + } + } + return 0; +} + +/// getUnconditionalBrDisp - Returns the maximum displacement that can fit in +/// the specific unconditional branch instruction. +static inline unsigned getUnconditionalBrDisp(int Opc) { + switch (Opc) { + case Mips::Bimm16: + return ((1<<10)-1)*2; + case Mips::BimmX16: + return ((1<<16)-1)*2; + default: + break; + } + return ((1<<16)-1)*2; +} + +/// findAvailableWater - Look for an existing entry in the WaterList in which +/// we can place the CPE referenced from U so it's within range of U's MI. +/// Returns true if found, false if not. If it returns true, WaterIter +/// is set to the WaterList entry. +/// To ensure that this pass +/// terminates, the CPE location for a particular CPUser is only allowed to +/// move to a lower address, so search backward from the end of the list and +/// prefer the first water that is in range. +bool MipsConstantIslands::findAvailableWater(CPUser &U, unsigned UserOffset, + water_iterator &WaterIter) { + if (WaterList.empty()) + return false; + + unsigned BestGrowth = ~0u; + for (water_iterator IP = prior(WaterList.end()), B = WaterList.begin();; + --IP) { + MachineBasicBlock* WaterBB = *IP; + // Check if water is in range and is either at a lower address than the + // current "high water mark" or a new water block that was created since + // the previous iteration by inserting an unconditional branch. In the + // latter case, we want to allow resetting the high water mark back to + // this new water since we haven't seen it before. Inserting branches + // should be relatively uncommon and when it does happen, we want to be + // sure to take advantage of it for all the CPEs near that block, so that + // we don't insert more branches than necessary. + unsigned Growth; + if (isWaterInRange(UserOffset, WaterBB, U, Growth) && + (WaterBB->getNumber() < U.HighWaterMark->getNumber() || + NewWaterList.count(WaterBB)) && Growth < BestGrowth) { + // This is the least amount of required padding seen so far. + BestGrowth = Growth; + WaterIter = IP; + DEBUG(dbgs() << "Found water after BB#" << WaterBB->getNumber() + << " Growth=" << Growth << '\n'); + + // Keep looking unless it is perfect. + if (BestGrowth == 0) + return true; + } + if (IP == B) + break; + } + return BestGrowth != ~0u; +} + +/// createNewWater - No existing WaterList entry will work for +/// CPUsers[CPUserIndex], so create a place to put the CPE. The end of the +/// block is used if in range, and the conditional branch munged so control +/// flow is correct. Otherwise the block is split to create a hole with an +/// unconditional branch around it. In either case NewMBB is set to a +/// block following which the new island can be inserted (the WaterList +/// is not adjusted). +void MipsConstantIslands::createNewWater(unsigned CPUserIndex, + unsigned UserOffset, + MachineBasicBlock *&NewMBB) { + CPUser &U = CPUsers[CPUserIndex]; + MachineInstr *UserMI = U.MI; + MachineInstr *CPEMI = U.CPEMI; + unsigned CPELogAlign = getCPELogAlign(CPEMI); + MachineBasicBlock *UserMBB = UserMI->getParent(); + const BasicBlockInfo &UserBBI = BBInfo[UserMBB->getNumber()]; + + // If the block does not end in an unconditional branch already, and if the + // end of the block is within range, make new water there. + if (BBHasFallthrough(UserMBB)) { + // Size of branch to insert. + unsigned Delta = 2; + // Compute the offset where the CPE will begin. + unsigned CPEOffset = UserBBI.postOffset(CPELogAlign) + Delta; + + if (isOffsetInRange(UserOffset, CPEOffset, U)) { + DEBUG(dbgs() << "Split at end of BB#" << UserMBB->getNumber() + << format(", expected CPE offset %#x\n", CPEOffset)); + NewMBB = llvm::next(MachineFunction::iterator(UserMBB)); + // Add an unconditional branch from UserMBB to fallthrough block. Record + // it for branch lengthening; this new branch will not get out of range, + // but if the preceding conditional branch is out of range, the targets + // will be exchanged, and the altered branch may be out of range, so the + // machinery has to know about it. + int UncondBr = Mips::Bimm16; + BuildMI(UserMBB, DebugLoc(), TII->get(UncondBr)).addMBB(NewMBB); + unsigned MaxDisp = getUnconditionalBrDisp(UncondBr); + ImmBranches.push_back(ImmBranch(&UserMBB->back(), + MaxDisp, false, UncondBr)); + BBInfo[UserMBB->getNumber()].Size += Delta; + adjustBBOffsetsAfter(UserMBB); + return; + } + } + + // What a big block. Find a place within the block to split it. + + // Try to split the block so it's fully aligned. Compute the latest split + // point where we can add a 4-byte branch instruction, and then align to + // LogAlign which is the largest possible alignment in the function. + unsigned LogAlign = MF->getAlignment(); + assert(LogAlign >= CPELogAlign && "Over-aligned constant pool entry"); + unsigned BaseInsertOffset = UserOffset + U.getMaxDisp(); + DEBUG(dbgs() << format("Split in middle of big block before %#x", + BaseInsertOffset)); + + // The 4 in the following is for the unconditional branch we'll be inserting + // Alignment of the island is handled + // inside isOffsetInRange. + BaseInsertOffset -= 4; + + DEBUG(dbgs() << format(", adjusted to %#x", BaseInsertOffset) + << " la=" << LogAlign << '\n'); + + // This could point off the end of the block if we've already got constant + // pool entries following this block; only the last one is in the water list. + // Back past any possible branches (allow for a conditional and a maximally + // long unconditional). + if (BaseInsertOffset + 8 >= UserBBI.postOffset()) { + BaseInsertOffset = UserBBI.postOffset() - 8; + DEBUG(dbgs() << format("Move inside block: %#x\n", BaseInsertOffset)); + } + unsigned EndInsertOffset = BaseInsertOffset + 4 + + CPEMI->getOperand(2).getImm(); + MachineBasicBlock::iterator MI = UserMI; + ++MI; + unsigned CPUIndex = CPUserIndex+1; + unsigned NumCPUsers = CPUsers.size(); + //MachineInstr *LastIT = 0; + for (unsigned Offset = UserOffset+TII->GetInstSizeInBytes(UserMI); + Offset < BaseInsertOffset; + Offset += TII->GetInstSizeInBytes(MI), + MI = llvm::next(MI)) { + assert(MI != UserMBB->end() && "Fell off end of block"); + if (CPUIndex < NumCPUsers && CPUsers[CPUIndex].MI == MI) { + CPUser &U = CPUsers[CPUIndex]; + if (!isOffsetInRange(Offset, EndInsertOffset, U)) { + // Shift intertion point by one unit of alignment so it is within reach. + BaseInsertOffset -= 1u << LogAlign; + EndInsertOffset -= 1u << LogAlign; + } + // This is overly conservative, as we don't account for CPEMIs being + // reused within the block, but it doesn't matter much. Also assume CPEs + // are added in order with alignment padding. We may eventually be able + // to pack the aligned CPEs better. + EndInsertOffset += U.CPEMI->getOperand(2).getImm(); + CPUIndex++; + } + } + + --MI; + NewMBB = splitBlockBeforeInstr(MI); +} + +/// handleConstantPoolUser - Analyze the specified user, checking to see if it +/// is out-of-range. If so, pick up the constant pool value and move it some +/// place in-range. Return true if we changed any addresses (thus must run +/// another pass of branch lengthening), false otherwise. +bool MipsConstantIslands::handleConstantPoolUser(unsigned CPUserIndex) { + CPUser &U = CPUsers[CPUserIndex]; + MachineInstr *UserMI = U.MI; + MachineInstr *CPEMI = U.CPEMI; + unsigned CPI = CPEMI->getOperand(1).getIndex(); + unsigned Size = CPEMI->getOperand(2).getImm(); + // Compute this only once, it's expensive. + unsigned UserOffset = getUserOffset(U); + + // See if the current entry is within range, or there is a clone of it + // in range. + int result = findInRangeCPEntry(U, UserOffset); + if (result==1) return false; + else if (result==2) return true; + + + // Look for water where we can place this CPE. + MachineBasicBlock *NewIsland = MF->CreateMachineBasicBlock(); + MachineBasicBlock *NewMBB; + water_iterator IP; + if (findAvailableWater(U, UserOffset, IP)) { + DEBUG(dbgs() << "Found water in range\n"); + MachineBasicBlock *WaterBB = *IP; + + // If the original WaterList entry was "new water" on this iteration, + // propagate that to the new island. This is just keeping NewWaterList + // updated to match the WaterList, which will be updated below. + if (NewWaterList.erase(WaterBB)) + NewWaterList.insert(NewIsland); + + // The new CPE goes before the following block (NewMBB). + NewMBB = llvm::next(MachineFunction::iterator(WaterBB)); + + } else { + // No water found. + // we first see if a longer form of the instrucion could have reached + // the constant. in that case we won't bother to split + if (!NoLoadRelaxation) { + result = findLongFormInRangeCPEntry(U, UserOffset); + if (result != 0) return true; + } + DEBUG(dbgs() << "No water found\n"); + createNewWater(CPUserIndex, UserOffset, NewMBB); + + // splitBlockBeforeInstr adds to WaterList, which is important when it is + // called while handling branches so that the water will be seen on the + // next iteration for constant pools, but in this context, we don't want + // it. Check for this so it will be removed from the WaterList. + // Also remove any entry from NewWaterList. + MachineBasicBlock *WaterBB = prior(MachineFunction::iterator(NewMBB)); + IP = std::find(WaterList.begin(), WaterList.end(), WaterBB); + if (IP != WaterList.end()) + NewWaterList.erase(WaterBB); + + // We are adding new water. Update NewWaterList. + NewWaterList.insert(NewIsland); + } + + // Remove the original WaterList entry; we want subsequent insertions in + // this vicinity to go after the one we're about to insert. This + // considerably reduces the number of times we have to move the same CPE + // more than once and is also important to ensure the algorithm terminates. + if (IP != WaterList.end()) + WaterList.erase(IP); + + // Okay, we know we can put an island before NewMBB now, do it! + MF->insert(NewMBB, NewIsland); + + // Update internal data structures to account for the newly inserted MBB. + updateForInsertedWaterBlock(NewIsland); + + // Decrement the old entry, and remove it if refcount becomes 0. + decrementCPEReferenceCount(CPI, CPEMI); + + // Now that we have an island to add the CPE to, clone the original CPE and + // add it to the island. + U.HighWaterMark = NewIsland; + U.CPEMI = BuildMI(NewIsland, DebugLoc(), TII->get(Mips::CONSTPOOL_ENTRY)) + .addImm(ID).addConstantPoolIndex(CPI).addImm(Size); + CPEntries[CPI].push_back(CPEntry(U.CPEMI, ID, 1)); + ++NumCPEs; + + // Mark the basic block as aligned as required by the const-pool entry. + NewIsland->setAlignment(getCPELogAlign(U.CPEMI)); + + // Increase the size of the island block to account for the new entry. + BBInfo[NewIsland->getNumber()].Size += Size; + adjustBBOffsetsAfter(llvm::prior(MachineFunction::iterator(NewIsland))); + + // No existing clone of this CPE is within range. + // We will be generating a new clone. Get a UID for it. + unsigned ID = createPICLabelUId(); + + // Finally, change the CPI in the instruction operand to be ID. + for (unsigned i = 0, e = UserMI->getNumOperands(); i != e; ++i) + if (UserMI->getOperand(i).isCPI()) { + UserMI->getOperand(i).setIndex(ID); + break; + } + + DEBUG(dbgs() << " Moved CPE to #" << ID << " CPI=" << CPI + << format(" offset=%#x\n", BBInfo[NewIsland->getNumber()].Offset)); + + return true; +} + +/// removeDeadCPEMI - Remove a dead constant pool entry instruction. Update +/// sizes and offsets of impacted basic blocks. +void MipsConstantIslands::removeDeadCPEMI(MachineInstr *CPEMI) { + MachineBasicBlock *CPEBB = CPEMI->getParent(); + unsigned Size = CPEMI->getOperand(2).getImm(); + CPEMI->eraseFromParent(); + BBInfo[CPEBB->getNumber()].Size -= Size; + // All succeeding offsets have the current size value added in, fix this. + if (CPEBB->empty()) { + BBInfo[CPEBB->getNumber()].Size = 0; + + // This block no longer needs to be aligned. + CPEBB->setAlignment(0); + } else + // Entries are sorted by descending alignment, so realign from the front. + CPEBB->setAlignment(getCPELogAlign(CPEBB->begin())); + + adjustBBOffsetsAfter(CPEBB); + // An island has only one predecessor BB and one successor BB. Check if + // this BB's predecessor jumps directly to this BB's successor. This + // shouldn't happen currently. + assert(!BBIsJumpedOver(CPEBB) && "How did this happen?"); + // FIXME: remove the empty blocks after all the work is done? +} + +/// removeUnusedCPEntries - Remove constant pool entries whose refcounts +/// are zero. +bool MipsConstantIslands::removeUnusedCPEntries() { + unsigned MadeChange = false; + for (unsigned i = 0, e = CPEntries.size(); i != e; ++i) { + std::vector<CPEntry> &CPEs = CPEntries[i]; + for (unsigned j = 0, ee = CPEs.size(); j != ee; ++j) { + if (CPEs[j].RefCount == 0 && CPEs[j].CPEMI) { + removeDeadCPEMI(CPEs[j].CPEMI); + CPEs[j].CPEMI = NULL; + MadeChange = true; + } + } + } + return MadeChange; +} + +/// isBBInRange - Returns true if the distance between specific MI and +/// specific BB can fit in MI's displacement field. +bool MipsConstantIslands::isBBInRange + (MachineInstr *MI,MachineBasicBlock *DestBB, unsigned MaxDisp) { + +unsigned PCAdj = 4; + + unsigned BrOffset = getOffsetOf(MI) + PCAdj; + unsigned DestOffset = BBInfo[DestBB->getNumber()].Offset; + + DEBUG(dbgs() << "Branch of destination BB#" << DestBB->getNumber() + << " from BB#" << MI->getParent()->getNumber() + << " max delta=" << MaxDisp + << " from " << getOffsetOf(MI) << " to " << DestOffset + << " offset " << int(DestOffset-BrOffset) << "\t" << *MI); + + if (BrOffset <= DestOffset) { + // Branch before the Dest. + if (DestOffset-BrOffset <= MaxDisp) + return true; + } else { + if (BrOffset-DestOffset <= MaxDisp) + return true; + } + return false; +} + +/// fixupImmediateBr - Fix up an immediate branch whose destination is too far +/// away to fit in its displacement field. +bool MipsConstantIslands::fixupImmediateBr(ImmBranch &Br) { + MachineInstr *MI = Br.MI; + MachineBasicBlock *DestBB = MI->getOperand(0).getMBB(); + + // Check to see if the DestBB is already in-range. + if (isBBInRange(MI, DestBB, Br.MaxDisp)) + return false; + + if (!Br.isCond) + return fixupUnconditionalBr(Br); + return fixupConditionalBr(Br); +} + +/// fixupUnconditionalBr - Fix up an unconditional branch whose destination is +/// too far away to fit in its displacement field. If the LR register has been +/// spilled in the epilogue, then we can use BL to implement a far jump. +/// Otherwise, add an intermediate branch instruction to a branch. +bool +MipsConstantIslands::fixupUnconditionalBr(ImmBranch &Br) { + MachineInstr *MI = Br.MI; + MachineBasicBlock *MBB = MI->getParent(); + // Use BL to implement far jump. + Br.MaxDisp = ((1 << 16)-1) * 2; + MI->setDesc(TII->get(Mips::BimmX16)); + BBInfo[MBB->getNumber()].Size += 2; + adjustBBOffsetsAfter(MBB); + HasFarJump = true; + ++NumUBrFixed; + + DEBUG(dbgs() << " Changed B to long jump " << *MI); + + return true; +} + +/// fixupConditionalBr - Fix up a conditional branch whose destination is too +/// far away to fit in its displacement field. It is converted to an inverse +/// conditional branch + an unconditional branch to the destination. +bool +MipsConstantIslands::fixupConditionalBr(ImmBranch &Br) { + MachineInstr *MI = Br.MI; + MachineBasicBlock *DestBB = MI->getOperand(0).getMBB(); + + // Add an unconditional branch to the destination and invert the branch + // condition to jump over it: + // blt L1 + // => + // bge L2 + // b L1 + // L2: + unsigned CCReg = 0; // FIXME + unsigned CC=0; //FIXME + + // If the branch is at the end of its MBB and that has a fall-through block, + // direct the updated conditional branch to the fall-through block. Otherwise, + // split the MBB before the next instruction. + MachineBasicBlock *MBB = MI->getParent(); + MachineInstr *BMI = &MBB->back(); + bool NeedSplit = (BMI != MI) || !BBHasFallthrough(MBB); + + ++NumCBrFixed; + if (BMI != MI) { + if (llvm::next(MachineBasicBlock::iterator(MI)) == prior(MBB->end()) && + BMI->getOpcode() == Br.UncondBr) { + // Last MI in the BB is an unconditional branch. Can we simply invert the + // condition and swap destinations: + // beq L1 + // b L2 + // => + // bne L2 + // b L1 + MachineBasicBlock *NewDest = BMI->getOperand(0).getMBB(); + if (isBBInRange(MI, NewDest, Br.MaxDisp)) { + DEBUG(dbgs() << " Invert Bcc condition and swap its destination with " + << *BMI); + BMI->getOperand(0).setMBB(DestBB); + MI->getOperand(0).setMBB(NewDest); + return true; + } + } + } + + if (NeedSplit) { + splitBlockBeforeInstr(MI); + // No need for the branch to the next block. We're adding an unconditional + // branch to the destination. + int delta = TII->GetInstSizeInBytes(&MBB->back()); + BBInfo[MBB->getNumber()].Size -= delta; + MBB->back().eraseFromParent(); + // BBInfo[SplitBB].Offset is wrong temporarily, fixed below + } + MachineBasicBlock *NextBB = llvm::next(MachineFunction::iterator(MBB)); + + DEBUG(dbgs() << " Insert B to BB#" << DestBB->getNumber() + << " also invert condition and change dest. to BB#" + << NextBB->getNumber() << "\n"); + + // Insert a new conditional branch and a new unconditional branch. + // Also update the ImmBranch as well as adding a new entry for the new branch. + BuildMI(MBB, DebugLoc(), TII->get(MI->getOpcode())) + .addMBB(NextBB).addImm(CC).addReg(CCReg); + Br.MI = &MBB->back(); + BBInfo[MBB->getNumber()].Size += TII->GetInstSizeInBytes(&MBB->back()); + BuildMI(MBB, DebugLoc(), TII->get(Br.UncondBr)).addMBB(DestBB); + BBInfo[MBB->getNumber()].Size += TII->GetInstSizeInBytes(&MBB->back()); + unsigned MaxDisp = getUnconditionalBrDisp(Br.UncondBr); + ImmBranches.push_back(ImmBranch(&MBB->back(), MaxDisp, false, Br.UncondBr)); + + // Remove the old conditional branch. It may or may not still be in MBB. + BBInfo[MI->getParent()->getNumber()].Size -= TII->GetInstSizeInBytes(MI); + MI->eraseFromParent(); + adjustBBOffsetsAfter(MBB); + return true; +} + + +void MipsConstantIslands::prescanForConstants() { + unsigned J = 0; + (void)J; + PrescannedForConstants = true; + for (MachineFunction::iterator B = + MF->begin(), E = MF->end(); B != E; ++B) { + for (MachineBasicBlock::instr_iterator I = + B->instr_begin(), EB = B->instr_end(); I != EB; ++I) { + switch(I->getDesc().getOpcode()) { + case Mips::LwConstant32: { + DEBUG(dbgs() << "constant island constant " << *I << "\n"); + J = I->getNumOperands(); + DEBUG(dbgs() << "num operands " << J << "\n"); + MachineOperand& Literal = I->getOperand(1); + if (Literal.isImm()) { + int64_t V = Literal.getImm(); + DEBUG(dbgs() << "literal " << V << "\n"); + Type *Int32Ty = + Type::getInt32Ty(MF->getFunction()->getContext()); + const Constant *C = ConstantInt::get(Int32Ty, V); + unsigned index = MCP->getConstantPoolIndex(C, 4); + I->getOperand(2).ChangeToImmediate(index); + DEBUG(dbgs() << "constant island constant " << *I << "\n"); + I->setDesc(TII->get(Mips::LwRxPcTcp16)); + I->RemoveOperand(1); + I->RemoveOperand(1); + I->addOperand(MachineOperand::CreateCPI(index, 0)); + I->addOperand(MachineOperand::CreateImm(4)); + } + break; + } + default: + break; + } + } + } +} + diff --git a/contrib/llvm/lib/Target/Mips/MipsDSPInstrFormats.td b/contrib/llvm/lib/Target/Mips/MipsDSPInstrFormats.td new file mode 100644 index 000000000000..cf09113cd8ad --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsDSPInstrFormats.td @@ -0,0 +1,337 @@ +//===- MipsDSPInstrFormats.td - Mips Instruction Formats ---*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +def HasDSP : Predicate<"Subtarget.hasDSP()">, + AssemblerPredicate<"FeatureDSP">; +def HasDSPR2 : Predicate<"Subtarget.hasDSPR2()">, + AssemblerPredicate<"FeatureDSPR2">; + +// Fields. +class Field6<bits<6> val> { + bits<6> V = val; +} + +def SPECIAL3_OPCODE : Field6<0b011111>; +def REGIMM_OPCODE : Field6<0b000001>; + +class DSPInst : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther> { + let Predicates = [HasDSP]; +} + +class PseudoDSP<dag outs, dag ins, list<dag> pattern, + InstrItinClass itin = IIPseudo>: + MipsPseudo<outs, ins, pattern, itin> { + let Predicates = [HasDSP]; +} + +// ADDU.QB sub-class format. +class ADDU_QB_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b010000; +} + +class RADDU_W_QB_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<5> rs; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = 0; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b010000; +} + +// CMPU.EQ.QB sub-class format. +class CMP_EQ_QB_R2_FMT<bits<5> op> : DSPInst { + bits<5> rs; + bits<5> rt; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = 0; + let Inst{10-6} = op; + let Inst{5-0} = 0b010001; +} + +class CMP_EQ_QB_R3_FMT<bits<5> op> : DSPInst { + bits<5> rs; + bits<5> rt; + bits<5> rd; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b010001; +} + +class PRECR_SRA_PH_W_FMT<bits<5> op> : DSPInst { + bits<5> rs; + bits<5> rt; + bits<5> sa; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = sa; + let Inst{10-6} = op; + let Inst{5-0} = 0b010001; +} + +// ABSQ_S.PH sub-class format. +class ABSQ_S_PH_R2_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<5> rt; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = 0; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b010010; +} + + +class REPL_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<10> imm; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-16} = imm; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b010010; +} + +// SHLL.QB sub-class format. +class SHLL_QB_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<5> rt; + bits<5> rs_sa; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs_sa; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b010011; +} + +// LX sub-class format. +class LX_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<5> base; + bits<5> index; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = base; + let Inst{20-16} = index; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b001010; +} + +// ADDUH.QB sub-class format. +class ADDUH_QB_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b011000; +} + +// APPEND sub-class format. +class APPEND_FMT<bits<5> op> : DSPInst { + bits<5> rt; + bits<5> rs; + bits<5> sa; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = sa; + let Inst{10-6} = op; + let Inst{5-0} = 0b110001; +} + +// DPA.W.PH sub-class format. +class DPA_W_PH_FMT<bits<5> op> : DSPInst { + bits<2> ac; + bits<5> rs; + bits<5> rt; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-13} = 0; + let Inst{12-11} = ac; + let Inst{10-6} = op; + let Inst{5-0} = 0b110000; +} + +// MULT sub-class format. +class MULT_FMT<bits<6> opcode, bits<6> funct> : DSPInst { + bits<2> ac; + bits<5> rs; + bits<5> rt; + + let Opcode = opcode; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-13} = 0; + let Inst{12-11} = ac; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +// MFHI sub-class format. +class MFHI_FMT<bits<6> funct> : DSPInst { + bits<5> rd; + bits<2> ac; + + let Inst{31-26} = 0; + let Inst{25-23} = 0; + let Inst{22-21} = ac; + let Inst{20-16} = 0; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +// MTHI sub-class format. +class MTHI_FMT<bits<6> funct> : DSPInst { + bits<5> rs; + bits<2> ac; + + let Inst{31-26} = 0; + let Inst{25-21} = rs; + let Inst{20-13} = 0; + let Inst{12-11} = ac; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +// EXTR.W sub-class format (type 1). +class EXTR_W_TY1_FMT<bits<5> op> : DSPInst { + bits<5> rt; + bits<2> ac; + bits<5> shift_rs; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = shift_rs; + let Inst{20-16} = rt; + let Inst{15-13} = 0; + let Inst{12-11} = ac; + let Inst{10-6} = op; + let Inst{5-0} = 0b111000; +} + +// SHILO sub-class format. +class SHILO_R1_FMT<bits<5> op> : DSPInst { + bits<2> ac; + bits<6> shift; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-20} = shift; + let Inst{19-13} = 0; + let Inst{12-11} = ac; + let Inst{10-6} = op; + let Inst{5-0} = 0b111000; +} + +class SHILO_R2_FMT<bits<5> op> : DSPInst { + bits<2> ac; + bits<5> rs; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-13} = 0; + let Inst{12-11} = ac; + let Inst{10-6} = op; + let Inst{5-0} = 0b111000; +} + +class RDDSP_FMT<bits<5> op> : DSPInst { + bits<5> rd; + bits<10> mask; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-16} = mask; + let Inst{15-11} = rd; + let Inst{10-6} = op; + let Inst{5-0} = 0b111000; +} + +class WRDSP_FMT<bits<5> op> : DSPInst { + bits<5> rs; + bits<10> mask; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-11} = mask; + let Inst{10-6} = op; + let Inst{5-0} = 0b111000; +} + +class BPOSGE32_FMT<bits<5> op> : DSPInst { + bits<16> offset; + + let Opcode = REGIMM_OPCODE.V; + + let Inst{25-21} = 0; + let Inst{20-16} = op; + let Inst{15-0} = offset; +} + +// INSV sub-class format. +class INSV_FMT<bits<6> op> : DSPInst { + bits<5> rt; + bits<5> rs; + + let Opcode = SPECIAL3_OPCODE.V; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-6} = 0; + let Inst{5-0} = op; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsDSPInstrInfo.td b/contrib/llvm/lib/Target/Mips/MipsDSPInstrInfo.td new file mode 100644 index 000000000000..d26838404451 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsDSPInstrInfo.td @@ -0,0 +1,1417 @@ +//===- MipsDSPInstrInfo.td - DSP ASE instructions -*- tablegen ------------*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Mips DSP ASE instructions. +// +//===----------------------------------------------------------------------===// + +// ImmLeaf +def immZExt2 : ImmLeaf<i32, [{return isUInt<2>(Imm);}]>; +def immZExt3 : ImmLeaf<i32, [{return isUInt<3>(Imm);}]>; +def immZExt4 : ImmLeaf<i32, [{return isUInt<4>(Imm);}]>; +def immZExt8 : ImmLeaf<i32, [{return isUInt<8>(Imm);}]>; +def immZExt10 : ImmLeaf<i32, [{return isUInt<10>(Imm);}]>; +def immSExt6 : ImmLeaf<i32, [{return isInt<6>(Imm);}]>; + +// Mips-specific dsp nodes +def SDT_MipsExtr : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>, + SDTCisVT<2, untyped>]>; +def SDT_MipsShilo : SDTypeProfile<1, 2, [SDTCisVT<0, untyped>, + SDTCisSameAs<0, 2>, SDTCisVT<1, i32>]>; +def SDT_MipsDPA : SDTypeProfile<1, 3, [SDTCisVT<0, untyped>, SDTCisSameAs<0, 3>, + SDTCisVT<1, i32>, SDTCisSameAs<1, 2>]>; +def SDT_MipsSHIFT_DSP : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisSameAs<0, 1>, + SDTCisVT<2, i32>]>; + +class MipsDSPBase<string Opc, SDTypeProfile Prof> : + SDNode<!strconcat("MipsISD::", Opc), Prof>; + +class MipsDSPSideEffectBase<string Opc, SDTypeProfile Prof> : + SDNode<!strconcat("MipsISD::", Opc), Prof, [SDNPHasChain, SDNPSideEffect]>; + +def MipsEXTP : MipsDSPSideEffectBase<"EXTP", SDT_MipsExtr>; +def MipsEXTPDP : MipsDSPSideEffectBase<"EXTPDP", SDT_MipsExtr>; +def MipsEXTR_S_H : MipsDSPSideEffectBase<"EXTR_S_H", SDT_MipsExtr>; +def MipsEXTR_W : MipsDSPSideEffectBase<"EXTR_W", SDT_MipsExtr>; +def MipsEXTR_R_W : MipsDSPSideEffectBase<"EXTR_R_W", SDT_MipsExtr>; +def MipsEXTR_RS_W : MipsDSPSideEffectBase<"EXTR_RS_W", SDT_MipsExtr>; + +def MipsSHILO : MipsDSPBase<"SHILO", SDT_MipsShilo>; +def MipsMTHLIP : MipsDSPSideEffectBase<"MTHLIP", SDT_MipsShilo>; + +def MipsMULSAQ_S_W_PH : MipsDSPSideEffectBase<"MULSAQ_S_W_PH", SDT_MipsDPA>; +def MipsMAQ_S_W_PHL : MipsDSPSideEffectBase<"MAQ_S_W_PHL", SDT_MipsDPA>; +def MipsMAQ_S_W_PHR : MipsDSPSideEffectBase<"MAQ_S_W_PHR", SDT_MipsDPA>; +def MipsMAQ_SA_W_PHL : MipsDSPSideEffectBase<"MAQ_SA_W_PHL", SDT_MipsDPA>; +def MipsMAQ_SA_W_PHR : MipsDSPSideEffectBase<"MAQ_SA_W_PHR", SDT_MipsDPA>; + +def MipsDPAU_H_QBL : MipsDSPBase<"DPAU_H_QBL", SDT_MipsDPA>; +def MipsDPAU_H_QBR : MipsDSPBase<"DPAU_H_QBR", SDT_MipsDPA>; +def MipsDPSU_H_QBL : MipsDSPBase<"DPSU_H_QBL", SDT_MipsDPA>; +def MipsDPSU_H_QBR : MipsDSPBase<"DPSU_H_QBR", SDT_MipsDPA>; +def MipsDPAQ_S_W_PH : MipsDSPSideEffectBase<"DPAQ_S_W_PH", SDT_MipsDPA>; +def MipsDPSQ_S_W_PH : MipsDSPSideEffectBase<"DPSQ_S_W_PH", SDT_MipsDPA>; +def MipsDPAQ_SA_L_W : MipsDSPSideEffectBase<"DPAQ_SA_L_W", SDT_MipsDPA>; +def MipsDPSQ_SA_L_W : MipsDSPSideEffectBase<"DPSQ_SA_L_W", SDT_MipsDPA>; + +def MipsDPA_W_PH : MipsDSPBase<"DPA_W_PH", SDT_MipsDPA>; +def MipsDPS_W_PH : MipsDSPBase<"DPS_W_PH", SDT_MipsDPA>; +def MipsDPAQX_S_W_PH : MipsDSPSideEffectBase<"DPAQX_S_W_PH", SDT_MipsDPA>; +def MipsDPAQX_SA_W_PH : MipsDSPSideEffectBase<"DPAQX_SA_W_PH", SDT_MipsDPA>; +def MipsDPAX_W_PH : MipsDSPBase<"DPAX_W_PH", SDT_MipsDPA>; +def MipsDPSX_W_PH : MipsDSPBase<"DPSX_W_PH", SDT_MipsDPA>; +def MipsDPSQX_S_W_PH : MipsDSPSideEffectBase<"DPSQX_S_W_PH", SDT_MipsDPA>; +def MipsDPSQX_SA_W_PH : MipsDSPSideEffectBase<"DPSQX_SA_W_PH", SDT_MipsDPA>; +def MipsMULSA_W_PH : MipsDSPBase<"MULSA_W_PH", SDT_MipsDPA>; + +def MipsMULT : MipsDSPBase<"MULT", SDT_MipsDPA>; +def MipsMULTU : MipsDSPBase<"MULTU", SDT_MipsDPA>; +def MipsMADD_DSP : MipsDSPBase<"MADD_DSP", SDT_MipsDPA>; +def MipsMADDU_DSP : MipsDSPBase<"MADDU_DSP", SDT_MipsDPA>; +def MipsMSUB_DSP : MipsDSPBase<"MSUB_DSP", SDT_MipsDPA>; +def MipsMSUBU_DSP : MipsDSPBase<"MSUBU_DSP", SDT_MipsDPA>; +def MipsSHLL_DSP : MipsDSPBase<"SHLL_DSP", SDT_MipsSHIFT_DSP>; +def MipsSHRA_DSP : MipsDSPBase<"SHRA_DSP", SDT_MipsSHIFT_DSP>; +def MipsSHRL_DSP : MipsDSPBase<"SHRL_DSP", SDT_MipsSHIFT_DSP>; +def MipsSETCC_DSP : MipsDSPBase<"SETCC_DSP", SDTSetCC>; +def MipsSELECT_CC_DSP : MipsDSPBase<"SELECT_CC_DSP", SDTSelectCC>; + +// Flags. +class Uses<list<Register> Regs> { + list<Register> Uses = Regs; +} + +class Defs<list<Register> Regs> { + list<Register> Defs = Regs; +} + +// Instruction encoding. +class ADDU_QB_ENC : ADDU_QB_FMT<0b00000>; +class ADDU_S_QB_ENC : ADDU_QB_FMT<0b00100>; +class SUBU_QB_ENC : ADDU_QB_FMT<0b00001>; +class SUBU_S_QB_ENC : ADDU_QB_FMT<0b00101>; +class ADDQ_PH_ENC : ADDU_QB_FMT<0b01010>; +class ADDQ_S_PH_ENC : ADDU_QB_FMT<0b01110>; +class SUBQ_PH_ENC : ADDU_QB_FMT<0b01011>; +class SUBQ_S_PH_ENC : ADDU_QB_FMT<0b01111>; +class ADDQ_S_W_ENC : ADDU_QB_FMT<0b10110>; +class SUBQ_S_W_ENC : ADDU_QB_FMT<0b10111>; +class ADDSC_ENC : ADDU_QB_FMT<0b10000>; +class ADDWC_ENC : ADDU_QB_FMT<0b10001>; +class MODSUB_ENC : ADDU_QB_FMT<0b10010>; +class RADDU_W_QB_ENC : RADDU_W_QB_FMT<0b10100>; +class ABSQ_S_PH_ENC : ABSQ_S_PH_R2_FMT<0b01001>; +class ABSQ_S_W_ENC : ABSQ_S_PH_R2_FMT<0b10001>; +class PRECRQ_QB_PH_ENC : CMP_EQ_QB_R3_FMT<0b01100>; +class PRECRQ_PH_W_ENC : CMP_EQ_QB_R3_FMT<0b10100>; +class PRECRQ_RS_PH_W_ENC : CMP_EQ_QB_R3_FMT<0b10101>; +class PRECRQU_S_QB_PH_ENC : CMP_EQ_QB_R3_FMT<0b01111>; +class PRECEQ_W_PHL_ENC : ABSQ_S_PH_R2_FMT<0b01100>; +class PRECEQ_W_PHR_ENC : ABSQ_S_PH_R2_FMT<0b01101>; +class PRECEQU_PH_QBL_ENC : ABSQ_S_PH_R2_FMT<0b00100>; +class PRECEQU_PH_QBR_ENC : ABSQ_S_PH_R2_FMT<0b00101>; +class PRECEQU_PH_QBLA_ENC : ABSQ_S_PH_R2_FMT<0b00110>; +class PRECEQU_PH_QBRA_ENC : ABSQ_S_PH_R2_FMT<0b00111>; +class PRECEU_PH_QBL_ENC : ABSQ_S_PH_R2_FMT<0b11100>; +class PRECEU_PH_QBR_ENC : ABSQ_S_PH_R2_FMT<0b11101>; +class PRECEU_PH_QBLA_ENC : ABSQ_S_PH_R2_FMT<0b11110>; +class PRECEU_PH_QBRA_ENC : ABSQ_S_PH_R2_FMT<0b11111>; +class SHLL_QB_ENC : SHLL_QB_FMT<0b00000>; +class SHLLV_QB_ENC : SHLL_QB_FMT<0b00010>; +class SHRL_QB_ENC : SHLL_QB_FMT<0b00001>; +class SHRLV_QB_ENC : SHLL_QB_FMT<0b00011>; +class SHLL_PH_ENC : SHLL_QB_FMT<0b01000>; +class SHLLV_PH_ENC : SHLL_QB_FMT<0b01010>; +class SHLL_S_PH_ENC : SHLL_QB_FMT<0b01100>; +class SHLLV_S_PH_ENC : SHLL_QB_FMT<0b01110>; +class SHRA_PH_ENC : SHLL_QB_FMT<0b01001>; +class SHRAV_PH_ENC : SHLL_QB_FMT<0b01011>; +class SHRA_R_PH_ENC : SHLL_QB_FMT<0b01101>; +class SHRAV_R_PH_ENC : SHLL_QB_FMT<0b01111>; +class SHLL_S_W_ENC : SHLL_QB_FMT<0b10100>; +class SHLLV_S_W_ENC : SHLL_QB_FMT<0b10110>; +class SHRA_R_W_ENC : SHLL_QB_FMT<0b10101>; +class SHRAV_R_W_ENC : SHLL_QB_FMT<0b10111>; +class MULEU_S_PH_QBL_ENC : ADDU_QB_FMT<0b00110>; +class MULEU_S_PH_QBR_ENC : ADDU_QB_FMT<0b00111>; +class MULEQ_S_W_PHL_ENC : ADDU_QB_FMT<0b11100>; +class MULEQ_S_W_PHR_ENC : ADDU_QB_FMT<0b11101>; +class MULQ_RS_PH_ENC : ADDU_QB_FMT<0b11111>; +class MULSAQ_S_W_PH_ENC : DPA_W_PH_FMT<0b00110>; +class MAQ_S_W_PHL_ENC : DPA_W_PH_FMT<0b10100>; +class MAQ_S_W_PHR_ENC : DPA_W_PH_FMT<0b10110>; +class MAQ_SA_W_PHL_ENC : DPA_W_PH_FMT<0b10000>; +class MAQ_SA_W_PHR_ENC : DPA_W_PH_FMT<0b10010>; +class MFHI_ENC : MFHI_FMT<0b010000>; +class MFLO_ENC : MFHI_FMT<0b010010>; +class MTHI_ENC : MTHI_FMT<0b010001>; +class MTLO_ENC : MTHI_FMT<0b010011>; +class DPAU_H_QBL_ENC : DPA_W_PH_FMT<0b00011>; +class DPAU_H_QBR_ENC : DPA_W_PH_FMT<0b00111>; +class DPSU_H_QBL_ENC : DPA_W_PH_FMT<0b01011>; +class DPSU_H_QBR_ENC : DPA_W_PH_FMT<0b01111>; +class DPAQ_S_W_PH_ENC : DPA_W_PH_FMT<0b00100>; +class DPSQ_S_W_PH_ENC : DPA_W_PH_FMT<0b00101>; +class DPAQ_SA_L_W_ENC : DPA_W_PH_FMT<0b01100>; +class DPSQ_SA_L_W_ENC : DPA_W_PH_FMT<0b01101>; +class MULT_DSP_ENC : MULT_FMT<0b000000, 0b011000>; +class MULTU_DSP_ENC : MULT_FMT<0b000000, 0b011001>; +class MADD_DSP_ENC : MULT_FMT<0b011100, 0b000000>; +class MADDU_DSP_ENC : MULT_FMT<0b011100, 0b000001>; +class MSUB_DSP_ENC : MULT_FMT<0b011100, 0b000100>; +class MSUBU_DSP_ENC : MULT_FMT<0b011100, 0b000101>; +class CMPU_EQ_QB_ENC : CMP_EQ_QB_R2_FMT<0b00000>; +class CMPU_LT_QB_ENC : CMP_EQ_QB_R2_FMT<0b00001>; +class CMPU_LE_QB_ENC : CMP_EQ_QB_R2_FMT<0b00010>; +class CMPGU_EQ_QB_ENC : CMP_EQ_QB_R3_FMT<0b00100>; +class CMPGU_LT_QB_ENC : CMP_EQ_QB_R3_FMT<0b00101>; +class CMPGU_LE_QB_ENC : CMP_EQ_QB_R3_FMT<0b00110>; +class CMP_EQ_PH_ENC : CMP_EQ_QB_R2_FMT<0b01000>; +class CMP_LT_PH_ENC : CMP_EQ_QB_R2_FMT<0b01001>; +class CMP_LE_PH_ENC : CMP_EQ_QB_R2_FMT<0b01010>; +class BITREV_ENC : ABSQ_S_PH_R2_FMT<0b11011>; +class PACKRL_PH_ENC : CMP_EQ_QB_R3_FMT<0b01110>; +class REPL_QB_ENC : REPL_FMT<0b00010>; +class REPL_PH_ENC : REPL_FMT<0b01010>; +class REPLV_QB_ENC : ABSQ_S_PH_R2_FMT<0b00011>; +class REPLV_PH_ENC : ABSQ_S_PH_R2_FMT<0b01011>; +class PICK_QB_ENC : CMP_EQ_QB_R3_FMT<0b00011>; +class PICK_PH_ENC : CMP_EQ_QB_R3_FMT<0b01011>; +class LWX_ENC : LX_FMT<0b00000>; +class LHX_ENC : LX_FMT<0b00100>; +class LBUX_ENC : LX_FMT<0b00110>; +class BPOSGE32_ENC : BPOSGE32_FMT<0b11100>; +class INSV_ENC : INSV_FMT<0b001100>; + +class EXTP_ENC : EXTR_W_TY1_FMT<0b00010>; +class EXTPV_ENC : EXTR_W_TY1_FMT<0b00011>; +class EXTPDP_ENC : EXTR_W_TY1_FMT<0b01010>; +class EXTPDPV_ENC : EXTR_W_TY1_FMT<0b01011>; +class EXTR_W_ENC : EXTR_W_TY1_FMT<0b00000>; +class EXTRV_W_ENC : EXTR_W_TY1_FMT<0b00001>; +class EXTR_R_W_ENC : EXTR_W_TY1_FMT<0b00100>; +class EXTRV_R_W_ENC : EXTR_W_TY1_FMT<0b00101>; +class EXTR_RS_W_ENC : EXTR_W_TY1_FMT<0b00110>; +class EXTRV_RS_W_ENC : EXTR_W_TY1_FMT<0b00111>; +class EXTR_S_H_ENC : EXTR_W_TY1_FMT<0b01110>; +class EXTRV_S_H_ENC : EXTR_W_TY1_FMT<0b01111>; +class SHILO_ENC : SHILO_R1_FMT<0b11010>; +class SHILOV_ENC : SHILO_R2_FMT<0b11011>; +class MTHLIP_ENC : SHILO_R2_FMT<0b11111>; + +class RDDSP_ENC : RDDSP_FMT<0b10010>; +class WRDSP_ENC : WRDSP_FMT<0b10011>; +class ADDU_PH_ENC : ADDU_QB_FMT<0b01000>; +class ADDU_S_PH_ENC : ADDU_QB_FMT<0b01100>; +class SUBU_PH_ENC : ADDU_QB_FMT<0b01001>; +class SUBU_S_PH_ENC : ADDU_QB_FMT<0b01101>; +class CMPGDU_EQ_QB_ENC : CMP_EQ_QB_R3_FMT<0b11000>; +class CMPGDU_LT_QB_ENC : CMP_EQ_QB_R3_FMT<0b11001>; +class CMPGDU_LE_QB_ENC : CMP_EQ_QB_R3_FMT<0b11010>; +class ABSQ_S_QB_ENC : ABSQ_S_PH_R2_FMT<0b00001>; +class ADDUH_QB_ENC : ADDUH_QB_FMT<0b00000>; +class ADDUH_R_QB_ENC : ADDUH_QB_FMT<0b00010>; +class SUBUH_QB_ENC : ADDUH_QB_FMT<0b00001>; +class SUBUH_R_QB_ENC : ADDUH_QB_FMT<0b00011>; +class ADDQH_PH_ENC : ADDUH_QB_FMT<0b01000>; +class ADDQH_R_PH_ENC : ADDUH_QB_FMT<0b01010>; +class SUBQH_PH_ENC : ADDUH_QB_FMT<0b01001>; +class SUBQH_R_PH_ENC : ADDUH_QB_FMT<0b01011>; +class ADDQH_W_ENC : ADDUH_QB_FMT<0b10000>; +class ADDQH_R_W_ENC : ADDUH_QB_FMT<0b10010>; +class SUBQH_W_ENC : ADDUH_QB_FMT<0b10001>; +class SUBQH_R_W_ENC : ADDUH_QB_FMT<0b10011>; +class MUL_PH_ENC : ADDUH_QB_FMT<0b01100>; +class MUL_S_PH_ENC : ADDUH_QB_FMT<0b01110>; +class MULQ_S_W_ENC : ADDUH_QB_FMT<0b10110>; +class MULQ_RS_W_ENC : ADDUH_QB_FMT<0b10111>; +class MULQ_S_PH_ENC : ADDU_QB_FMT<0b11110>; +class DPA_W_PH_ENC : DPA_W_PH_FMT<0b00000>; +class DPS_W_PH_ENC : DPA_W_PH_FMT<0b00001>; +class DPAQX_S_W_PH_ENC : DPA_W_PH_FMT<0b11000>; +class DPAQX_SA_W_PH_ENC : DPA_W_PH_FMT<0b11010>; +class DPAX_W_PH_ENC : DPA_W_PH_FMT<0b01000>; +class DPSX_W_PH_ENC : DPA_W_PH_FMT<0b01001>; +class DPSQX_S_W_PH_ENC : DPA_W_PH_FMT<0b11001>; +class DPSQX_SA_W_PH_ENC : DPA_W_PH_FMT<0b11011>; +class MULSA_W_PH_ENC : DPA_W_PH_FMT<0b00010>; +class PRECR_QB_PH_ENC : CMP_EQ_QB_R3_FMT<0b01101>; +class PRECR_SRA_PH_W_ENC : PRECR_SRA_PH_W_FMT<0b11110>; +class PRECR_SRA_R_PH_W_ENC : PRECR_SRA_PH_W_FMT<0b11111>; +class SHRA_QB_ENC : SHLL_QB_FMT<0b00100>; +class SHRAV_QB_ENC : SHLL_QB_FMT<0b00110>; +class SHRA_R_QB_ENC : SHLL_QB_FMT<0b00101>; +class SHRAV_R_QB_ENC : SHLL_QB_FMT<0b00111>; +class SHRL_PH_ENC : SHLL_QB_FMT<0b11001>; +class SHRLV_PH_ENC : SHLL_QB_FMT<0b11011>; +class APPEND_ENC : APPEND_FMT<0b00000>; +class BALIGN_ENC : APPEND_FMT<0b10000>; +class PREPEND_ENC : APPEND_FMT<0b00001>; + +// Instruction desc. +class ADDU_QB_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROD, + RegisterOperand ROS, RegisterOperand ROT = ROS> { + dag OutOperandList = (outs ROD:$rd); + dag InOperandList = (ins ROS:$rs, ROT:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list<dag> Pattern = [(set ROD:$rd, (OpNode ROS:$rs, ROT:$rt))]; + InstrItinClass Itinerary = itin; +} + +class RADDU_W_QB_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROD, + RegisterOperand ROS = ROD> { + dag OutOperandList = (outs ROD:$rd); + dag InOperandList = (ins ROS:$rs); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs"); + list<dag> Pattern = [(set ROD:$rd, (OpNode ROS:$rs))]; + InstrItinClass Itinerary = itin; +} + +class CMP_EQ_QB_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROS, + RegisterOperand ROT = ROS> { + dag OutOperandList = (outs); + dag InOperandList = (ins ROS:$rs, ROT:$rt); + string AsmString = !strconcat(instr_asm, "\t$rs, $rt"); + list<dag> Pattern = [(OpNode ROS:$rs, ROT:$rt)]; + InstrItinClass Itinerary = itin; +} + +class CMP_EQ_QB_R3_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROD, + RegisterOperand ROS, RegisterOperand ROT = ROS> { + dag OutOperandList = (outs ROD:$rd); + dag InOperandList = (ins ROS:$rs, ROT:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list<dag> Pattern = [(set ROD:$rd, (OpNode ROS:$rs, ROT:$rt))]; + InstrItinClass Itinerary = itin; +} + +class PRECR_SRA_PH_W_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROT, + RegisterOperand ROS = ROT> { + dag OutOperandList = (outs ROT:$rt); + dag InOperandList = (ins ROS:$rs, uimm5:$sa, ROS:$src); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $sa"); + list<dag> Pattern = [(set ROT:$rt, (OpNode ROS:$src, ROS:$rs, immZExt5:$sa))]; + InstrItinClass Itinerary = itin; + string Constraints = "$src = $rt"; +} + +class ABSQ_S_PH_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROD, + RegisterOperand ROT = ROD> { + dag OutOperandList = (outs ROD:$rd); + dag InOperandList = (ins ROT:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rt"); + list<dag> Pattern = [(set ROD:$rd, (OpNode ROT:$rt))]; + InstrItinClass Itinerary = itin; +} + +class REPL_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ImmLeaf immPat, InstrItinClass itin, RegisterOperand RO> { + dag OutOperandList = (outs RO:$rd); + dag InOperandList = (ins uimm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rd, $imm"); + list<dag> Pattern = [(set RO:$rd, (OpNode immPat:$imm))]; + InstrItinClass Itinerary = itin; +} + +class SHLL_QB_R3_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand RO> { + dag OutOperandList = (outs RO:$rd); + dag InOperandList = (ins RO:$rt, GPR32Opnd:$rs_sa); + string AsmString = !strconcat(instr_asm, "\t$rd, $rt, $rs_sa"); + list<dag> Pattern = [(set RO:$rd, (OpNode RO:$rt, GPR32Opnd:$rs_sa))]; + InstrItinClass Itinerary = itin; +} + +class SHLL_QB_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + SDPatternOperator ImmPat, InstrItinClass itin, + RegisterOperand RO> { + dag OutOperandList = (outs RO:$rd); + dag InOperandList = (ins RO:$rt, uimm16:$rs_sa); + string AsmString = !strconcat(instr_asm, "\t$rd, $rt, $rs_sa"); + list<dag> Pattern = [(set RO:$rd, (OpNode RO:$rt, ImmPat:$rs_sa))]; + InstrItinClass Itinerary = itin; + bit hasSideEffects = 1; +} + +class LX_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rd); + dag InOperandList = (ins PtrRC:$base, PtrRC:$index); + string AsmString = !strconcat(instr_asm, "\t$rd, ${index}(${base})"); + list<dag> Pattern = [(set GPR32Opnd:$rd, (OpNode iPTR:$base, iPTR:$index))]; + InstrItinClass Itinerary = itin; + bit mayLoad = 1; +} + +class ADDUH_QB_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin, RegisterOperand ROD, + RegisterOperand ROS = ROD, RegisterOperand ROT = ROD> { + dag OutOperandList = (outs ROD:$rd); + dag InOperandList = (ins ROS:$rs, ROT:$rt); + string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); + list<dag> Pattern = [(set ROD:$rd, (OpNode ROS:$rs, ROT:$rt))]; + InstrItinClass Itinerary = itin; +} + +class APPEND_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + SDPatternOperator ImmOp, InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins GPR32Opnd:$rs, uimm5:$sa, GPR32Opnd:$src); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $sa"); + list<dag> Pattern = [(set GPR32Opnd:$rt, + (OpNode GPR32Opnd:$src, GPR32Opnd:$rs, ImmOp:$sa))]; + InstrItinClass Itinerary = itin; + string Constraints = "$src = $rt"; +} + +class EXTR_W_TY1_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins ACC64DSPOpnd:$ac, GPR32Opnd:$shift_rs); + string AsmString = !strconcat(instr_asm, "\t$rt, $ac, $shift_rs"); + InstrItinClass Itinerary = itin; +} + +class EXTR_W_TY1_R1_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins ACC64DSPOpnd:$ac, uimm16:$shift_rs); + string AsmString = !strconcat(instr_asm, "\t$rt, $ac, $shift_rs"); + InstrItinClass Itinerary = itin; +} + +class SHILO_R1_DESC_BASE<string instr_asm, SDPatternOperator OpNode> { + dag OutOperandList = (outs ACC64DSPOpnd:$ac); + dag InOperandList = (ins simm16:$shift, ACC64DSPOpnd:$acin); + string AsmString = !strconcat(instr_asm, "\t$ac, $shift"); + list<dag> Pattern = [(set ACC64DSPOpnd:$ac, + (OpNode immSExt6:$shift, ACC64DSPOpnd:$acin))]; + string Constraints = "$acin = $ac"; +} + +class SHILO_R2_DESC_BASE<string instr_asm, SDPatternOperator OpNode> { + dag OutOperandList = (outs ACC64DSPOpnd:$ac); + dag InOperandList = (ins GPR32Opnd:$rs, ACC64DSPOpnd:$acin); + string AsmString = !strconcat(instr_asm, "\t$ac, $rs"); + list<dag> Pattern = [(set ACC64DSPOpnd:$ac, + (OpNode GPR32Opnd:$rs, ACC64DSPOpnd:$acin))]; + string Constraints = "$acin = $ac"; +} + +class MTHLIP_DESC_BASE<string instr_asm, SDPatternOperator OpNode> { + dag OutOperandList = (outs ACC64DSPOpnd:$ac); + dag InOperandList = (ins GPR32Opnd:$rs, ACC64DSPOpnd:$acin); + string AsmString = !strconcat(instr_asm, "\t$rs, $ac"); + list<dag> Pattern = [(set ACC64DSPOpnd:$ac, + (OpNode GPR32Opnd:$rs, ACC64DSPOpnd:$acin))]; + string Constraints = "$acin = $ac"; +} + +class RDDSP_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rd); + dag InOperandList = (ins uimm16:$mask); + string AsmString = !strconcat(instr_asm, "\t$rd, $mask"); + list<dag> Pattern = [(set GPR32Opnd:$rd, (OpNode immZExt10:$mask))]; + InstrItinClass Itinerary = itin; +} + +class WRDSP_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs); + dag InOperandList = (ins GPR32Opnd:$rs, uimm16:$mask); + string AsmString = !strconcat(instr_asm, "\t$rs, $mask"); + list<dag> Pattern = [(OpNode GPR32Opnd:$rs, immZExt10:$mask)]; + InstrItinClass Itinerary = itin; +} + +class DPA_W_PH_DESC_BASE<string instr_asm, SDPatternOperator OpNode> { + dag OutOperandList = (outs ACC64DSPOpnd:$ac); + dag InOperandList = (ins GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64DSPOpnd:$acin); + string AsmString = !strconcat(instr_asm, "\t$ac, $rs, $rt"); + list<dag> Pattern = [(set ACC64DSPOpnd:$ac, + (OpNode GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64DSPOpnd:$acin))]; + string Constraints = "$acin = $ac"; +} + +class MULT_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs ACC64DSPOpnd:$ac); + dag InOperandList = (ins GPR32Opnd:$rs, GPR32Opnd:$rt); + string AsmString = !strconcat(instr_asm, "\t$ac, $rs, $rt"); + list<dag> Pattern = [(set ACC64DSPOpnd:$ac, (OpNode GPR32Opnd:$rs, GPR32Opnd:$rt))]; + InstrItinClass Itinerary = itin; + bit isCommutable = 1; +} + +class MADD_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs ACC64DSPOpnd:$ac); + dag InOperandList = (ins GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64DSPOpnd:$acin); + string AsmString = !strconcat(instr_asm, "\t$ac, $rs, $rt"); + list<dag> Pattern = [(set ACC64DSPOpnd:$ac, + (OpNode GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64DSPOpnd:$acin))]; + InstrItinClass Itinerary = itin; + string Constraints = "$acin = $ac"; +} + +class MFHI_DESC_BASE<string instr_asm, RegisterOperand RO, SDNode OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rd); + dag InOperandList = (ins RO:$ac); + string AsmString = !strconcat(instr_asm, "\t$rd, $ac"); + list<dag> Pattern = [(set GPR32Opnd:$rd, (OpNode RO:$ac))]; + InstrItinClass Itinerary = itin; +} + +class MTHI_DESC_BASE<string instr_asm, RegisterOperand RO, InstrItinClass itin> { + dag OutOperandList = (outs RO:$ac); + dag InOperandList = (ins GPR32Opnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rs, $ac"); + InstrItinClass Itinerary = itin; +} + +class BPOSGE32_PSEUDO_DESC_BASE<SDPatternOperator OpNode, InstrItinClass itin> : + MipsPseudo<(outs GPR32Opnd:$dst), (ins), [(set GPR32Opnd:$dst, (OpNode))]> { + bit usesCustomInserter = 1; +} + +class BPOSGE32_DESC_BASE<string instr_asm, InstrItinClass itin> { + dag OutOperandList = (outs); + dag InOperandList = (ins brtarget:$offset); + string AsmString = !strconcat(instr_asm, "\t$offset"); + InstrItinClass Itinerary = itin; + bit isBranch = 1; + bit isTerminator = 1; + bit hasDelaySlot = 1; +} + +class INSV_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + InstrItinClass itin> { + dag OutOperandList = (outs GPR32Opnd:$rt); + dag InOperandList = (ins GPR32Opnd:$src, GPR32Opnd:$rs); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs"); + list<dag> Pattern = [(set GPR32Opnd:$rt, (OpNode GPR32Opnd:$src, GPR32Opnd:$rs))]; + InstrItinClass Itinerary = itin; + string Constraints = "$src = $rt"; +} + +//===----------------------------------------------------------------------===// +// MIPS DSP Rev 1 +//===----------------------------------------------------------------------===// + +// Addition/subtraction +class ADDU_QB_DESC : ADDU_QB_DESC_BASE<"addu.qb", null_frag, NoItinerary, + DSPROpnd, DSPROpnd>, IsCommutable, + Defs<[DSPOutFlag20]>; + +class ADDU_S_QB_DESC : ADDU_QB_DESC_BASE<"addu_s.qb", int_mips_addu_s_qb, + NoItinerary, DSPROpnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag20]>; + +class SUBU_QB_DESC : ADDU_QB_DESC_BASE<"subu.qb", null_frag, NoItinerary, + DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class SUBU_S_QB_DESC : ADDU_QB_DESC_BASE<"subu_s.qb", int_mips_subu_s_qb, + NoItinerary, DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class ADDQ_PH_DESC : ADDU_QB_DESC_BASE<"addq.ph", null_frag, NoItinerary, + DSPROpnd, DSPROpnd>, IsCommutable, + Defs<[DSPOutFlag20]>; + +class ADDQ_S_PH_DESC : ADDU_QB_DESC_BASE<"addq_s.ph", int_mips_addq_s_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag20]>; + +class SUBQ_PH_DESC : ADDU_QB_DESC_BASE<"subq.ph", null_frag, NoItinerary, + DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class SUBQ_S_PH_DESC : ADDU_QB_DESC_BASE<"subq_s.ph", int_mips_subq_s_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class ADDQ_S_W_DESC : ADDU_QB_DESC_BASE<"addq_s.w", int_mips_addq_s_w, + NoItinerary, GPR32Opnd, GPR32Opnd>, + IsCommutable, Defs<[DSPOutFlag20]>; + +class SUBQ_S_W_DESC : ADDU_QB_DESC_BASE<"subq_s.w", int_mips_subq_s_w, + NoItinerary, GPR32Opnd, GPR32Opnd>, + Defs<[DSPOutFlag20]>; + +class ADDSC_DESC : ADDU_QB_DESC_BASE<"addsc", null_frag, NoItinerary, + GPR32Opnd, GPR32Opnd>, IsCommutable, + Defs<[DSPCarry]>; + +class ADDWC_DESC : ADDU_QB_DESC_BASE<"addwc", null_frag, NoItinerary, + GPR32Opnd, GPR32Opnd>, + IsCommutable, Uses<[DSPCarry]>, Defs<[DSPOutFlag20]>; + +class MODSUB_DESC : ADDU_QB_DESC_BASE<"modsub", int_mips_modsub, NoItinerary, + GPR32Opnd, GPR32Opnd>; + +class RADDU_W_QB_DESC : RADDU_W_QB_DESC_BASE<"raddu.w.qb", int_mips_raddu_w_qb, + NoItinerary, GPR32Opnd, DSPROpnd>; + +// Absolute value +class ABSQ_S_PH_DESC : ABSQ_S_PH_R2_DESC_BASE<"absq_s.ph", int_mips_absq_s_ph, + NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class ABSQ_S_W_DESC : ABSQ_S_PH_R2_DESC_BASE<"absq_s.w", int_mips_absq_s_w, + NoItinerary, GPR32Opnd>, + Defs<[DSPOutFlag20]>; + +// Precision reduce/expand +class PRECRQ_QB_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"precrq.qb.ph", + int_mips_precrq_qb_ph, + NoItinerary, DSPROpnd, DSPROpnd>; + +class PRECRQ_PH_W_DESC : CMP_EQ_QB_R3_DESC_BASE<"precrq.ph.w", + int_mips_precrq_ph_w, + NoItinerary, DSPROpnd, GPR32Opnd>; + +class PRECRQ_RS_PH_W_DESC : CMP_EQ_QB_R3_DESC_BASE<"precrq_rs.ph.w", + int_mips_precrq_rs_ph_w, + NoItinerary, DSPROpnd, + GPR32Opnd>, + Defs<[DSPOutFlag22]>; + +class PRECRQU_S_QB_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"precrqu_s.qb.ph", + int_mips_precrqu_s_qb_ph, + NoItinerary, DSPROpnd, + DSPROpnd>, + Defs<[DSPOutFlag22]>; + +class PRECEQ_W_PHL_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceq.w.phl", + int_mips_preceq_w_phl, + NoItinerary, GPR32Opnd, DSPROpnd>; + +class PRECEQ_W_PHR_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceq.w.phr", + int_mips_preceq_w_phr, + NoItinerary, GPR32Opnd, DSPROpnd>; + +class PRECEQU_PH_QBL_DESC : ABSQ_S_PH_R2_DESC_BASE<"precequ.ph.qbl", + int_mips_precequ_ph_qbl, + NoItinerary, DSPROpnd>; + +class PRECEQU_PH_QBR_DESC : ABSQ_S_PH_R2_DESC_BASE<"precequ.ph.qbr", + int_mips_precequ_ph_qbr, + NoItinerary, DSPROpnd>; + +class PRECEQU_PH_QBLA_DESC : ABSQ_S_PH_R2_DESC_BASE<"precequ.ph.qbla", + int_mips_precequ_ph_qbla, + NoItinerary, DSPROpnd>; + +class PRECEQU_PH_QBRA_DESC : ABSQ_S_PH_R2_DESC_BASE<"precequ.ph.qbra", + int_mips_precequ_ph_qbra, + NoItinerary, DSPROpnd>; + +class PRECEU_PH_QBL_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceu.ph.qbl", + int_mips_preceu_ph_qbl, + NoItinerary, DSPROpnd>; + +class PRECEU_PH_QBR_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceu.ph.qbr", + int_mips_preceu_ph_qbr, + NoItinerary, DSPROpnd>; + +class PRECEU_PH_QBLA_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceu.ph.qbla", + int_mips_preceu_ph_qbla, + NoItinerary, DSPROpnd>; + +class PRECEU_PH_QBRA_DESC : ABSQ_S_PH_R2_DESC_BASE<"preceu.ph.qbra", + int_mips_preceu_ph_qbra, + NoItinerary, DSPROpnd>; + +// Shift +class SHLL_QB_DESC : SHLL_QB_R2_DESC_BASE<"shll.qb", null_frag, immZExt3, + NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag22]>; + +class SHLLV_QB_DESC : SHLL_QB_R3_DESC_BASE<"shllv.qb", int_mips_shll_qb, + NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag22]>; + +class SHRL_QB_DESC : SHLL_QB_R2_DESC_BASE<"shrl.qb", null_frag, immZExt3, + NoItinerary, DSPROpnd>; + +class SHRLV_QB_DESC : SHLL_QB_R3_DESC_BASE<"shrlv.qb", int_mips_shrl_qb, + NoItinerary, DSPROpnd>; + +class SHLL_PH_DESC : SHLL_QB_R2_DESC_BASE<"shll.ph", null_frag, immZExt4, + NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag22]>; + +class SHLLV_PH_DESC : SHLL_QB_R3_DESC_BASE<"shllv.ph", int_mips_shll_ph, + NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag22]>; + +class SHLL_S_PH_DESC : SHLL_QB_R2_DESC_BASE<"shll_s.ph", int_mips_shll_s_ph, + immZExt4, NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag22]>; + +class SHLLV_S_PH_DESC : SHLL_QB_R3_DESC_BASE<"shllv_s.ph", int_mips_shll_s_ph, + NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag22]>; + +class SHRA_PH_DESC : SHLL_QB_R2_DESC_BASE<"shra.ph", null_frag, immZExt4, + NoItinerary, DSPROpnd>; + +class SHRAV_PH_DESC : SHLL_QB_R3_DESC_BASE<"shrav.ph", int_mips_shra_ph, + NoItinerary, DSPROpnd>; + +class SHRA_R_PH_DESC : SHLL_QB_R2_DESC_BASE<"shra_r.ph", int_mips_shra_r_ph, + immZExt4, NoItinerary, DSPROpnd>; + +class SHRAV_R_PH_DESC : SHLL_QB_R3_DESC_BASE<"shrav_r.ph", int_mips_shra_r_ph, + NoItinerary, DSPROpnd>; + +class SHLL_S_W_DESC : SHLL_QB_R2_DESC_BASE<"shll_s.w", int_mips_shll_s_w, + immZExt5, NoItinerary, GPR32Opnd>, + Defs<[DSPOutFlag22]>; + +class SHLLV_S_W_DESC : SHLL_QB_R3_DESC_BASE<"shllv_s.w", int_mips_shll_s_w, + NoItinerary, GPR32Opnd>, + Defs<[DSPOutFlag22]>; + +class SHRA_R_W_DESC : SHLL_QB_R2_DESC_BASE<"shra_r.w", int_mips_shra_r_w, + immZExt5, NoItinerary, GPR32Opnd>; + +class SHRAV_R_W_DESC : SHLL_QB_R3_DESC_BASE<"shrav_r.w", int_mips_shra_r_w, + NoItinerary, GPR32Opnd>; + +// Multiplication +class MULEU_S_PH_QBL_DESC : ADDU_QB_DESC_BASE<"muleu_s.ph.qbl", + int_mips_muleu_s_ph_qbl, + NoItinerary, DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag21]>; + +class MULEU_S_PH_QBR_DESC : ADDU_QB_DESC_BASE<"muleu_s.ph.qbr", + int_mips_muleu_s_ph_qbr, + NoItinerary, DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag21]>; + +class MULEQ_S_W_PHL_DESC : ADDU_QB_DESC_BASE<"muleq_s.w.phl", + int_mips_muleq_s_w_phl, + NoItinerary, GPR32Opnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag21]>; + +class MULEQ_S_W_PHR_DESC : ADDU_QB_DESC_BASE<"muleq_s.w.phr", + int_mips_muleq_s_w_phr, + NoItinerary, GPR32Opnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag21]>; + +class MULQ_RS_PH_DESC : ADDU_QB_DESC_BASE<"mulq_rs.ph", int_mips_mulq_rs_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag21]>; + +class MULSAQ_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"mulsaq_s.w.ph", + MipsMULSAQ_S_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class MAQ_S_W_PHL_DESC : DPA_W_PH_DESC_BASE<"maq_s.w.phl", MipsMAQ_S_W_PHL>, + Defs<[DSPOutFlag16_19]>; + +class MAQ_S_W_PHR_DESC : DPA_W_PH_DESC_BASE<"maq_s.w.phr", MipsMAQ_S_W_PHR>, + Defs<[DSPOutFlag16_19]>; + +class MAQ_SA_W_PHL_DESC : DPA_W_PH_DESC_BASE<"maq_sa.w.phl", MipsMAQ_SA_W_PHL>, + Defs<[DSPOutFlag16_19]>; + +class MAQ_SA_W_PHR_DESC : DPA_W_PH_DESC_BASE<"maq_sa.w.phr", MipsMAQ_SA_W_PHR>, + Defs<[DSPOutFlag16_19]>; + +// Move from/to hi/lo. +class MFHI_DESC : MFHI_DESC_BASE<"mfhi", ACC64DSPOpnd, MipsMFHI, NoItinerary>; +class MFLO_DESC : MFHI_DESC_BASE<"mflo", ACC64DSPOpnd, MipsMFLO, NoItinerary>; +class MTHI_DESC : MTHI_DESC_BASE<"mthi", HI32DSPOpnd, NoItinerary>; +class MTLO_DESC : MTHI_DESC_BASE<"mtlo", LO32DSPOpnd, NoItinerary>; + +// Dot product with accumulate/subtract +class DPAU_H_QBL_DESC : DPA_W_PH_DESC_BASE<"dpau.h.qbl", MipsDPAU_H_QBL>; + +class DPAU_H_QBR_DESC : DPA_W_PH_DESC_BASE<"dpau.h.qbr", MipsDPAU_H_QBR>; + +class DPSU_H_QBL_DESC : DPA_W_PH_DESC_BASE<"dpsu.h.qbl", MipsDPSU_H_QBL>; + +class DPSU_H_QBR_DESC : DPA_W_PH_DESC_BASE<"dpsu.h.qbr", MipsDPSU_H_QBR>; + +class DPAQ_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpaq_s.w.ph", MipsDPAQ_S_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class DPSQ_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpsq_s.w.ph", MipsDPSQ_S_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class DPAQ_SA_L_W_DESC : DPA_W_PH_DESC_BASE<"dpaq_sa.l.w", MipsDPAQ_SA_L_W>, + Defs<[DSPOutFlag16_19]>; + +class DPSQ_SA_L_W_DESC : DPA_W_PH_DESC_BASE<"dpsq_sa.l.w", MipsDPSQ_SA_L_W>, + Defs<[DSPOutFlag16_19]>; + +class MULT_DSP_DESC : MULT_DESC_BASE<"mult", MipsMult, NoItinerary>; +class MULTU_DSP_DESC : MULT_DESC_BASE<"multu", MipsMultu, NoItinerary>; +class MADD_DSP_DESC : MADD_DESC_BASE<"madd", MipsMAdd, NoItinerary>; +class MADDU_DSP_DESC : MADD_DESC_BASE<"maddu", MipsMAddu, NoItinerary>; +class MSUB_DSP_DESC : MADD_DESC_BASE<"msub", MipsMSub, NoItinerary>; +class MSUBU_DSP_DESC : MADD_DESC_BASE<"msubu", MipsMSubu, NoItinerary>; + +// Comparison +class CMPU_EQ_QB_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmpu.eq.qb", + int_mips_cmpu_eq_qb, NoItinerary, + DSPROpnd>, + IsCommutable, Defs<[DSPCCond]>; + +class CMPU_LT_QB_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmpu.lt.qb", + int_mips_cmpu_lt_qb, NoItinerary, + DSPROpnd>, Defs<[DSPCCond]>; + +class CMPU_LE_QB_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmpu.le.qb", + int_mips_cmpu_le_qb, NoItinerary, + DSPROpnd>, Defs<[DSPCCond]>; + +class CMPGU_EQ_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgu.eq.qb", + int_mips_cmpgu_eq_qb, + NoItinerary, GPR32Opnd, DSPROpnd>, + IsCommutable; + +class CMPGU_LT_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgu.lt.qb", + int_mips_cmpgu_lt_qb, + NoItinerary, GPR32Opnd, DSPROpnd>; + +class CMPGU_LE_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgu.le.qb", + int_mips_cmpgu_le_qb, + NoItinerary, GPR32Opnd, DSPROpnd>; + +class CMP_EQ_PH_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmp.eq.ph", int_mips_cmp_eq_ph, + NoItinerary, DSPROpnd>, + IsCommutable, Defs<[DSPCCond]>; + +class CMP_LT_PH_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmp.lt.ph", int_mips_cmp_lt_ph, + NoItinerary, DSPROpnd>, + Defs<[DSPCCond]>; + +class CMP_LE_PH_DESC : CMP_EQ_QB_R2_DESC_BASE<"cmp.le.ph", int_mips_cmp_le_ph, + NoItinerary, DSPROpnd>, + Defs<[DSPCCond]>; + +// Misc +class BITREV_DESC : ABSQ_S_PH_R2_DESC_BASE<"bitrev", int_mips_bitrev, + NoItinerary, GPR32Opnd>; + +class PACKRL_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"packrl.ph", int_mips_packrl_ph, + NoItinerary, DSPROpnd, DSPROpnd>; + +class REPL_QB_DESC : REPL_DESC_BASE<"repl.qb", int_mips_repl_qb, immZExt8, + NoItinerary, DSPROpnd>; + +class REPL_PH_DESC : REPL_DESC_BASE<"repl.ph", int_mips_repl_ph, immZExt10, + NoItinerary, DSPROpnd>; + +class REPLV_QB_DESC : ABSQ_S_PH_R2_DESC_BASE<"replv.qb", int_mips_repl_qb, + NoItinerary, DSPROpnd, GPR32Opnd>; + +class REPLV_PH_DESC : ABSQ_S_PH_R2_DESC_BASE<"replv.ph", int_mips_repl_ph, + NoItinerary, DSPROpnd, GPR32Opnd>; + +class PICK_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"pick.qb", int_mips_pick_qb, + NoItinerary, DSPROpnd, DSPROpnd>, + Uses<[DSPCCond]>; + +class PICK_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"pick.ph", int_mips_pick_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + Uses<[DSPCCond]>; + +class LWX_DESC : LX_DESC_BASE<"lwx", int_mips_lwx, NoItinerary>; + +class LHX_DESC : LX_DESC_BASE<"lhx", int_mips_lhx, NoItinerary>; + +class LBUX_DESC : LX_DESC_BASE<"lbux", int_mips_lbux, NoItinerary>; + +class BPOSGE32_DESC : BPOSGE32_DESC_BASE<"bposge32", NoItinerary>; + +// Extr +class EXTP_DESC : EXTR_W_TY1_R1_DESC_BASE<"extp", MipsEXTP, NoItinerary>, + Uses<[DSPPos]>, Defs<[DSPEFI]>; + +class EXTPV_DESC : EXTR_W_TY1_R2_DESC_BASE<"extpv", MipsEXTP, NoItinerary>, + Uses<[DSPPos]>, Defs<[DSPEFI]>; + +class EXTPDP_DESC : EXTR_W_TY1_R1_DESC_BASE<"extpdp", MipsEXTPDP, NoItinerary>, + Uses<[DSPPos]>, Defs<[DSPPos, DSPEFI]>; + +class EXTPDPV_DESC : EXTR_W_TY1_R2_DESC_BASE<"extpdpv", MipsEXTPDP, + NoItinerary>, + Uses<[DSPPos]>, Defs<[DSPPos, DSPEFI]>; + +class EXTR_W_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr.w", MipsEXTR_W, NoItinerary>, + Defs<[DSPOutFlag23]>; + +class EXTRV_W_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv.w", MipsEXTR_W, + NoItinerary>, Defs<[DSPOutFlag23]>; + +class EXTR_R_W_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr_r.w", MipsEXTR_R_W, + NoItinerary>, + Defs<[DSPOutFlag23]>; + +class EXTRV_R_W_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv_r.w", MipsEXTR_R_W, + NoItinerary>, + Defs<[DSPOutFlag23]>; + +class EXTR_RS_W_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr_rs.w", MipsEXTR_RS_W, + NoItinerary>, + Defs<[DSPOutFlag23]>; + +class EXTRV_RS_W_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv_rs.w", MipsEXTR_RS_W, + NoItinerary>, + Defs<[DSPOutFlag23]>; + +class EXTR_S_H_DESC : EXTR_W_TY1_R1_DESC_BASE<"extr_s.h", MipsEXTR_S_H, + NoItinerary>, + Defs<[DSPOutFlag23]>; + +class EXTRV_S_H_DESC : EXTR_W_TY1_R2_DESC_BASE<"extrv_s.h", MipsEXTR_S_H, + NoItinerary>, + Defs<[DSPOutFlag23]>; + +class SHILO_DESC : SHILO_R1_DESC_BASE<"shilo", MipsSHILO>; + +class SHILOV_DESC : SHILO_R2_DESC_BASE<"shilov", MipsSHILO>; + +class MTHLIP_DESC : MTHLIP_DESC_BASE<"mthlip", MipsMTHLIP>, Defs<[DSPPos]>; + +class RDDSP_DESC : RDDSP_DESC_BASE<"rddsp", int_mips_rddsp, NoItinerary>; + +class WRDSP_DESC : WRDSP_DESC_BASE<"wrdsp", int_mips_wrdsp, NoItinerary>; + +class INSV_DESC : INSV_DESC_BASE<"insv", int_mips_insv, NoItinerary>, + Uses<[DSPPos, DSPSCount]>; + +//===----------------------------------------------------------------------===// +// MIPS DSP Rev 2 +// Addition/subtraction +class ADDU_PH_DESC : ADDU_QB_DESC_BASE<"addu.ph", int_mips_addu_ph, NoItinerary, + DSPROpnd, DSPROpnd>, IsCommutable, + Defs<[DSPOutFlag20]>; + +class ADDU_S_PH_DESC : ADDU_QB_DESC_BASE<"addu_s.ph", int_mips_addu_s_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag20]>; + +class SUBU_PH_DESC : ADDU_QB_DESC_BASE<"subu.ph", int_mips_subu_ph, NoItinerary, + DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class SUBU_S_PH_DESC : ADDU_QB_DESC_BASE<"subu_s.ph", int_mips_subu_s_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +class ADDUH_QB_DESC : ADDUH_QB_DESC_BASE<"adduh.qb", int_mips_adduh_qb, + NoItinerary, DSPROpnd>, IsCommutable; + +class ADDUH_R_QB_DESC : ADDUH_QB_DESC_BASE<"adduh_r.qb", int_mips_adduh_r_qb, + NoItinerary, DSPROpnd>, IsCommutable; + +class SUBUH_QB_DESC : ADDUH_QB_DESC_BASE<"subuh.qb", int_mips_subuh_qb, + NoItinerary, DSPROpnd>; + +class SUBUH_R_QB_DESC : ADDUH_QB_DESC_BASE<"subuh_r.qb", int_mips_subuh_r_qb, + NoItinerary, DSPROpnd>; + +class ADDQH_PH_DESC : ADDUH_QB_DESC_BASE<"addqh.ph", int_mips_addqh_ph, + NoItinerary, DSPROpnd>, IsCommutable; + +class ADDQH_R_PH_DESC : ADDUH_QB_DESC_BASE<"addqh_r.ph", int_mips_addqh_r_ph, + NoItinerary, DSPROpnd>, IsCommutable; + +class SUBQH_PH_DESC : ADDUH_QB_DESC_BASE<"subqh.ph", int_mips_subqh_ph, + NoItinerary, DSPROpnd>; + +class SUBQH_R_PH_DESC : ADDUH_QB_DESC_BASE<"subqh_r.ph", int_mips_subqh_r_ph, + NoItinerary, DSPROpnd>; + +class ADDQH_W_DESC : ADDUH_QB_DESC_BASE<"addqh.w", int_mips_addqh_w, + NoItinerary, GPR32Opnd>, IsCommutable; + +class ADDQH_R_W_DESC : ADDUH_QB_DESC_BASE<"addqh_r.w", int_mips_addqh_r_w, + NoItinerary, GPR32Opnd>, IsCommutable; + +class SUBQH_W_DESC : ADDUH_QB_DESC_BASE<"subqh.w", int_mips_subqh_w, + NoItinerary, GPR32Opnd>; + +class SUBQH_R_W_DESC : ADDUH_QB_DESC_BASE<"subqh_r.w", int_mips_subqh_r_w, + NoItinerary, GPR32Opnd>; + +// Comparison +class CMPGDU_EQ_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgdu.eq.qb", + int_mips_cmpgdu_eq_qb, + NoItinerary, GPR32Opnd, DSPROpnd>, + IsCommutable, Defs<[DSPCCond]>; + +class CMPGDU_LT_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgdu.lt.qb", + int_mips_cmpgdu_lt_qb, + NoItinerary, GPR32Opnd, DSPROpnd>, + Defs<[DSPCCond]>; + +class CMPGDU_LE_QB_DESC : CMP_EQ_QB_R3_DESC_BASE<"cmpgdu.le.qb", + int_mips_cmpgdu_le_qb, + NoItinerary, GPR32Opnd, DSPROpnd>, + Defs<[DSPCCond]>; + +// Absolute +class ABSQ_S_QB_DESC : ABSQ_S_PH_R2_DESC_BASE<"absq_s.qb", int_mips_absq_s_qb, + NoItinerary, DSPROpnd>, + Defs<[DSPOutFlag20]>; + +// Multiplication +class MUL_PH_DESC : ADDUH_QB_DESC_BASE<"mul.ph", null_frag, NoItinerary, + DSPROpnd>, IsCommutable, + Defs<[DSPOutFlag21]>; + +class MUL_S_PH_DESC : ADDUH_QB_DESC_BASE<"mul_s.ph", int_mips_mul_s_ph, + NoItinerary, DSPROpnd>, IsCommutable, + Defs<[DSPOutFlag21]>; + +class MULQ_S_W_DESC : ADDUH_QB_DESC_BASE<"mulq_s.w", int_mips_mulq_s_w, + NoItinerary, GPR32Opnd>, IsCommutable, + Defs<[DSPOutFlag21]>; + +class MULQ_RS_W_DESC : ADDUH_QB_DESC_BASE<"mulq_rs.w", int_mips_mulq_rs_w, + NoItinerary, GPR32Opnd>, IsCommutable, + Defs<[DSPOutFlag21]>; + +class MULQ_S_PH_DESC : ADDU_QB_DESC_BASE<"mulq_s.ph", int_mips_mulq_s_ph, + NoItinerary, DSPROpnd, DSPROpnd>, + IsCommutable, Defs<[DSPOutFlag21]>; + +// Dot product with accumulate/subtract +class DPA_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpa.w.ph", MipsDPA_W_PH>; + +class DPS_W_PH_DESC : DPA_W_PH_DESC_BASE<"dps.w.ph", MipsDPS_W_PH>; + +class DPAQX_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpaqx_s.w.ph", MipsDPAQX_S_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class DPAQX_SA_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpaqx_sa.w.ph", + MipsDPAQX_SA_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class DPAX_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpax.w.ph", MipsDPAX_W_PH>; + +class DPSX_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpsx.w.ph", MipsDPSX_W_PH>; + +class DPSQX_S_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpsqx_s.w.ph", MipsDPSQX_S_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class DPSQX_SA_W_PH_DESC : DPA_W_PH_DESC_BASE<"dpsqx_sa.w.ph", + MipsDPSQX_SA_W_PH>, + Defs<[DSPOutFlag16_19]>; + +class MULSA_W_PH_DESC : DPA_W_PH_DESC_BASE<"mulsa.w.ph", MipsMULSA_W_PH>; + +// Precision reduce/expand +class PRECR_QB_PH_DESC : CMP_EQ_QB_R3_DESC_BASE<"precr.qb.ph", + int_mips_precr_qb_ph, + NoItinerary, DSPROpnd, DSPROpnd>; + +class PRECR_SRA_PH_W_DESC : PRECR_SRA_PH_W_DESC_BASE<"precr_sra.ph.w", + int_mips_precr_sra_ph_w, + NoItinerary, DSPROpnd, + GPR32Opnd>; + +class PRECR_SRA_R_PH_W_DESC : PRECR_SRA_PH_W_DESC_BASE<"precr_sra_r.ph.w", + int_mips_precr_sra_r_ph_w, + NoItinerary, DSPROpnd, + GPR32Opnd>; + +// Shift +class SHRA_QB_DESC : SHLL_QB_R2_DESC_BASE<"shra.qb", null_frag, immZExt3, + NoItinerary, DSPROpnd>; + +class SHRAV_QB_DESC : SHLL_QB_R3_DESC_BASE<"shrav.qb", int_mips_shra_qb, + NoItinerary, DSPROpnd>; + +class SHRA_R_QB_DESC : SHLL_QB_R2_DESC_BASE<"shra_r.qb", int_mips_shra_r_qb, + immZExt3, NoItinerary, DSPROpnd>; + +class SHRAV_R_QB_DESC : SHLL_QB_R3_DESC_BASE<"shrav_r.qb", int_mips_shra_r_qb, + NoItinerary, DSPROpnd>; + +class SHRL_PH_DESC : SHLL_QB_R2_DESC_BASE<"shrl.ph", null_frag, immZExt4, + NoItinerary, DSPROpnd>; + +class SHRLV_PH_DESC : SHLL_QB_R3_DESC_BASE<"shrlv.ph", int_mips_shrl_ph, + NoItinerary, DSPROpnd>; + +// Misc +class APPEND_DESC : APPEND_DESC_BASE<"append", int_mips_append, immZExt5, + NoItinerary>; + +class BALIGN_DESC : APPEND_DESC_BASE<"balign", int_mips_balign, immZExt2, + NoItinerary>; + +class PREPEND_DESC : APPEND_DESC_BASE<"prepend", int_mips_prepend, immZExt5, + NoItinerary>; + +// Pseudos. +def BPOSGE32_PSEUDO : BPOSGE32_PSEUDO_DESC_BASE<int_mips_bposge32, + NoItinerary>, Uses<[DSPPos]>; + +// Instruction defs. +// MIPS DSP Rev 1 +def ADDU_QB : ADDU_QB_ENC, ADDU_QB_DESC; +def ADDU_S_QB : ADDU_S_QB_ENC, ADDU_S_QB_DESC; +def SUBU_QB : SUBU_QB_ENC, SUBU_QB_DESC; +def SUBU_S_QB : SUBU_S_QB_ENC, SUBU_S_QB_DESC; +def ADDQ_PH : ADDQ_PH_ENC, ADDQ_PH_DESC; +def ADDQ_S_PH : ADDQ_S_PH_ENC, ADDQ_S_PH_DESC; +def SUBQ_PH : SUBQ_PH_ENC, SUBQ_PH_DESC; +def SUBQ_S_PH : SUBQ_S_PH_ENC, SUBQ_S_PH_DESC; +def ADDQ_S_W : ADDQ_S_W_ENC, ADDQ_S_W_DESC; +def SUBQ_S_W : SUBQ_S_W_ENC, SUBQ_S_W_DESC; +def ADDSC : ADDSC_ENC, ADDSC_DESC; +def ADDWC : ADDWC_ENC, ADDWC_DESC; +def MODSUB : MODSUB_ENC, MODSUB_DESC; +def RADDU_W_QB : RADDU_W_QB_ENC, RADDU_W_QB_DESC; +def ABSQ_S_PH : ABSQ_S_PH_ENC, ABSQ_S_PH_DESC; +def ABSQ_S_W : ABSQ_S_W_ENC, ABSQ_S_W_DESC; +def PRECRQ_QB_PH : PRECRQ_QB_PH_ENC, PRECRQ_QB_PH_DESC; +def PRECRQ_PH_W : PRECRQ_PH_W_ENC, PRECRQ_PH_W_DESC; +def PRECRQ_RS_PH_W : PRECRQ_RS_PH_W_ENC, PRECRQ_RS_PH_W_DESC; +def PRECRQU_S_QB_PH : PRECRQU_S_QB_PH_ENC, PRECRQU_S_QB_PH_DESC; +def PRECEQ_W_PHL : PRECEQ_W_PHL_ENC, PRECEQ_W_PHL_DESC; +def PRECEQ_W_PHR : PRECEQ_W_PHR_ENC, PRECEQ_W_PHR_DESC; +def PRECEQU_PH_QBL : PRECEQU_PH_QBL_ENC, PRECEQU_PH_QBL_DESC; +def PRECEQU_PH_QBR : PRECEQU_PH_QBR_ENC, PRECEQU_PH_QBR_DESC; +def PRECEQU_PH_QBLA : PRECEQU_PH_QBLA_ENC, PRECEQU_PH_QBLA_DESC; +def PRECEQU_PH_QBRA : PRECEQU_PH_QBRA_ENC, PRECEQU_PH_QBRA_DESC; +def PRECEU_PH_QBL : PRECEU_PH_QBL_ENC, PRECEU_PH_QBL_DESC; +def PRECEU_PH_QBR : PRECEU_PH_QBR_ENC, PRECEU_PH_QBR_DESC; +def PRECEU_PH_QBLA : PRECEU_PH_QBLA_ENC, PRECEU_PH_QBLA_DESC; +def PRECEU_PH_QBRA : PRECEU_PH_QBRA_ENC, PRECEU_PH_QBRA_DESC; +def SHLL_QB : SHLL_QB_ENC, SHLL_QB_DESC; +def SHLLV_QB : SHLLV_QB_ENC, SHLLV_QB_DESC; +def SHRL_QB : SHRL_QB_ENC, SHRL_QB_DESC; +def SHRLV_QB : SHRLV_QB_ENC, SHRLV_QB_DESC; +def SHLL_PH : SHLL_PH_ENC, SHLL_PH_DESC; +def SHLLV_PH : SHLLV_PH_ENC, SHLLV_PH_DESC; +def SHLL_S_PH : SHLL_S_PH_ENC, SHLL_S_PH_DESC; +def SHLLV_S_PH : SHLLV_S_PH_ENC, SHLLV_S_PH_DESC; +def SHRA_PH : SHRA_PH_ENC, SHRA_PH_DESC; +def SHRAV_PH : SHRAV_PH_ENC, SHRAV_PH_DESC; +def SHRA_R_PH : SHRA_R_PH_ENC, SHRA_R_PH_DESC; +def SHRAV_R_PH : SHRAV_R_PH_ENC, SHRAV_R_PH_DESC; +def SHLL_S_W : SHLL_S_W_ENC, SHLL_S_W_DESC; +def SHLLV_S_W : SHLLV_S_W_ENC, SHLLV_S_W_DESC; +def SHRA_R_W : SHRA_R_W_ENC, SHRA_R_W_DESC; +def SHRAV_R_W : SHRAV_R_W_ENC, SHRAV_R_W_DESC; +def MULEU_S_PH_QBL : MULEU_S_PH_QBL_ENC, MULEU_S_PH_QBL_DESC; +def MULEU_S_PH_QBR : MULEU_S_PH_QBR_ENC, MULEU_S_PH_QBR_DESC; +def MULEQ_S_W_PHL : MULEQ_S_W_PHL_ENC, MULEQ_S_W_PHL_DESC; +def MULEQ_S_W_PHR : MULEQ_S_W_PHR_ENC, MULEQ_S_W_PHR_DESC; +def MULQ_RS_PH : MULQ_RS_PH_ENC, MULQ_RS_PH_DESC; +def MULSAQ_S_W_PH : MULSAQ_S_W_PH_ENC, MULSAQ_S_W_PH_DESC; +def MAQ_S_W_PHL : MAQ_S_W_PHL_ENC, MAQ_S_W_PHL_DESC; +def MAQ_S_W_PHR : MAQ_S_W_PHR_ENC, MAQ_S_W_PHR_DESC; +def MAQ_SA_W_PHL : MAQ_SA_W_PHL_ENC, MAQ_SA_W_PHL_DESC; +def MAQ_SA_W_PHR : MAQ_SA_W_PHR_ENC, MAQ_SA_W_PHR_DESC; +def MFHI_DSP : MFHI_ENC, MFHI_DESC; +def MFLO_DSP : MFLO_ENC, MFLO_DESC; +def MTHI_DSP : MTHI_ENC, MTHI_DESC; +def MTLO_DSP : MTLO_ENC, MTLO_DESC; +def DPAU_H_QBL : DPAU_H_QBL_ENC, DPAU_H_QBL_DESC; +def DPAU_H_QBR : DPAU_H_QBR_ENC, DPAU_H_QBR_DESC; +def DPSU_H_QBL : DPSU_H_QBL_ENC, DPSU_H_QBL_DESC; +def DPSU_H_QBR : DPSU_H_QBR_ENC, DPSU_H_QBR_DESC; +def DPAQ_S_W_PH : DPAQ_S_W_PH_ENC, DPAQ_S_W_PH_DESC; +def DPSQ_S_W_PH : DPSQ_S_W_PH_ENC, DPSQ_S_W_PH_DESC; +def DPAQ_SA_L_W : DPAQ_SA_L_W_ENC, DPAQ_SA_L_W_DESC; +def DPSQ_SA_L_W : DPSQ_SA_L_W_ENC, DPSQ_SA_L_W_DESC; +def MULT_DSP : MULT_DSP_ENC, MULT_DSP_DESC; +def MULTU_DSP : MULTU_DSP_ENC, MULTU_DSP_DESC; +def MADD_DSP : MADD_DSP_ENC, MADD_DSP_DESC; +def MADDU_DSP : MADDU_DSP_ENC, MADDU_DSP_DESC; +def MSUB_DSP : MSUB_DSP_ENC, MSUB_DSP_DESC; +def MSUBU_DSP : MSUBU_DSP_ENC, MSUBU_DSP_DESC; +def CMPU_EQ_QB : CMPU_EQ_QB_ENC, CMPU_EQ_QB_DESC; +def CMPU_LT_QB : CMPU_LT_QB_ENC, CMPU_LT_QB_DESC; +def CMPU_LE_QB : CMPU_LE_QB_ENC, CMPU_LE_QB_DESC; +def CMPGU_EQ_QB : CMPGU_EQ_QB_ENC, CMPGU_EQ_QB_DESC; +def CMPGU_LT_QB : CMPGU_LT_QB_ENC, CMPGU_LT_QB_DESC; +def CMPGU_LE_QB : CMPGU_LE_QB_ENC, CMPGU_LE_QB_DESC; +def CMP_EQ_PH : CMP_EQ_PH_ENC, CMP_EQ_PH_DESC; +def CMP_LT_PH : CMP_LT_PH_ENC, CMP_LT_PH_DESC; +def CMP_LE_PH : CMP_LE_PH_ENC, CMP_LE_PH_DESC; +def BITREV : BITREV_ENC, BITREV_DESC; +def PACKRL_PH : PACKRL_PH_ENC, PACKRL_PH_DESC; +def REPL_QB : REPL_QB_ENC, REPL_QB_DESC; +def REPL_PH : REPL_PH_ENC, REPL_PH_DESC; +def REPLV_QB : REPLV_QB_ENC, REPLV_QB_DESC; +def REPLV_PH : REPLV_PH_ENC, REPLV_PH_DESC; +def PICK_QB : PICK_QB_ENC, PICK_QB_DESC; +def PICK_PH : PICK_PH_ENC, PICK_PH_DESC; +def LWX : LWX_ENC, LWX_DESC; +def LHX : LHX_ENC, LHX_DESC; +def LBUX : LBUX_ENC, LBUX_DESC; +def BPOSGE32 : BPOSGE32_ENC, BPOSGE32_DESC; +def INSV : INSV_ENC, INSV_DESC; +def EXTP : EXTP_ENC, EXTP_DESC; +def EXTPV : EXTPV_ENC, EXTPV_DESC; +def EXTPDP : EXTPDP_ENC, EXTPDP_DESC; +def EXTPDPV : EXTPDPV_ENC, EXTPDPV_DESC; +def EXTR_W : EXTR_W_ENC, EXTR_W_DESC; +def EXTRV_W : EXTRV_W_ENC, EXTRV_W_DESC; +def EXTR_R_W : EXTR_R_W_ENC, EXTR_R_W_DESC; +def EXTRV_R_W : EXTRV_R_W_ENC, EXTRV_R_W_DESC; +def EXTR_RS_W : EXTR_RS_W_ENC, EXTR_RS_W_DESC; +def EXTRV_RS_W : EXTRV_RS_W_ENC, EXTRV_RS_W_DESC; +def EXTR_S_H : EXTR_S_H_ENC, EXTR_S_H_DESC; +def EXTRV_S_H : EXTRV_S_H_ENC, EXTRV_S_H_DESC; +def SHILO : SHILO_ENC, SHILO_DESC; +def SHILOV : SHILOV_ENC, SHILOV_DESC; +def MTHLIP : MTHLIP_ENC, MTHLIP_DESC; +def RDDSP : RDDSP_ENC, RDDSP_DESC; +def WRDSP : WRDSP_ENC, WRDSP_DESC; + +// MIPS DSP Rev 2 +let Predicates = [HasDSPR2] in { + +def ADDU_PH : ADDU_PH_ENC, ADDU_PH_DESC; +def ADDU_S_PH : ADDU_S_PH_ENC, ADDU_S_PH_DESC; +def SUBU_PH : SUBU_PH_ENC, SUBU_PH_DESC; +def SUBU_S_PH : SUBU_S_PH_ENC, SUBU_S_PH_DESC; +def CMPGDU_EQ_QB : CMPGDU_EQ_QB_ENC, CMPGDU_EQ_QB_DESC; +def CMPGDU_LT_QB : CMPGDU_LT_QB_ENC, CMPGDU_LT_QB_DESC; +def CMPGDU_LE_QB : CMPGDU_LE_QB_ENC, CMPGDU_LE_QB_DESC; +def ABSQ_S_QB : ABSQ_S_QB_ENC, ABSQ_S_QB_DESC; +def ADDUH_QB : ADDUH_QB_ENC, ADDUH_QB_DESC; +def ADDUH_R_QB : ADDUH_R_QB_ENC, ADDUH_R_QB_DESC; +def SUBUH_QB : SUBUH_QB_ENC, SUBUH_QB_DESC; +def SUBUH_R_QB : SUBUH_R_QB_ENC, SUBUH_R_QB_DESC; +def ADDQH_PH : ADDQH_PH_ENC, ADDQH_PH_DESC; +def ADDQH_R_PH : ADDQH_R_PH_ENC, ADDQH_R_PH_DESC; +def SUBQH_PH : SUBQH_PH_ENC, SUBQH_PH_DESC; +def SUBQH_R_PH : SUBQH_R_PH_ENC, SUBQH_R_PH_DESC; +def ADDQH_W : ADDQH_W_ENC, ADDQH_W_DESC; +def ADDQH_R_W : ADDQH_R_W_ENC, ADDQH_R_W_DESC; +def SUBQH_W : SUBQH_W_ENC, SUBQH_W_DESC; +def SUBQH_R_W : SUBQH_R_W_ENC, SUBQH_R_W_DESC; +def MUL_PH : MUL_PH_ENC, MUL_PH_DESC; +def MUL_S_PH : MUL_S_PH_ENC, MUL_S_PH_DESC; +def MULQ_S_W : MULQ_S_W_ENC, MULQ_S_W_DESC; +def MULQ_RS_W : MULQ_RS_W_ENC, MULQ_RS_W_DESC; +def MULQ_S_PH : MULQ_S_PH_ENC, MULQ_S_PH_DESC; +def DPA_W_PH : DPA_W_PH_ENC, DPA_W_PH_DESC; +def DPS_W_PH : DPS_W_PH_ENC, DPS_W_PH_DESC; +def DPAQX_S_W_PH : DPAQX_S_W_PH_ENC, DPAQX_S_W_PH_DESC; +def DPAQX_SA_W_PH : DPAQX_SA_W_PH_ENC, DPAQX_SA_W_PH_DESC; +def DPAX_W_PH : DPAX_W_PH_ENC, DPAX_W_PH_DESC; +def DPSX_W_PH : DPSX_W_PH_ENC, DPSX_W_PH_DESC; +def DPSQX_S_W_PH : DPSQX_S_W_PH_ENC, DPSQX_S_W_PH_DESC; +def DPSQX_SA_W_PH : DPSQX_SA_W_PH_ENC, DPSQX_SA_W_PH_DESC; +def MULSA_W_PH : MULSA_W_PH_ENC, MULSA_W_PH_DESC; +def PRECR_QB_PH : PRECR_QB_PH_ENC, PRECR_QB_PH_DESC; +def PRECR_SRA_PH_W : PRECR_SRA_PH_W_ENC, PRECR_SRA_PH_W_DESC; +def PRECR_SRA_R_PH_W : PRECR_SRA_R_PH_W_ENC, PRECR_SRA_R_PH_W_DESC; +def SHRA_QB : SHRA_QB_ENC, SHRA_QB_DESC; +def SHRAV_QB : SHRAV_QB_ENC, SHRAV_QB_DESC; +def SHRA_R_QB : SHRA_R_QB_ENC, SHRA_R_QB_DESC; +def SHRAV_R_QB : SHRAV_R_QB_ENC, SHRAV_R_QB_DESC; +def SHRL_PH : SHRL_PH_ENC, SHRL_PH_DESC; +def SHRLV_PH : SHRLV_PH_ENC, SHRLV_PH_DESC; +def APPEND : APPEND_ENC, APPEND_DESC; +def BALIGN : BALIGN_ENC, BALIGN_DESC; +def PREPEND : PREPEND_ENC, PREPEND_DESC; + +} + +// Pseudos. +let isPseudo = 1, isCodeGenOnly = 1 in { + // Pseudo instructions for loading and storing accumulator registers. + def LOAD_ACC64DSP : Load<"", ACC64DSPOpnd>; + def STORE_ACC64DSP : Store<"", ACC64DSPOpnd>; + + // Pseudos for loading and storing ccond field of DSP control register. + def LOAD_CCOND_DSP : Load<"load_ccond_dsp", DSPCC>; + def STORE_CCOND_DSP : Store<"store_ccond_dsp", DSPCC>; +} + +// Pseudo CMP and PICK instructions. +class PseudoCMP<Instruction RealInst> : + PseudoDSP<(outs DSPCC:$cmp), (ins DSPROpnd:$rs, DSPROpnd:$rt), []>, + PseudoInstExpansion<(RealInst DSPROpnd:$rs, DSPROpnd:$rt)>, NeverHasSideEffects; + +class PseudoPICK<Instruction RealInst> : + PseudoDSP<(outs DSPROpnd:$rd), (ins DSPCC:$cmp, DSPROpnd:$rs, DSPROpnd:$rt), []>, + PseudoInstExpansion<(RealInst DSPROpnd:$rd, DSPROpnd:$rs, DSPROpnd:$rt)>, + NeverHasSideEffects; + +def PseudoCMP_EQ_PH : PseudoCMP<CMP_EQ_PH>; +def PseudoCMP_LT_PH : PseudoCMP<CMP_LT_PH>; +def PseudoCMP_LE_PH : PseudoCMP<CMP_LE_PH>; +def PseudoCMPU_EQ_QB : PseudoCMP<CMPU_EQ_QB>; +def PseudoCMPU_LT_QB : PseudoCMP<CMPU_LT_QB>; +def PseudoCMPU_LE_QB : PseudoCMP<CMPU_LE_QB>; + +def PseudoPICK_PH : PseudoPICK<PICK_PH>; +def PseudoPICK_QB : PseudoPICK<PICK_QB>; + +def PseudoMTLOHI_DSP : PseudoMTLOHI<ACC64DSP, GPR32>; + +// Patterns. +class DSPPat<dag pattern, dag result, Predicate pred = HasDSP> : + Pat<pattern, result>, Requires<[pred]>; + +class BitconvertPat<ValueType DstVT, ValueType SrcVT, RegisterClass DstRC, + RegisterClass SrcRC> : + DSPPat<(DstVT (bitconvert (SrcVT SrcRC:$src))), + (COPY_TO_REGCLASS SrcRC:$src, DstRC)>; + +def : BitconvertPat<i32, v2i16, GPR32, DSPR>; +def : BitconvertPat<i32, v4i8, GPR32, DSPR>; +def : BitconvertPat<v2i16, i32, DSPR, GPR32>; +def : BitconvertPat<v4i8, i32, DSPR, GPR32>; + +def : DSPPat<(v2i16 (load addr:$a)), + (v2i16 (COPY_TO_REGCLASS (LW addr:$a), DSPR))>; +def : DSPPat<(v4i8 (load addr:$a)), + (v4i8 (COPY_TO_REGCLASS (LW addr:$a), DSPR))>; +def : DSPPat<(store (v2i16 DSPR:$val), addr:$a), + (SW (COPY_TO_REGCLASS DSPR:$val, GPR32), addr:$a)>; +def : DSPPat<(store (v4i8 DSPR:$val), addr:$a), + (SW (COPY_TO_REGCLASS DSPR:$val, GPR32), addr:$a)>; + +// Binary operations. +class DSPBinPat<Instruction Inst, ValueType ValTy, SDPatternOperator Node, + Predicate Pred = HasDSP> : + DSPPat<(Node ValTy:$a, ValTy:$b), (Inst ValTy:$a, ValTy:$b), Pred>; + +def : DSPBinPat<ADDQ_PH, v2i16, int_mips_addq_ph>; +def : DSPBinPat<ADDQ_PH, v2i16, add>; +def : DSPBinPat<SUBQ_PH, v2i16, int_mips_subq_ph>; +def : DSPBinPat<SUBQ_PH, v2i16, sub>; +def : DSPBinPat<MUL_PH, v2i16, int_mips_mul_ph, HasDSPR2>; +def : DSPBinPat<MUL_PH, v2i16, mul, HasDSPR2>; +def : DSPBinPat<ADDU_QB, v4i8, int_mips_addu_qb>; +def : DSPBinPat<ADDU_QB, v4i8, add>; +def : DSPBinPat<SUBU_QB, v4i8, int_mips_subu_qb>; +def : DSPBinPat<SUBU_QB, v4i8, sub>; +def : DSPBinPat<ADDSC, i32, int_mips_addsc>; +def : DSPBinPat<ADDSC, i32, addc>; +def : DSPBinPat<ADDWC, i32, int_mips_addwc>; +def : DSPBinPat<ADDWC, i32, adde>; + +// Shift immediate patterns. +class DSPShiftPat<Instruction Inst, ValueType ValTy, SDPatternOperator Node, + SDPatternOperator Imm, Predicate Pred = HasDSP> : + DSPPat<(Node ValTy:$a, Imm:$shamt), (Inst ValTy:$a, Imm:$shamt), Pred>; + +def : DSPShiftPat<SHLL_PH, v2i16, MipsSHLL_DSP, imm>; +def : DSPShiftPat<SHRA_PH, v2i16, MipsSHRA_DSP, imm>; +def : DSPShiftPat<SHRL_PH, v2i16, MipsSHRL_DSP, imm, HasDSPR2>; +def : DSPShiftPat<SHLL_PH, v2i16, int_mips_shll_ph, immZExt4>; +def : DSPShiftPat<SHRA_PH, v2i16, int_mips_shra_ph, immZExt4>; +def : DSPShiftPat<SHRL_PH, v2i16, int_mips_shrl_ph, immZExt4, HasDSPR2>; +def : DSPShiftPat<SHLL_QB, v4i8, MipsSHLL_DSP, imm>; +def : DSPShiftPat<SHRA_QB, v4i8, MipsSHRA_DSP, imm, HasDSPR2>; +def : DSPShiftPat<SHRL_QB, v4i8, MipsSHRL_DSP, imm>; +def : DSPShiftPat<SHLL_QB, v4i8, int_mips_shll_qb, immZExt3>; +def : DSPShiftPat<SHRA_QB, v4i8, int_mips_shra_qb, immZExt3, HasDSPR2>; +def : DSPShiftPat<SHRL_QB, v4i8, int_mips_shrl_qb, immZExt3>; + +// SETCC/SELECT_CC patterns. +class DSPSetCCPat<Instruction Cmp, Instruction Pick, ValueType ValTy, + CondCode CC> : + DSPPat<(ValTy (MipsSETCC_DSP ValTy:$a, ValTy:$b, CC)), + (ValTy (Pick (ValTy (Cmp ValTy:$a, ValTy:$b)), + (ValTy (COPY_TO_REGCLASS (ADDiu ZERO, -1), DSPR)), + (ValTy ZERO)))>; + +class DSPSetCCPatInv<Instruction Cmp, Instruction Pick, ValueType ValTy, + CondCode CC> : + DSPPat<(ValTy (MipsSETCC_DSP ValTy:$a, ValTy:$b, CC)), + (ValTy (Pick (ValTy (Cmp ValTy:$a, ValTy:$b)), + (ValTy ZERO), + (ValTy (COPY_TO_REGCLASS (ADDiu ZERO, -1), DSPR))))>; + +class DSPSelectCCPat<Instruction Cmp, Instruction Pick, ValueType ValTy, + CondCode CC> : + DSPPat<(ValTy (MipsSELECT_CC_DSP ValTy:$a, ValTy:$b, ValTy:$c, ValTy:$d, CC)), + (ValTy (Pick (ValTy (Cmp ValTy:$a, ValTy:$b)), $c, $d))>; + +class DSPSelectCCPatInv<Instruction Cmp, Instruction Pick, ValueType ValTy, + CondCode CC> : + DSPPat<(ValTy (MipsSELECT_CC_DSP ValTy:$a, ValTy:$b, ValTy:$c, ValTy:$d, CC)), + (ValTy (Pick (ValTy (Cmp ValTy:$a, ValTy:$b)), $d, $c))>; + +def : DSPSetCCPat<PseudoCMP_EQ_PH, PseudoPICK_PH, v2i16, SETEQ>; +def : DSPSetCCPat<PseudoCMP_LT_PH, PseudoPICK_PH, v2i16, SETLT>; +def : DSPSetCCPat<PseudoCMP_LE_PH, PseudoPICK_PH, v2i16, SETLE>; +def : DSPSetCCPatInv<PseudoCMP_EQ_PH, PseudoPICK_PH, v2i16, SETNE>; +def : DSPSetCCPatInv<PseudoCMP_LT_PH, PseudoPICK_PH, v2i16, SETGE>; +def : DSPSetCCPatInv<PseudoCMP_LE_PH, PseudoPICK_PH, v2i16, SETGT>; +def : DSPSetCCPat<PseudoCMPU_EQ_QB, PseudoPICK_QB, v4i8, SETEQ>; +def : DSPSetCCPat<PseudoCMPU_LT_QB, PseudoPICK_QB, v4i8, SETULT>; +def : DSPSetCCPat<PseudoCMPU_LE_QB, PseudoPICK_QB, v4i8, SETULE>; +def : DSPSetCCPatInv<PseudoCMPU_EQ_QB, PseudoPICK_QB, v4i8, SETNE>; +def : DSPSetCCPatInv<PseudoCMPU_LT_QB, PseudoPICK_QB, v4i8, SETUGE>; +def : DSPSetCCPatInv<PseudoCMPU_LE_QB, PseudoPICK_QB, v4i8, SETUGT>; + +def : DSPSelectCCPat<PseudoCMP_EQ_PH, PseudoPICK_PH, v2i16, SETEQ>; +def : DSPSelectCCPat<PseudoCMP_LT_PH, PseudoPICK_PH, v2i16, SETLT>; +def : DSPSelectCCPat<PseudoCMP_LE_PH, PseudoPICK_PH, v2i16, SETLE>; +def : DSPSelectCCPatInv<PseudoCMP_EQ_PH, PseudoPICK_PH, v2i16, SETNE>; +def : DSPSelectCCPatInv<PseudoCMP_LT_PH, PseudoPICK_PH, v2i16, SETGE>; +def : DSPSelectCCPatInv<PseudoCMP_LE_PH, PseudoPICK_PH, v2i16, SETGT>; +def : DSPSelectCCPat<PseudoCMPU_EQ_QB, PseudoPICK_QB, v4i8, SETEQ>; +def : DSPSelectCCPat<PseudoCMPU_LT_QB, PseudoPICK_QB, v4i8, SETULT>; +def : DSPSelectCCPat<PseudoCMPU_LE_QB, PseudoPICK_QB, v4i8, SETULE>; +def : DSPSelectCCPatInv<PseudoCMPU_EQ_QB, PseudoPICK_QB, v4i8, SETNE>; +def : DSPSelectCCPatInv<PseudoCMPU_LT_QB, PseudoPICK_QB, v4i8, SETUGE>; +def : DSPSelectCCPatInv<PseudoCMPU_LE_QB, PseudoPICK_QB, v4i8, SETUGT>; + +// Extr patterns. +class EXTR_W_TY1_R2_Pat<SDPatternOperator OpNode, Instruction Instr> : + DSPPat<(i32 (OpNode GPR32:$rs, ACC64DSP:$ac)), + (Instr ACC64DSP:$ac, GPR32:$rs)>; + +class EXTR_W_TY1_R1_Pat<SDPatternOperator OpNode, Instruction Instr> : + DSPPat<(i32 (OpNode immZExt5:$shift, ACC64DSP:$ac)), + (Instr ACC64DSP:$ac, immZExt5:$shift)>; + +def : EXTR_W_TY1_R1_Pat<MipsEXTP, EXTP>; +def : EXTR_W_TY1_R2_Pat<MipsEXTP, EXTPV>; +def : EXTR_W_TY1_R1_Pat<MipsEXTPDP, EXTPDP>; +def : EXTR_W_TY1_R2_Pat<MipsEXTPDP, EXTPDPV>; +def : EXTR_W_TY1_R1_Pat<MipsEXTR_W, EXTR_W>; +def : EXTR_W_TY1_R2_Pat<MipsEXTR_W, EXTRV_W>; +def : EXTR_W_TY1_R1_Pat<MipsEXTR_R_W, EXTR_R_W>; +def : EXTR_W_TY1_R2_Pat<MipsEXTR_R_W, EXTRV_R_W>; +def : EXTR_W_TY1_R1_Pat<MipsEXTR_RS_W, EXTR_RS_W>; +def : EXTR_W_TY1_R2_Pat<MipsEXTR_RS_W, EXTRV_RS_W>; +def : EXTR_W_TY1_R1_Pat<MipsEXTR_S_H, EXTR_S_H>; +def : EXTR_W_TY1_R2_Pat<MipsEXTR_S_H, EXTRV_S_H>; + +// Indexed load patterns. +class IndexedLoadPat<SDPatternOperator LoadNode, Instruction Instr> : + DSPPat<(i32 (LoadNode (add i32:$base, i32:$index))), + (Instr i32:$base, i32:$index)>; + +let AddedComplexity = 20 in { + def : IndexedLoadPat<zextloadi8, LBUX>; + def : IndexedLoadPat<sextloadi16, LHX>; + def : IndexedLoadPat<load, LWX>; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp b/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp new file mode 100644 index 000000000000..ffbd83b1bbbf --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp @@ -0,0 +1,719 @@ +//===-- MipsDelaySlotFiller.cpp - Mips Delay Slot Filler ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Simple pass to fill delay slots with useful instructions. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "delay-slot-filler" + +#include "Mips.h" +#include "MipsInstrInfo.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/CodeGen/MachineBranchProbabilityInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" + +using namespace llvm; + +STATISTIC(FilledSlots, "Number of delay slots filled"); +STATISTIC(UsefulSlots, "Number of delay slots filled with instructions that" + " are not NOP."); + +static cl::opt<bool> DisableDelaySlotFiller( + "disable-mips-delay-filler", + cl::init(false), + cl::desc("Fill all delay slots with NOPs."), + cl::Hidden); + +static cl::opt<bool> DisableForwardSearch( + "disable-mips-df-forward-search", + cl::init(true), + cl::desc("Disallow MIPS delay filler to search forward."), + cl::Hidden); + +static cl::opt<bool> DisableSuccBBSearch( + "disable-mips-df-succbb-search", + cl::init(true), + cl::desc("Disallow MIPS delay filler to search successor basic blocks."), + cl::Hidden); + +static cl::opt<bool> DisableBackwardSearch( + "disable-mips-df-backward-search", + cl::init(false), + cl::desc("Disallow MIPS delay filler to search backward."), + cl::Hidden); + +namespace { + typedef MachineBasicBlock::iterator Iter; + typedef MachineBasicBlock::reverse_iterator ReverseIter; + typedef SmallDenseMap<MachineBasicBlock*, MachineInstr*, 2> BB2BrMap; + + /// \brief A functor comparing edge weight of two blocks. + struct CmpWeight { + CmpWeight(const MachineBasicBlock &S, + const MachineBranchProbabilityInfo &P) : Src(S), Prob(P) {} + + bool operator()(const MachineBasicBlock *Dst0, + const MachineBasicBlock *Dst1) const { + return Prob.getEdgeWeight(&Src, Dst0) < Prob.getEdgeWeight(&Src, Dst1); + } + + const MachineBasicBlock &Src; + const MachineBranchProbabilityInfo &Prob; + }; + + class RegDefsUses { + public: + RegDefsUses(TargetMachine &TM); + void init(const MachineInstr &MI); + + /// This function sets all caller-saved registers in Defs. + void setCallerSaved(const MachineInstr &MI); + + /// This function sets all unallocatable registers in Defs. + void setUnallocatableRegs(const MachineFunction &MF); + + /// Set bits in Uses corresponding to MBB's live-out registers except for + /// the registers that are live-in to SuccBB. + void addLiveOut(const MachineBasicBlock &MBB, + const MachineBasicBlock &SuccBB); + + bool update(const MachineInstr &MI, unsigned Begin, unsigned End); + + private: + bool checkRegDefsUses(BitVector &NewDefs, BitVector &NewUses, unsigned Reg, + bool IsDef) const; + + /// Returns true if Reg or its alias is in RegSet. + bool isRegInSet(const BitVector &RegSet, unsigned Reg) const; + + const TargetRegisterInfo &TRI; + BitVector Defs, Uses; + }; + + /// Base class for inspecting loads and stores. + class InspectMemInstr { + public: + InspectMemInstr(bool ForbidMemInstr_) + : OrigSeenLoad(false), OrigSeenStore(false), SeenLoad(false), + SeenStore(false), ForbidMemInstr(ForbidMemInstr_) {} + + /// Return true if MI cannot be moved to delay slot. + bool hasHazard(const MachineInstr &MI); + + virtual ~InspectMemInstr() {} + + protected: + /// Flags indicating whether loads or stores have been seen. + bool OrigSeenLoad, OrigSeenStore, SeenLoad, SeenStore; + + /// Memory instructions are not allowed to move to delay slot if this flag + /// is true. + bool ForbidMemInstr; + + private: + virtual bool hasHazard_(const MachineInstr &MI) = 0; + }; + + /// This subclass rejects any memory instructions. + class NoMemInstr : public InspectMemInstr { + public: + NoMemInstr() : InspectMemInstr(true) {} + private: + virtual bool hasHazard_(const MachineInstr &MI) { return true; } + }; + + /// This subclass accepts loads from stacks and constant loads. + class LoadFromStackOrConst : public InspectMemInstr { + public: + LoadFromStackOrConst() : InspectMemInstr(false) {} + private: + virtual bool hasHazard_(const MachineInstr &MI); + }; + + /// This subclass uses memory dependence information to determine whether a + /// memory instruction can be moved to a delay slot. + class MemDefsUses : public InspectMemInstr { + public: + MemDefsUses(const MachineFrameInfo *MFI); + + private: + virtual bool hasHazard_(const MachineInstr &MI); + + /// Update Defs and Uses. Return true if there exist dependences that + /// disqualify the delay slot candidate between V and values in Uses and + /// Defs. + bool updateDefsUses(const Value *V, bool MayStore); + + /// Get the list of underlying objects of MI's memory operand. + bool getUnderlyingObjects(const MachineInstr &MI, + SmallVectorImpl<const Value *> &Objects) const; + + const MachineFrameInfo *MFI; + SmallPtrSet<const Value*, 4> Uses, Defs; + + /// Flags indicating whether loads or stores with no underlying objects have + /// been seen. + bool SeenNoObjLoad, SeenNoObjStore; + }; + + class Filler : public MachineFunctionPass { + public: + Filler(TargetMachine &tm) + : MachineFunctionPass(ID), TM(tm) { } + + virtual const char *getPassName() const { + return "Mips Delay Slot Filler"; + } + + bool runOnMachineFunction(MachineFunction &F) { + bool Changed = false; + for (MachineFunction::iterator FI = F.begin(), FE = F.end(); + FI != FE; ++FI) + Changed |= runOnMachineBasicBlock(*FI); + return Changed; + } + + void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<MachineBranchProbabilityInfo>(); + MachineFunctionPass::getAnalysisUsage(AU); + } + + private: + bool runOnMachineBasicBlock(MachineBasicBlock &MBB); + + /// This function checks if it is valid to move Candidate to the delay slot + /// and returns true if it isn't. It also updates memory and register + /// dependence information. + bool delayHasHazard(const MachineInstr &Candidate, RegDefsUses &RegDU, + InspectMemInstr &IM) const; + + /// This function searches range [Begin, End) for an instruction that can be + /// moved to the delay slot. Returns true on success. + template<typename IterTy> + bool searchRange(MachineBasicBlock &MBB, IterTy Begin, IterTy End, + RegDefsUses &RegDU, InspectMemInstr &IM, + IterTy &Filler) const; + + /// This function searches in the backward direction for an instruction that + /// can be moved to the delay slot. Returns true on success. + bool searchBackward(MachineBasicBlock &MBB, Iter Slot) const; + + /// This function searches MBB in the forward direction for an instruction + /// that can be moved to the delay slot. Returns true on success. + bool searchForward(MachineBasicBlock &MBB, Iter Slot) const; + + /// This function searches one of MBB's successor blocks for an instruction + /// that can be moved to the delay slot and inserts clones of the + /// instruction into the successor's predecessor blocks. + bool searchSuccBBs(MachineBasicBlock &MBB, Iter Slot) const; + + /// Pick a successor block of MBB. Return NULL if MBB doesn't have a + /// successor block that is not a landing pad. + MachineBasicBlock *selectSuccBB(MachineBasicBlock &B) const; + + /// This function analyzes MBB and returns an instruction with an unoccupied + /// slot that branches to Dst. + std::pair<MipsInstrInfo::BranchType, MachineInstr *> + getBranch(MachineBasicBlock &MBB, const MachineBasicBlock &Dst) const; + + /// Examine Pred and see if it is possible to insert an instruction into + /// one of its branches delay slot or its end. + bool examinePred(MachineBasicBlock &Pred, const MachineBasicBlock &Succ, + RegDefsUses &RegDU, bool &HasMultipleSuccs, + BB2BrMap &BrMap) const; + + bool terminateSearch(const MachineInstr &Candidate) const; + + TargetMachine &TM; + + static char ID; + }; + char Filler::ID = 0; +} // end of anonymous namespace + +static bool hasUnoccupiedSlot(const MachineInstr *MI) { + return MI->hasDelaySlot() && !MI->isBundledWithSucc(); +} + +/// This function inserts clones of Filler into predecessor blocks. +static void insertDelayFiller(Iter Filler, const BB2BrMap &BrMap) { + MachineFunction *MF = Filler->getParent()->getParent(); + + for (BB2BrMap::const_iterator I = BrMap.begin(); I != BrMap.end(); ++I) { + if (I->second) { + MIBundleBuilder(I->second).append(MF->CloneMachineInstr(&*Filler)); + ++UsefulSlots; + } else { + I->first->insert(I->first->end(), MF->CloneMachineInstr(&*Filler)); + } + } +} + +/// This function adds registers Filler defines to MBB's live-in register list. +static void addLiveInRegs(Iter Filler, MachineBasicBlock &MBB) { + for (unsigned I = 0, E = Filler->getNumOperands(); I != E; ++I) { + const MachineOperand &MO = Filler->getOperand(I); + unsigned R; + + if (!MO.isReg() || !MO.isDef() || !(R = MO.getReg())) + continue; + +#ifndef NDEBUG + const MachineFunction &MF = *MBB.getParent(); + assert(MF.getTarget().getRegisterInfo()->getAllocatableSet(MF).test(R) && + "Shouldn't move an instruction with unallocatable registers across " + "basic block boundaries."); +#endif + + if (!MBB.isLiveIn(R)) + MBB.addLiveIn(R); + } +} + +RegDefsUses::RegDefsUses(TargetMachine &TM) + : TRI(*TM.getRegisterInfo()), Defs(TRI.getNumRegs(), false), + Uses(TRI.getNumRegs(), false) {} + +void RegDefsUses::init(const MachineInstr &MI) { + // Add all register operands which are explicit and non-variadic. + update(MI, 0, MI.getDesc().getNumOperands()); + + // If MI is a call, add RA to Defs to prevent users of RA from going into + // delay slot. + if (MI.isCall()) + Defs.set(Mips::RA); + + // Add all implicit register operands of branch instructions except + // register AT. + if (MI.isBranch()) { + update(MI, MI.getDesc().getNumOperands(), MI.getNumOperands()); + Defs.reset(Mips::AT); + } +} + +void RegDefsUses::setCallerSaved(const MachineInstr &MI) { + assert(MI.isCall()); + + // If MI is a call, add all caller-saved registers to Defs. + BitVector CallerSavedRegs(TRI.getNumRegs(), true); + + CallerSavedRegs.reset(Mips::ZERO); + CallerSavedRegs.reset(Mips::ZERO_64); + + for (const MCPhysReg *R = TRI.getCalleeSavedRegs(); *R; ++R) + for (MCRegAliasIterator AI(*R, &TRI, true); AI.isValid(); ++AI) + CallerSavedRegs.reset(*AI); + + Defs |= CallerSavedRegs; +} + +void RegDefsUses::setUnallocatableRegs(const MachineFunction &MF) { + BitVector AllocSet = TRI.getAllocatableSet(MF); + + for (int R = AllocSet.find_first(); R != -1; R = AllocSet.find_next(R)) + for (MCRegAliasIterator AI(R, &TRI, false); AI.isValid(); ++AI) + AllocSet.set(*AI); + + AllocSet.set(Mips::ZERO); + AllocSet.set(Mips::ZERO_64); + + Defs |= AllocSet.flip(); +} + +void RegDefsUses::addLiveOut(const MachineBasicBlock &MBB, + const MachineBasicBlock &SuccBB) { + for (MachineBasicBlock::const_succ_iterator SI = MBB.succ_begin(), + SE = MBB.succ_end(); SI != SE; ++SI) + if (*SI != &SuccBB) + for (MachineBasicBlock::livein_iterator LI = (*SI)->livein_begin(), + LE = (*SI)->livein_end(); LI != LE; ++LI) + Uses.set(*LI); +} + +bool RegDefsUses::update(const MachineInstr &MI, unsigned Begin, unsigned End) { + BitVector NewDefs(TRI.getNumRegs()), NewUses(TRI.getNumRegs()); + bool HasHazard = false; + + for (unsigned I = Begin; I != End; ++I) { + const MachineOperand &MO = MI.getOperand(I); + + if (MO.isReg() && MO.getReg()) + HasHazard |= checkRegDefsUses(NewDefs, NewUses, MO.getReg(), MO.isDef()); + } + + Defs |= NewDefs; + Uses |= NewUses; + + return HasHazard; +} + +bool RegDefsUses::checkRegDefsUses(BitVector &NewDefs, BitVector &NewUses, + unsigned Reg, bool IsDef) const { + if (IsDef) { + NewDefs.set(Reg); + // check whether Reg has already been defined or used. + return (isRegInSet(Defs, Reg) || isRegInSet(Uses, Reg)); + } + + NewUses.set(Reg); + // check whether Reg has already been defined. + return isRegInSet(Defs, Reg); +} + +bool RegDefsUses::isRegInSet(const BitVector &RegSet, unsigned Reg) const { + // Check Reg and all aliased Registers. + for (MCRegAliasIterator AI(Reg, &TRI, true); AI.isValid(); ++AI) + if (RegSet.test(*AI)) + return true; + return false; +} + +bool InspectMemInstr::hasHazard(const MachineInstr &MI) { + if (!MI.mayStore() && !MI.mayLoad()) + return false; + + if (ForbidMemInstr) + return true; + + OrigSeenLoad = SeenLoad; + OrigSeenStore = SeenStore; + SeenLoad |= MI.mayLoad(); + SeenStore |= MI.mayStore(); + + // If MI is an ordered or volatile memory reference, disallow moving + // subsequent loads and stores to delay slot. + if (MI.hasOrderedMemoryRef() && (OrigSeenLoad || OrigSeenStore)) { + ForbidMemInstr = true; + return true; + } + + return hasHazard_(MI); +} + +bool LoadFromStackOrConst::hasHazard_(const MachineInstr &MI) { + if (MI.mayStore()) + return true; + + if (!MI.hasOneMemOperand() || !(*MI.memoperands_begin())->getValue()) + return true; + + const Value *V = (*MI.memoperands_begin())->getValue(); + + if (isa<FixedStackPseudoSourceValue>(V)) + return false; + + if (const PseudoSourceValue *PSV = dyn_cast<const PseudoSourceValue>(V)) + return !PSV->isConstant(0) && V != PseudoSourceValue::getStack(); + + return true; +} + +MemDefsUses::MemDefsUses(const MachineFrameInfo *MFI_) + : InspectMemInstr(false), MFI(MFI_), SeenNoObjLoad(false), + SeenNoObjStore(false) {} + +bool MemDefsUses::hasHazard_(const MachineInstr &MI) { + bool HasHazard = false; + SmallVector<const Value *, 4> Objs; + + // Check underlying object list. + if (getUnderlyingObjects(MI, Objs)) { + for (SmallVectorImpl<const Value *>::const_iterator I = Objs.begin(); + I != Objs.end(); ++I) + HasHazard |= updateDefsUses(*I, MI.mayStore()); + + return HasHazard; + } + + // No underlying objects found. + HasHazard = MI.mayStore() && (OrigSeenLoad || OrigSeenStore); + HasHazard |= MI.mayLoad() || OrigSeenStore; + + SeenNoObjLoad |= MI.mayLoad(); + SeenNoObjStore |= MI.mayStore(); + + return HasHazard; +} + +bool MemDefsUses::updateDefsUses(const Value *V, bool MayStore) { + if (MayStore) + return !Defs.insert(V) || Uses.count(V) || SeenNoObjStore || SeenNoObjLoad; + + Uses.insert(V); + return Defs.count(V) || SeenNoObjStore; +} + +bool MemDefsUses:: +getUnderlyingObjects(const MachineInstr &MI, + SmallVectorImpl<const Value *> &Objects) const { + if (!MI.hasOneMemOperand() || !(*MI.memoperands_begin())->getValue()) + return false; + + const Value *V = (*MI.memoperands_begin())->getValue(); + + SmallVector<Value *, 4> Objs; + GetUnderlyingObjects(const_cast<Value *>(V), Objs); + + for (SmallVectorImpl<Value *>::iterator I = Objs.begin(), E = Objs.end(); + I != E; ++I) { + if (const PseudoSourceValue *PSV = dyn_cast<PseudoSourceValue>(*I)) { + if (PSV->isAliased(MFI)) + return false; + } else if (!isIdentifiedObject(V)) + return false; + + Objects.push_back(*I); + } + + return true; +} + +/// runOnMachineBasicBlock - Fill in delay slots for the given basic block. +/// We assume there is only one delay slot per delayed instruction. +bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { + bool Changed = false; + + for (Iter I = MBB.begin(); I != MBB.end(); ++I) { + if (!hasUnoccupiedSlot(&*I)) + continue; + + ++FilledSlots; + Changed = true; + + // Delay slot filling is disabled at -O0. + if (!DisableDelaySlotFiller && (TM.getOptLevel() != CodeGenOpt::None)) { + if (searchBackward(MBB, I)) + continue; + + if (I->isTerminator()) { + if (searchSuccBBs(MBB, I)) + continue; + } else if (searchForward(MBB, I)) { + continue; + } + } + + // Bundle the NOP to the instruction with the delay slot. + const MipsInstrInfo *TII = + static_cast<const MipsInstrInfo*>(TM.getInstrInfo()); + BuildMI(MBB, llvm::next(I), I->getDebugLoc(), TII->get(Mips::NOP)); + MIBundleBuilder(MBB, I, llvm::next(llvm::next(I))); + } + + return Changed; +} + +/// createMipsDelaySlotFillerPass - Returns a pass that fills in delay +/// slots in Mips MachineFunctions +FunctionPass *llvm::createMipsDelaySlotFillerPass(MipsTargetMachine &tm) { + return new Filler(tm); +} + +template<typename IterTy> +bool Filler::searchRange(MachineBasicBlock &MBB, IterTy Begin, IterTy End, + RegDefsUses &RegDU, InspectMemInstr& IM, + IterTy &Filler) const { + for (IterTy I = Begin; I != End; ++I) { + // skip debug value + if (I->isDebugValue()) + continue; + + if (terminateSearch(*I)) + break; + + assert((!I->isCall() && !I->isReturn() && !I->isBranch()) && + "Cannot put calls, returns or branches in delay slot."); + + if (delayHasHazard(*I, RegDU, IM)) + continue; + + Filler = I; + return true; + } + + return false; +} + +bool Filler::searchBackward(MachineBasicBlock &MBB, Iter Slot) const { + if (DisableBackwardSearch) + return false; + + RegDefsUses RegDU(TM); + MemDefsUses MemDU(MBB.getParent()->getFrameInfo()); + ReverseIter Filler; + + RegDU.init(*Slot); + + if (!searchRange(MBB, ReverseIter(Slot), MBB.rend(), RegDU, MemDU, Filler)) + return false; + + MBB.splice(llvm::next(Slot), &MBB, llvm::next(Filler).base()); + MIBundleBuilder(MBB, Slot, llvm::next(llvm::next(Slot))); + ++UsefulSlots; + return true; +} + +bool Filler::searchForward(MachineBasicBlock &MBB, Iter Slot) const { + // Can handle only calls. + if (DisableForwardSearch || !Slot->isCall()) + return false; + + RegDefsUses RegDU(TM); + NoMemInstr NM; + Iter Filler; + + RegDU.setCallerSaved(*Slot); + + if (!searchRange(MBB, llvm::next(Slot), MBB.end(), RegDU, NM, Filler)) + return false; + + MBB.splice(llvm::next(Slot), &MBB, Filler); + MIBundleBuilder(MBB, Slot, llvm::next(llvm::next(Slot))); + ++UsefulSlots; + return true; +} + +bool Filler::searchSuccBBs(MachineBasicBlock &MBB, Iter Slot) const { + if (DisableSuccBBSearch) + return false; + + MachineBasicBlock *SuccBB = selectSuccBB(MBB); + + if (!SuccBB) + return false; + + RegDefsUses RegDU(TM); + bool HasMultipleSuccs = false; + BB2BrMap BrMap; + OwningPtr<InspectMemInstr> IM; + Iter Filler; + + // Iterate over SuccBB's predecessor list. + for (MachineBasicBlock::pred_iterator PI = SuccBB->pred_begin(), + PE = SuccBB->pred_end(); PI != PE; ++PI) + if (!examinePred(**PI, *SuccBB, RegDU, HasMultipleSuccs, BrMap)) + return false; + + // Do not allow moving instructions which have unallocatable register operands + // across basic block boundaries. + RegDU.setUnallocatableRegs(*MBB.getParent()); + + // Only allow moving loads from stack or constants if any of the SuccBB's + // predecessors have multiple successors. + if (HasMultipleSuccs) { + IM.reset(new LoadFromStackOrConst()); + } else { + const MachineFrameInfo *MFI = MBB.getParent()->getFrameInfo(); + IM.reset(new MemDefsUses(MFI)); + } + + if (!searchRange(MBB, SuccBB->begin(), SuccBB->end(), RegDU, *IM, Filler)) + return false; + + insertDelayFiller(Filler, BrMap); + addLiveInRegs(Filler, *SuccBB); + Filler->eraseFromParent(); + + return true; +} + +MachineBasicBlock *Filler::selectSuccBB(MachineBasicBlock &B) const { + if (B.succ_empty()) + return NULL; + + // Select the successor with the larget edge weight. + CmpWeight Cmp(B, getAnalysis<MachineBranchProbabilityInfo>()); + MachineBasicBlock *S = *std::max_element(B.succ_begin(), B.succ_end(), Cmp); + return S->isLandingPad() ? NULL : S; +} + +std::pair<MipsInstrInfo::BranchType, MachineInstr *> +Filler::getBranch(MachineBasicBlock &MBB, const MachineBasicBlock &Dst) const { + const MipsInstrInfo *TII = + static_cast<const MipsInstrInfo*>(TM.getInstrInfo()); + MachineBasicBlock *TrueBB = 0, *FalseBB = 0; + SmallVector<MachineInstr*, 2> BranchInstrs; + SmallVector<MachineOperand, 2> Cond; + + MipsInstrInfo::BranchType R = + TII->AnalyzeBranch(MBB, TrueBB, FalseBB, Cond, false, BranchInstrs); + + if ((R == MipsInstrInfo::BT_None) || (R == MipsInstrInfo::BT_NoBranch)) + return std::make_pair(R, (MachineInstr*)NULL); + + if (R != MipsInstrInfo::BT_CondUncond) { + if (!hasUnoccupiedSlot(BranchInstrs[0])) + return std::make_pair(MipsInstrInfo::BT_None, (MachineInstr*)NULL); + + assert(((R != MipsInstrInfo::BT_Uncond) || (TrueBB == &Dst))); + + return std::make_pair(R, BranchInstrs[0]); + } + + assert((TrueBB == &Dst) || (FalseBB == &Dst)); + + // Examine the conditional branch. See if its slot is occupied. + if (hasUnoccupiedSlot(BranchInstrs[0])) + return std::make_pair(MipsInstrInfo::BT_Cond, BranchInstrs[0]); + + // If that fails, try the unconditional branch. + if (hasUnoccupiedSlot(BranchInstrs[1]) && (FalseBB == &Dst)) + return std::make_pair(MipsInstrInfo::BT_Uncond, BranchInstrs[1]); + + return std::make_pair(MipsInstrInfo::BT_None, (MachineInstr*)NULL); +} + +bool Filler::examinePred(MachineBasicBlock &Pred, const MachineBasicBlock &Succ, + RegDefsUses &RegDU, bool &HasMultipleSuccs, + BB2BrMap &BrMap) const { + std::pair<MipsInstrInfo::BranchType, MachineInstr *> P = + getBranch(Pred, Succ); + + // Return if either getBranch wasn't able to analyze the branches or there + // were no branches with unoccupied slots. + if (P.first == MipsInstrInfo::BT_None) + return false; + + if ((P.first != MipsInstrInfo::BT_Uncond) && + (P.first != MipsInstrInfo::BT_NoBranch)) { + HasMultipleSuccs = true; + RegDU.addLiveOut(Pred, Succ); + } + + BrMap[&Pred] = P.second; + return true; +} + +bool Filler::delayHasHazard(const MachineInstr &Candidate, RegDefsUses &RegDU, + InspectMemInstr &IM) const { + bool HasHazard = (Candidate.isImplicitDef() || Candidate.isKill()); + + HasHazard |= IM.hasHazard(Candidate); + HasHazard |= RegDU.update(Candidate, 0, Candidate.getNumOperands()); + + return HasHazard; +} + +bool Filler::terminateSearch(const MachineInstr &Candidate) const { + return (Candidate.isTerminator() || Candidate.isCall() || + Candidate.isLabel() || Candidate.isInlineAsm() || + Candidate.hasUnmodeledSideEffects()); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsFrameLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsFrameLowering.cpp new file mode 100644 index 000000000000..eb9d49fefb2f --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsFrameLowering.cpp @@ -0,0 +1,134 @@ +//===-- MipsFrameLowering.cpp - Mips 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 Mips implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "MipsFrameLowering.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsInstrInfo.h" +#include "MipsMachineFunction.h" +#include "MipsTargetMachine.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/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + + +//===----------------------------------------------------------------------===// +// +// 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 done thought a positive offset +// from the stack/frame pointer, so the stack is considering +// to grow up! Otherwise terrible hacks would have to be made +// to get this stack ABI compliant :) +// +// The stack frame required by the ABI (after call): +// Offset +// +// 0 ---------- +// 4 Args to pass +// . saved $GP (used in PIC) +// . Alloca allocations +// . Local Area +// . CPU "Callee Saved" Registers +// . saved FP +// . saved RA +// . FPU "Callee Saved" Registers +// StackSize ----------- +// +// Offset - offset from sp after stack allocation on function prologue +// +// The sp is the stack pointer subtracted/added from the stack size +// at the Prologue/Epilogue +// +// References to the previous stack (to obtain arguments) are done +// with offsets that exceeds the stack size: (stacksize+(4*(num_arg-1)) +// +// Examples: +// - reference to the actual stack frame +// for any local area var there is smt like : FI >= 0, StackOffset: 4 +// sw REGX, 4(SP) +// +// - reference to previous stack frame +// suppose there's a load to the 5th arguments : FI < 0, StackOffset: 16. +// The emitted instruction will be something like: +// lw REGX, 16+StackSize(SP) +// +// Since the total stack size is unknown on LowerFormalArguments, all +// stack references (ObjectOffset) created to reference the function +// arguments, are negative numbers. This way, on eliminateFrameIndex it's +// possible to detect those references and the offsets are adjusted to +// their real location. +// +//===----------------------------------------------------------------------===// + +const MipsFrameLowering *MipsFrameLowering::create(MipsTargetMachine &TM, + const MipsSubtarget &ST) { + if (TM.getSubtargetImpl()->inMips16Mode()) + return llvm::createMips16FrameLowering(ST); + + return llvm::createMipsSEFrameLowering(ST); +} + +// 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 MipsFrameLowering::hasFP(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + return MF.getTarget().Options.DisableFramePointerElim(MF) || + MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken(); +} + +uint64_t MipsFrameLowering::estimateStackSize(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + const TargetRegisterInfo &TRI = *MF.getTarget().getRegisterInfo(); + + int64_t Offset = 0; + + // Iterate over fixed sized objects. + for (int I = MFI->getObjectIndexBegin(); I != 0; ++I) + Offset = std::max(Offset, -MFI->getObjectOffset(I)); + + // Conservatively assume all callee-saved registers will be saved. + for (const uint16_t *R = TRI.getCalleeSavedRegs(&MF); *R; ++R) { + unsigned Size = TRI.getMinimalPhysRegClass(*R)->getSize(); + Offset = RoundUpToAlignment(Offset + Size, Size); + } + + unsigned MaxAlign = MFI->getMaxAlignment(); + + // Check that MaxAlign is not zero if there is a stack object that is not a + // callee-saved spill. + assert(!MFI->getObjectIndexEnd() || MaxAlign); + + // Iterate over other objects. + for (unsigned I = 0, E = MFI->getObjectIndexEnd(); I != E; ++I) + Offset = RoundUpToAlignment(Offset + MFI->getObjectSize(I), MaxAlign); + + // Call frame. + if (MFI->adjustsStack() && hasReservedCallFrame(MF)) + Offset = RoundUpToAlignment(Offset + MFI->getMaxCallFrameSize(), + std::max(MaxAlign, getStackAlignment())); + + return RoundUpToAlignment(Offset, getStackAlignment()); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsFrameLowering.h b/contrib/llvm/lib/Target/Mips/MipsFrameLowering.h new file mode 100644 index 000000000000..6a5f79d0dfc4 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsFrameLowering.h @@ -0,0 +1,47 @@ +//===-- MipsFrameLowering.h - Define frame lowering for Mips ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// +//===----------------------------------------------------------------------===// + +#ifndef MIPS_FRAMEINFO_H +#define MIPS_FRAMEINFO_H + +#include "Mips.h" +#include "MipsSubtarget.h" +#include "llvm/Target/TargetFrameLowering.h" + +namespace llvm { + class MipsSubtarget; + +class MipsFrameLowering : public TargetFrameLowering { +protected: + const MipsSubtarget &STI; + +public: + explicit MipsFrameLowering(const MipsSubtarget &sti, unsigned Alignment) + : TargetFrameLowering(StackGrowsDown, Alignment, 0, Alignment), STI(sti) {} + + static const MipsFrameLowering *create(MipsTargetMachine &TM, + const MipsSubtarget &ST); + + bool hasFP(const MachineFunction &MF) const; + +protected: + uint64_t estimateStackSize(const MachineFunction &MF) const; +}; + +/// Create MipsFrameLowering objects. +const MipsFrameLowering *createMips16FrameLowering(const MipsSubtarget &ST); +const MipsFrameLowering *createMipsSEFrameLowering(const MipsSubtarget &ST); + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp new file mode 100644 index 000000000000..c417bd593413 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -0,0 +1,232 @@ +//===-- MipsISelDAGToDAG.cpp - A Dag to Dag Inst Selector for Mips --------===// +// +// 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 MIPS target. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-isel" +#include "MipsISelDAGToDAG.h" +#include "Mips16ISelDAGToDAG.h" +#include "MipsSEISelDAGToDAG.h" +#include "Mips.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsMachineFunction.h" +#include "MipsRegisterInfo.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/CFG.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Instruction Selector Implementation +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MipsDAGToDAGISel - MIPS specific code to select MIPS machine +// instructions for SelectionDAG operations. +//===----------------------------------------------------------------------===// + +bool MipsDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { + bool Ret = SelectionDAGISel::runOnMachineFunction(MF); + + processFunctionAfterISel(MF); + + return Ret; +} + +/// getGlobalBaseReg - Output the instructions required to put the +/// GOT address into a register. +SDNode *MipsDAGToDAGISel::getGlobalBaseReg() { + unsigned GlobalBaseReg = MF->getInfo<MipsFunctionInfo>()->getGlobalBaseReg(); + return CurDAG->getRegister(GlobalBaseReg, + getTargetLowering()->getPointerTy()).getNode(); +} + +/// ComplexPattern used on MipsInstrInfo +/// Used on Mips Load/Store instructions +bool MipsDAGToDAGISel::selectAddrRegImm(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectAddrRegReg(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectAddrDefault(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectIntAddr(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectIntAddrMM(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectAddr16(SDNode *Parent, SDValue N, SDValue &Base, + SDValue &Offset, SDValue &Alias) { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm1(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm2(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm3(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm4(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm5(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm6(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimm8(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatSimm5(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimmPow2(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatMaskL(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +bool MipsDAGToDAGISel::selectVSplatMaskR(SDValue N, SDValue &Imm) const { + llvm_unreachable("Unimplemented function."); + return false; +} + +/// Select instructions not customized! Used for +/// expanded, promoted and normal instructions +SDNode* MipsDAGToDAGISel::Select(SDNode *Node) { + unsigned Opcode = Node->getOpcode(); + + // Dump information about the Node being selected + DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n"); + + // If we have a custom node, we already have selected! + if (Node->isMachineOpcode()) { + DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); + Node->setNodeId(-1); + return NULL; + } + + // See if subclasses can handle this node. + std::pair<bool, SDNode*> Ret = selectNode(Node); + + if (Ret.first) + return Ret.second; + + switch(Opcode) { + default: break; + + // Get target GOT address. + case ISD::GLOBAL_OFFSET_TABLE: + return getGlobalBaseReg(); + +#ifndef NDEBUG + case ISD::LOAD: + case ISD::STORE: + assert(cast<MemSDNode>(Node)->getMemoryVT().getSizeInBits() / 8 <= + cast<MemSDNode>(Node)->getAlignment() && + "Unexpected unaligned loads/stores."); + break; +#endif + } + + // 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; +} + +bool MipsDAGToDAGISel:: +SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, + std::vector<SDValue> &OutOps) { + assert(ConstraintCode == 'm' && "unexpected asm memory constraint"); + OutOps.push_back(Op); + return false; +} + +/// createMipsISelDag - This pass converts a legalized DAG into a +/// MIPS-specific DAG, ready for instruction scheduling. +FunctionPass *llvm::createMipsISelDag(MipsTargetMachine &TM) { + if (TM.getSubtargetImpl()->inMips16Mode()) + return llvm::createMips16ISelDag(TM); + + return llvm::createMipsSEISelDag(TM); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.h b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.h new file mode 100644 index 000000000000..a4d9da532b2e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsISelDAGToDAG.h @@ -0,0 +1,131 @@ +//===---- MipsISelDAGToDAG.h - A Dag to Dag Inst Selector for Mips --------===// +// +// 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 MIPS target. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSISELDAGTODAG_H +#define MIPSISELDAGTODAG_H + +#include "Mips.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" +#include "llvm/CodeGen/SelectionDAGISel.h" + +//===----------------------------------------------------------------------===// +// Instruction Selector Implementation +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MipsDAGToDAGISel - MIPS specific code to select MIPS machine +// instructions for SelectionDAG operations. +//===----------------------------------------------------------------------===// +namespace llvm { + +class MipsDAGToDAGISel : public SelectionDAGISel { +public: + explicit MipsDAGToDAGISel(MipsTargetMachine &TM) + : SelectionDAGISel(TM), Subtarget(TM.getSubtarget<MipsSubtarget>()) {} + + // Pass Name + virtual const char *getPassName() const { + return "MIPS DAG->DAG Pattern Instruction Selection"; + } + + virtual bool runOnMachineFunction(MachineFunction &MF); + +protected: + SDNode *getGlobalBaseReg(); + + /// Keep a pointer to the MipsSubtarget around so that we can make the right + /// decision when generating code for different targets. + const MipsSubtarget &Subtarget; + +private: + // Include the pieces autogenerated from the target description. + #include "MipsGenDAGISel.inc" + + // Complex Pattern. + /// (reg + imm). + virtual bool selectAddrRegImm(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + // Complex Pattern. + /// (reg + reg). + virtual bool selectAddrRegReg(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + /// Fall back on this function if all else fails. + virtual bool selectAddrDefault(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + /// Match integer address pattern. + virtual bool selectIntAddr(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + virtual bool selectIntAddrMM(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + virtual bool selectAddr16(SDNode *Parent, SDValue N, SDValue &Base, + SDValue &Offset, SDValue &Alias); + + /// \brief Select constant vector splats. + virtual bool selectVSplat(SDNode *N, APInt &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm1. + virtual bool selectVSplatUimm1(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm2. + virtual bool selectVSplatUimm2(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm3. + virtual bool selectVSplatUimm3(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm4. + virtual bool selectVSplatUimm4(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm5. + virtual bool selectVSplatUimm5(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm6. + virtual bool selectVSplatUimm6(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm8. + virtual bool selectVSplatUimm8(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a simm5. + virtual bool selectVSplatSimm5(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value is a power of 2. + virtual bool selectVSplatUimmPow2(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value is the inverse of a + /// power of 2. + virtual bool selectVSplatUimmInvPow2(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value is a run of set bits + /// ending at the most significant bit + virtual bool selectVSplatMaskL(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value is a run of set bits + /// starting at bit zero. + virtual bool selectVSplatMaskR(SDValue N, SDValue &Imm) const; + + virtual SDNode *Select(SDNode *N); + + virtual std::pair<bool, SDNode*> selectNode(SDNode *Node) = 0; + + // getImm - Return a target constant with the specified value. + inline SDValue getImm(const SDNode *Node, uint64_t Imm) { + return CurDAG->getTargetConstant(Imm, Node->getValueType(0)); + } + + virtual void processFunctionAfterISel(MachineFunction &MF) = 0; + + virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, + char ConstraintCode, + std::vector<SDValue> &OutOps); +}; + +/// createMipsISelDag - This pass converts a legalized DAG into a +/// MIPS-specific DAG, ready for instruction scheduling. +FunctionPass *createMipsISelDag(MipsTargetMachine &TM); + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp new file mode 100644 index 000000000000..1e8250c847fe --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -0,0 +1,3614 @@ +//===-- MipsISelLowering.cpp - Mips 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 Mips uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// +#define DEBUG_TYPE "mips-lower" +#include "MipsISelLowering.h" +#include "InstPrinter/MipsInstPrinter.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsMachineFunction.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" +#include "MipsTargetObjectFile.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringSwitch.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/IR/CallingConv.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <cctype> + +using namespace llvm; + +STATISTIC(NumTailCalls, "Number of tail calls"); + +static cl::opt<bool> +LargeGOT("mxgot", cl::Hidden, + cl::desc("MIPS: Enable GOT larger than 64k."), cl::init(false)); + +static cl::opt<bool> +NoZeroDivCheck("mno-check-zero-division", cl::Hidden, + cl::desc("MIPS: Don't trap on integer division by zero."), + cl::init(false)); + +static const uint16_t O32IntRegs[4] = { + Mips::A0, Mips::A1, Mips::A2, Mips::A3 +}; + +static const uint16_t Mips64IntRegs[8] = { + Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64, + Mips::T0_64, Mips::T1_64, Mips::T2_64, Mips::T3_64 +}; + +static const uint16_t Mips64DPRegs[8] = { + Mips::D12_64, Mips::D13_64, Mips::D14_64, Mips::D15_64, + Mips::D16_64, Mips::D17_64, Mips::D18_64, Mips::D19_64 +}; + +// If I is a shifted mask, set the size (Size) and the first bit of the +// mask (Pos), and return true. +// For example, if I is 0x003ff800, (Pos, Size) = (11, 11). +static bool isShiftedMask(uint64_t I, uint64_t &Pos, uint64_t &Size) { + if (!isShiftedMask_64(I)) + return false; + + Size = CountPopulation_64(I); + Pos = countTrailingZeros(I); + return true; +} + +SDValue MipsTargetLowering::getGlobalReg(SelectionDAG &DAG, EVT Ty) const { + MipsFunctionInfo *FI = DAG.getMachineFunction().getInfo<MipsFunctionInfo>(); + return DAG.getRegister(FI->getGlobalBaseReg(), Ty); +} + +SDValue MipsTargetLowering::getTargetNode(GlobalAddressSDNode *N, EVT Ty, + SelectionDAG &DAG, + unsigned Flag) const { + return DAG.getTargetGlobalAddress(N->getGlobal(), SDLoc(N), Ty, 0, Flag); +} + +SDValue MipsTargetLowering::getTargetNode(ExternalSymbolSDNode *N, EVT Ty, + SelectionDAG &DAG, + unsigned Flag) const { + return DAG.getTargetExternalSymbol(N->getSymbol(), Ty, Flag); +} + +SDValue MipsTargetLowering::getTargetNode(BlockAddressSDNode *N, EVT Ty, + SelectionDAG &DAG, + unsigned Flag) const { + return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, 0, Flag); +} + +SDValue MipsTargetLowering::getTargetNode(JumpTableSDNode *N, EVT Ty, + SelectionDAG &DAG, + unsigned Flag) const { + return DAG.getTargetJumpTable(N->getIndex(), Ty, Flag); +} + +SDValue MipsTargetLowering::getTargetNode(ConstantPoolSDNode *N, EVT Ty, + SelectionDAG &DAG, + unsigned Flag) const { + return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlignment(), + N->getOffset(), Flag); +} + +const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + case MipsISD::JmpLink: return "MipsISD::JmpLink"; + case MipsISD::TailCall: return "MipsISD::TailCall"; + case MipsISD::Hi: return "MipsISD::Hi"; + case MipsISD::Lo: return "MipsISD::Lo"; + case MipsISD::GPRel: return "MipsISD::GPRel"; + case MipsISD::ThreadPointer: return "MipsISD::ThreadPointer"; + case MipsISD::Ret: return "MipsISD::Ret"; + case MipsISD::EH_RETURN: return "MipsISD::EH_RETURN"; + case MipsISD::FPBrcond: return "MipsISD::FPBrcond"; + case MipsISD::FPCmp: return "MipsISD::FPCmp"; + case MipsISD::CMovFP_T: return "MipsISD::CMovFP_T"; + case MipsISD::CMovFP_F: return "MipsISD::CMovFP_F"; + case MipsISD::TruncIntFP: return "MipsISD::TruncIntFP"; + case MipsISD::MFHI: return "MipsISD::MFHI"; + case MipsISD::MFLO: return "MipsISD::MFLO"; + case MipsISD::MTLOHI: return "MipsISD::MTLOHI"; + case MipsISD::Mult: return "MipsISD::Mult"; + case MipsISD::Multu: return "MipsISD::Multu"; + case MipsISD::MAdd: return "MipsISD::MAdd"; + case MipsISD::MAddu: return "MipsISD::MAddu"; + case MipsISD::MSub: return "MipsISD::MSub"; + case MipsISD::MSubu: return "MipsISD::MSubu"; + case MipsISD::DivRem: return "MipsISD::DivRem"; + case MipsISD::DivRemU: return "MipsISD::DivRemU"; + case MipsISD::DivRem16: return "MipsISD::DivRem16"; + case MipsISD::DivRemU16: return "MipsISD::DivRemU16"; + case MipsISD::BuildPairF64: return "MipsISD::BuildPairF64"; + case MipsISD::ExtractElementF64: return "MipsISD::ExtractElementF64"; + case MipsISD::Wrapper: return "MipsISD::Wrapper"; + case MipsISD::Sync: return "MipsISD::Sync"; + case MipsISD::Ext: return "MipsISD::Ext"; + case MipsISD::Ins: return "MipsISD::Ins"; + case MipsISD::LWL: return "MipsISD::LWL"; + case MipsISD::LWR: return "MipsISD::LWR"; + case MipsISD::SWL: return "MipsISD::SWL"; + case MipsISD::SWR: return "MipsISD::SWR"; + case MipsISD::LDL: return "MipsISD::LDL"; + case MipsISD::LDR: return "MipsISD::LDR"; + case MipsISD::SDL: return "MipsISD::SDL"; + case MipsISD::SDR: return "MipsISD::SDR"; + case MipsISD::EXTP: return "MipsISD::EXTP"; + case MipsISD::EXTPDP: return "MipsISD::EXTPDP"; + case MipsISD::EXTR_S_H: return "MipsISD::EXTR_S_H"; + case MipsISD::EXTR_W: return "MipsISD::EXTR_W"; + case MipsISD::EXTR_R_W: return "MipsISD::EXTR_R_W"; + case MipsISD::EXTR_RS_W: return "MipsISD::EXTR_RS_W"; + case MipsISD::SHILO: return "MipsISD::SHILO"; + case MipsISD::MTHLIP: return "MipsISD::MTHLIP"; + case MipsISD::MULT: return "MipsISD::MULT"; + case MipsISD::MULTU: return "MipsISD::MULTU"; + case MipsISD::MADD_DSP: return "MipsISD::MADD_DSP"; + case MipsISD::MADDU_DSP: return "MipsISD::MADDU_DSP"; + case MipsISD::MSUB_DSP: return "MipsISD::MSUB_DSP"; + case MipsISD::MSUBU_DSP: return "MipsISD::MSUBU_DSP"; + case MipsISD::SHLL_DSP: return "MipsISD::SHLL_DSP"; + case MipsISD::SHRA_DSP: return "MipsISD::SHRA_DSP"; + case MipsISD::SHRL_DSP: return "MipsISD::SHRL_DSP"; + case MipsISD::SETCC_DSP: return "MipsISD::SETCC_DSP"; + case MipsISD::SELECT_CC_DSP: return "MipsISD::SELECT_CC_DSP"; + case MipsISD::VALL_ZERO: return "MipsISD::VALL_ZERO"; + case MipsISD::VANY_ZERO: return "MipsISD::VANY_ZERO"; + case MipsISD::VALL_NONZERO: return "MipsISD::VALL_NONZERO"; + case MipsISD::VANY_NONZERO: return "MipsISD::VANY_NONZERO"; + case MipsISD::VCEQ: return "MipsISD::VCEQ"; + case MipsISD::VCLE_S: return "MipsISD::VCLE_S"; + case MipsISD::VCLE_U: return "MipsISD::VCLE_U"; + case MipsISD::VCLT_S: return "MipsISD::VCLT_S"; + case MipsISD::VCLT_U: return "MipsISD::VCLT_U"; + case MipsISD::VSMAX: return "MipsISD::VSMAX"; + case MipsISD::VSMIN: return "MipsISD::VSMIN"; + case MipsISD::VUMAX: return "MipsISD::VUMAX"; + case MipsISD::VUMIN: return "MipsISD::VUMIN"; + case MipsISD::VEXTRACT_SEXT_ELT: return "MipsISD::VEXTRACT_SEXT_ELT"; + case MipsISD::VEXTRACT_ZEXT_ELT: return "MipsISD::VEXTRACT_ZEXT_ELT"; + case MipsISD::VNOR: return "MipsISD::VNOR"; + case MipsISD::VSHF: return "MipsISD::VSHF"; + case MipsISD::SHF: return "MipsISD::SHF"; + case MipsISD::ILVEV: return "MipsISD::ILVEV"; + case MipsISD::ILVOD: return "MipsISD::ILVOD"; + case MipsISD::ILVL: return "MipsISD::ILVL"; + case MipsISD::ILVR: return "MipsISD::ILVR"; + case MipsISD::PCKEV: return "MipsISD::PCKEV"; + case MipsISD::PCKOD: return "MipsISD::PCKOD"; + default: return NULL; + } +} + +MipsTargetLowering:: +MipsTargetLowering(MipsTargetMachine &TM) + : TargetLowering(TM, new MipsTargetObjectFile()), + Subtarget(&TM.getSubtarget<MipsSubtarget>()), + HasMips64(Subtarget->hasMips64()), IsN64(Subtarget->isABI_N64()), + IsO32(Subtarget->isABI_O32()) { + // Mips does not have i1 type, so use i32 for + // setcc operations results (slt, sgt, ...). + setBooleanContents(ZeroOrOneBooleanContent); + setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); + + // 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); + + // MIPS doesn't have extending float->double load/store + setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand); + setTruncStoreAction(MVT::f64, MVT::f32, 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); + + // Mips Custom Operations + setOperationAction(ISD::BR_JT, MVT::Other, Custom); + setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); + setOperationAction(ISD::BlockAddress, MVT::i32, Custom); + setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom); + setOperationAction(ISD::JumpTable, MVT::i32, Custom); + setOperationAction(ISD::ConstantPool, MVT::i32, Custom); + setOperationAction(ISD::SELECT, MVT::f32, Custom); + setOperationAction(ISD::SELECT, MVT::f64, Custom); + setOperationAction(ISD::SELECT, MVT::i32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); + setOperationAction(ISD::SETCC, MVT::f32, Custom); + setOperationAction(ISD::SETCC, MVT::f64, Custom); + setOperationAction(ISD::BRCOND, MVT::Other, Custom); + setOperationAction(ISD::VASTART, MVT::Other, Custom); + setOperationAction(ISD::FCOPYSIGN, MVT::f32, Custom); + setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom); + setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); + + if (!TM.Options.NoNaNsFPMath) { + setOperationAction(ISD::FABS, MVT::f32, Custom); + setOperationAction(ISD::FABS, MVT::f64, Custom); + } + + if (HasMips64) { + setOperationAction(ISD::GlobalAddress, MVT::i64, Custom); + setOperationAction(ISD::BlockAddress, MVT::i64, Custom); + setOperationAction(ISD::GlobalTLSAddress, MVT::i64, Custom); + setOperationAction(ISD::JumpTable, MVT::i64, Custom); + setOperationAction(ISD::ConstantPool, MVT::i64, Custom); + setOperationAction(ISD::SELECT, MVT::i64, Custom); + setOperationAction(ISD::LOAD, MVT::i64, Custom); + setOperationAction(ISD::STORE, MVT::i64, Custom); + setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom); + } + + if (!HasMips64) { + setOperationAction(ISD::SHL_PARTS, MVT::i32, Custom); + setOperationAction(ISD::SRA_PARTS, MVT::i32, Custom); + setOperationAction(ISD::SRL_PARTS, MVT::i32, Custom); + } + + setOperationAction(ISD::ADD, MVT::i32, Custom); + if (HasMips64) + setOperationAction(ISD::ADD, MVT::i64, Custom); + + setOperationAction(ISD::SDIV, MVT::i32, Expand); + setOperationAction(ISD::SREM, MVT::i32, Expand); + setOperationAction(ISD::UDIV, MVT::i32, Expand); + setOperationAction(ISD::UREM, MVT::i32, Expand); + setOperationAction(ISD::SDIV, MVT::i64, Expand); + setOperationAction(ISD::SREM, MVT::i64, Expand); + setOperationAction(ISD::UDIV, MVT::i64, Expand); + setOperationAction(ISD::UREM, MVT::i64, Expand); + + // Operations not directly supported by Mips. + setOperationAction(ISD::BR_CC, MVT::f32, Expand); + setOperationAction(ISD::BR_CC, MVT::f64, Expand); + setOperationAction(ISD::BR_CC, MVT::i32, Expand); + setOperationAction(ISD::BR_CC, MVT::i64, Expand); + setOperationAction(ISD::SELECT_CC, MVT::Other, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand); + setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand); + setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand); + setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + setOperationAction(ISD::CTPOP, MVT::i32, Expand); + setOperationAction(ISD::CTPOP, MVT::i64, Expand); + setOperationAction(ISD::CTTZ, MVT::i32, Expand); + setOperationAction(ISD::CTTZ, MVT::i64, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, Expand); + setOperationAction(ISD::ROTL, MVT::i32, Expand); + setOperationAction(ISD::ROTL, MVT::i64, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand); + + if (!Subtarget->hasMips32r2()) + setOperationAction(ISD::ROTR, MVT::i32, Expand); + + if (!Subtarget->hasMips64r2()) + setOperationAction(ISD::ROTR, MVT::i64, Expand); + + setOperationAction(ISD::FSIN, MVT::f32, Expand); + setOperationAction(ISD::FSIN, MVT::f64, Expand); + setOperationAction(ISD::FCOS, MVT::f32, Expand); + setOperationAction(ISD::FCOS, MVT::f64, Expand); + setOperationAction(ISD::FSINCOS, MVT::f32, Expand); + setOperationAction(ISD::FSINCOS, MVT::f64, Expand); + setOperationAction(ISD::FPOWI, MVT::f32, Expand); + setOperationAction(ISD::FPOW, MVT::f32, Expand); + setOperationAction(ISD::FPOW, MVT::f64, 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); + setOperationAction(ISD::FMA, MVT::f32, Expand); + setOperationAction(ISD::FMA, MVT::f64, Expand); + setOperationAction(ISD::FREM, MVT::f32, Expand); + setOperationAction(ISD::FREM, MVT::f64, Expand); + + if (!TM.Options.NoNaNsFPMath) { + setOperationAction(ISD::FNEG, MVT::f32, Expand); + setOperationAction(ISD::FNEG, MVT::f64, Expand); + } + + setOperationAction(ISD::EH_RETURN, MVT::Other, Custom); + + setOperationAction(ISD::VAARG, MVT::Other, Expand); + setOperationAction(ISD::VACOPY, MVT::Other, Expand); + setOperationAction(ISD::VAEND, MVT::Other, Expand); + + // Use the default for now + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + + setOperationAction(ISD::ATOMIC_LOAD, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD, MVT::i64, Expand); + setOperationAction(ISD::ATOMIC_STORE, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Expand); + + setInsertFencesForAtomic(true); + + if (!Subtarget->hasSEInReg()) { + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); + } + + if (!Subtarget->hasBitCount()) { + setOperationAction(ISD::CTLZ, MVT::i32, Expand); + setOperationAction(ISD::CTLZ, MVT::i64, Expand); + } + + if (!Subtarget->hasSwap()) { + setOperationAction(ISD::BSWAP, MVT::i32, Expand); + setOperationAction(ISD::BSWAP, MVT::i64, Expand); + } + + if (HasMips64) { + setLoadExtAction(ISD::SEXTLOAD, MVT::i32, Custom); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i32, Custom); + setLoadExtAction(ISD::EXTLOAD, MVT::i32, Custom); + setTruncStoreAction(MVT::i64, MVT::i32, Custom); + } + + setOperationAction(ISD::TRAP, MVT::Other, Legal); + + setTargetDAGCombine(ISD::SDIVREM); + setTargetDAGCombine(ISD::UDIVREM); + setTargetDAGCombine(ISD::SELECT); + setTargetDAGCombine(ISD::AND); + setTargetDAGCombine(ISD::OR); + setTargetDAGCombine(ISD::ADD); + + setMinFunctionAlignment(HasMips64 ? 3 : 2); + + setStackPointerRegisterToSaveRestore(IsN64 ? Mips::SP_64 : Mips::SP); + + setExceptionPointerRegister(IsN64 ? Mips::A0_64 : Mips::A0); + setExceptionSelectorRegister(IsN64 ? Mips::A1_64 : Mips::A1); + + MaxStoresPerMemcpy = 16; +} + +const MipsTargetLowering *MipsTargetLowering::create(MipsTargetMachine &TM) { + if (TM.getSubtargetImpl()->inMips16Mode()) + return llvm::createMips16TargetLowering(TM); + + return llvm::createMipsSETargetLowering(TM); +} + +EVT MipsTargetLowering::getSetCCResultType(LLVMContext &, EVT VT) const { + if (!VT.isVector()) + return MVT::i32; + return VT.changeVectorElementTypeToInteger(); +} + +static SDValue performDivRemCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget *Subtarget) { + if (DCI.isBeforeLegalizeOps()) + return SDValue(); + + EVT Ty = N->getValueType(0); + unsigned LO = (Ty == MVT::i32) ? Mips::LO0 : Mips::LO0_64; + unsigned HI = (Ty == MVT::i32) ? Mips::HI0 : Mips::HI0_64; + unsigned Opc = N->getOpcode() == ISD::SDIVREM ? MipsISD::DivRem16 : + MipsISD::DivRemU16; + SDLoc DL(N); + + SDValue DivRem = DAG.getNode(Opc, DL, MVT::Glue, + N->getOperand(0), N->getOperand(1)); + SDValue InChain = DAG.getEntryNode(); + SDValue InGlue = DivRem; + + // insert MFLO + if (N->hasAnyUseOfValue(0)) { + SDValue CopyFromLo = DAG.getCopyFromReg(InChain, DL, LO, Ty, + InGlue); + DAG.ReplaceAllUsesOfValueWith(SDValue(N, 0), CopyFromLo); + InChain = CopyFromLo.getValue(1); + InGlue = CopyFromLo.getValue(2); + } + + // insert MFHI + if (N->hasAnyUseOfValue(1)) { + SDValue CopyFromHi = DAG.getCopyFromReg(InChain, DL, + HI, Ty, InGlue); + DAG.ReplaceAllUsesOfValueWith(SDValue(N, 1), CopyFromHi); + } + + return SDValue(); +} + +static Mips::CondCode condCodeToFCC(ISD::CondCode CC) { + switch (CC) { + default: llvm_unreachable("Unknown fp condition code!"); + case ISD::SETEQ: + case ISD::SETOEQ: return Mips::FCOND_OEQ; + case ISD::SETUNE: return Mips::FCOND_UNE; + case ISD::SETLT: + case ISD::SETOLT: return Mips::FCOND_OLT; + case ISD::SETGT: + case ISD::SETOGT: return Mips::FCOND_OGT; + case ISD::SETLE: + case ISD::SETOLE: return Mips::FCOND_OLE; + case ISD::SETGE: + case ISD::SETOGE: return Mips::FCOND_OGE; + case ISD::SETULT: return Mips::FCOND_ULT; + case ISD::SETULE: return Mips::FCOND_ULE; + case ISD::SETUGT: return Mips::FCOND_UGT; + case ISD::SETUGE: return Mips::FCOND_UGE; + case ISD::SETUO: return Mips::FCOND_UN; + case ISD::SETO: return Mips::FCOND_OR; + case ISD::SETNE: + case ISD::SETONE: return Mips::FCOND_ONE; + case ISD::SETUEQ: return Mips::FCOND_UEQ; + } +} + + +/// This function returns true if the floating point conditional branches and +/// conditional moves which use condition code CC should be inverted. +static bool invertFPCondCodeUser(Mips::CondCode CC) { + if (CC >= Mips::FCOND_F && CC <= Mips::FCOND_NGT) + return false; + + assert((CC >= Mips::FCOND_T && CC <= Mips::FCOND_GT) && + "Illegal Condition Code"); + + return true; +} + +// Creates and returns an FPCmp node from a setcc node. +// Returns Op if setcc is not a floating point comparison. +static SDValue createFPCmp(SelectionDAG &DAG, const SDValue &Op) { + // must be a SETCC node + if (Op.getOpcode() != ISD::SETCC) + return Op; + + SDValue LHS = Op.getOperand(0); + + if (!LHS.getValueType().isFloatingPoint()) + return Op; + + SDValue RHS = Op.getOperand(1); + SDLoc DL(Op); + + // Assume the 3rd operand is a CondCodeSDNode. Add code to check the type of + // node if necessary. + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get(); + + return DAG.getNode(MipsISD::FPCmp, DL, MVT::Glue, LHS, RHS, + DAG.getConstant(condCodeToFCC(CC), MVT::i32)); +} + +// Creates and returns a CMovFPT/F node. +static SDValue createCMovFP(SelectionDAG &DAG, SDValue Cond, SDValue True, + SDValue False, SDLoc DL) { + ConstantSDNode *CC = cast<ConstantSDNode>(Cond.getOperand(2)); + bool invert = invertFPCondCodeUser((Mips::CondCode)CC->getSExtValue()); + SDValue FCC0 = DAG.getRegister(Mips::FCC0, MVT::i32); + + return DAG.getNode((invert ? MipsISD::CMovFP_F : MipsISD::CMovFP_T), DL, + True.getValueType(), True, FCC0, False, Cond); +} + +static SDValue performSELECTCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget *Subtarget) { + if (DCI.isBeforeLegalizeOps()) + return SDValue(); + + SDValue SetCC = N->getOperand(0); + + if ((SetCC.getOpcode() != ISD::SETCC) || + !SetCC.getOperand(0).getValueType().isInteger()) + return SDValue(); + + SDValue False = N->getOperand(2); + EVT FalseTy = False.getValueType(); + + if (!FalseTy.isInteger()) + return SDValue(); + + ConstantSDNode *CN = dyn_cast<ConstantSDNode>(False); + + if (!CN || CN->getZExtValue()) + return SDValue(); + + const SDLoc DL(N); + ISD::CondCode CC = cast<CondCodeSDNode>(SetCC.getOperand(2))->get(); + SDValue True = N->getOperand(1); + + SetCC = DAG.getSetCC(DL, SetCC.getValueType(), SetCC.getOperand(0), + SetCC.getOperand(1), ISD::getSetCCInverse(CC, true)); + + return DAG.getNode(ISD::SELECT, DL, FalseTy, SetCC, False, True); +} + +static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget *Subtarget) { + // Pattern match EXT. + // $dst = and ((sra or srl) $src , pos), (2**size - 1) + // => ext $dst, $src, size, pos + if (DCI.isBeforeLegalizeOps() || !Subtarget->hasExtractInsert()) + return SDValue(); + + SDValue ShiftRight = N->getOperand(0), Mask = N->getOperand(1); + unsigned ShiftRightOpc = ShiftRight.getOpcode(); + + // Op's first operand must be a shift right. + if (ShiftRightOpc != ISD::SRA && ShiftRightOpc != ISD::SRL) + return SDValue(); + + // The second operand of the shift must be an immediate. + ConstantSDNode *CN; + if (!(CN = dyn_cast<ConstantSDNode>(ShiftRight.getOperand(1)))) + return SDValue(); + + uint64_t Pos = CN->getZExtValue(); + uint64_t SMPos, SMSize; + + // Op's second operand must be a shifted mask. + if (!(CN = dyn_cast<ConstantSDNode>(Mask)) || + !isShiftedMask(CN->getZExtValue(), SMPos, SMSize)) + return SDValue(); + + // Return if the shifted mask does not start at bit 0 or the sum of its size + // and Pos exceeds the word's size. + EVT ValTy = N->getValueType(0); + if (SMPos != 0 || Pos + SMSize > ValTy.getSizeInBits()) + return SDValue(); + + return DAG.getNode(MipsISD::Ext, SDLoc(N), ValTy, + ShiftRight.getOperand(0), DAG.getConstant(Pos, MVT::i32), + DAG.getConstant(SMSize, MVT::i32)); +} + +static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget *Subtarget) { + // Pattern match INS. + // $dst = or (and $src1 , mask0), (and (shl $src, pos), mask1), + // where mask1 = (2**size - 1) << pos, mask0 = ~mask1 + // => ins $dst, $src, size, pos, $src1 + if (DCI.isBeforeLegalizeOps() || !Subtarget->hasExtractInsert()) + return SDValue(); + + SDValue And0 = N->getOperand(0), And1 = N->getOperand(1); + uint64_t SMPos0, SMSize0, SMPos1, SMSize1; + ConstantSDNode *CN; + + // See if Op's first operand matches (and $src1 , mask0). + if (And0.getOpcode() != ISD::AND) + return SDValue(); + + if (!(CN = dyn_cast<ConstantSDNode>(And0.getOperand(1))) || + !isShiftedMask(~CN->getSExtValue(), SMPos0, SMSize0)) + return SDValue(); + + // See if Op's second operand matches (and (shl $src, pos), mask1). + if (And1.getOpcode() != ISD::AND) + return SDValue(); + + if (!(CN = dyn_cast<ConstantSDNode>(And1.getOperand(1))) || + !isShiftedMask(CN->getZExtValue(), SMPos1, SMSize1)) + return SDValue(); + + // The shift masks must have the same position and size. + if (SMPos0 != SMPos1 || SMSize0 != SMSize1) + return SDValue(); + + SDValue Shl = And1.getOperand(0); + if (Shl.getOpcode() != ISD::SHL) + return SDValue(); + + if (!(CN = dyn_cast<ConstantSDNode>(Shl.getOperand(1)))) + return SDValue(); + + unsigned Shamt = CN->getZExtValue(); + + // Return if the shift amount and the first bit position of mask are not the + // same. + EVT ValTy = N->getValueType(0); + if ((Shamt != SMPos0) || (SMPos0 + SMSize0 > ValTy.getSizeInBits())) + return SDValue(); + + return DAG.getNode(MipsISD::Ins, SDLoc(N), ValTy, Shl.getOperand(0), + DAG.getConstant(SMPos0, MVT::i32), + DAG.getConstant(SMSize0, MVT::i32), And0.getOperand(0)); +} + +static SDValue performADDCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget *Subtarget) { + // (add v0, (add v1, abs_lo(tjt))) => (add (add v0, v1), abs_lo(tjt)) + + if (DCI.isBeforeLegalizeOps()) + return SDValue(); + + SDValue Add = N->getOperand(1); + + if (Add.getOpcode() != ISD::ADD) + return SDValue(); + + SDValue Lo = Add.getOperand(1); + + if ((Lo.getOpcode() != MipsISD::Lo) || + (Lo.getOperand(0).getOpcode() != ISD::TargetJumpTable)) + return SDValue(); + + EVT ValTy = N->getValueType(0); + SDLoc DL(N); + + SDValue Add1 = DAG.getNode(ISD::ADD, DL, ValTy, N->getOperand(0), + Add.getOperand(0)); + return DAG.getNode(ISD::ADD, DL, ValTy, Add1, Lo); +} + +SDValue MipsTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) + const { + SelectionDAG &DAG = DCI.DAG; + unsigned Opc = N->getOpcode(); + + switch (Opc) { + default: break; + case ISD::SDIVREM: + case ISD::UDIVREM: + return performDivRemCombine(N, DAG, DCI, Subtarget); + case ISD::SELECT: + return performSELECTCombine(N, DAG, DCI, Subtarget); + case ISD::AND: + return performANDCombine(N, DAG, DCI, Subtarget); + case ISD::OR: + return performORCombine(N, DAG, DCI, Subtarget); + case ISD::ADD: + return performADDCombine(N, DAG, DCI, Subtarget); + } + + return SDValue(); +} + +void +MipsTargetLowering::LowerOperationWrapper(SDNode *N, + SmallVectorImpl<SDValue> &Results, + SelectionDAG &DAG) const { + SDValue Res = LowerOperation(SDValue(N, 0), DAG); + + for (unsigned I = 0, E = Res->getNumValues(); I != E; ++I) + Results.push_back(Res.getValue(I)); +} + +void +MipsTargetLowering::ReplaceNodeResults(SDNode *N, + SmallVectorImpl<SDValue> &Results, + SelectionDAG &DAG) const { + return LowerOperationWrapper(N, Results, DAG); +} + +SDValue MipsTargetLowering:: +LowerOperation(SDValue Op, SelectionDAG &DAG) const +{ + switch (Op.getOpcode()) + { + case ISD::BR_JT: return lowerBR_JT(Op, DAG); + case ISD::BRCOND: return lowerBRCOND(Op, DAG); + case ISD::ConstantPool: return lowerConstantPool(Op, DAG); + case ISD::GlobalAddress: return lowerGlobalAddress(Op, DAG); + case ISD::BlockAddress: return lowerBlockAddress(Op, DAG); + case ISD::GlobalTLSAddress: return lowerGlobalTLSAddress(Op, DAG); + case ISD::JumpTable: return lowerJumpTable(Op, DAG); + case ISD::SELECT: return lowerSELECT(Op, DAG); + case ISD::SELECT_CC: return lowerSELECT_CC(Op, DAG); + case ISD::SETCC: return lowerSETCC(Op, DAG); + case ISD::VASTART: return lowerVASTART(Op, DAG); + case ISD::FCOPYSIGN: return lowerFCOPYSIGN(Op, DAG); + case ISD::FABS: return lowerFABS(Op, DAG); + case ISD::FRAMEADDR: return lowerFRAMEADDR(Op, DAG); + case ISD::RETURNADDR: return lowerRETURNADDR(Op, DAG); + case ISD::EH_RETURN: return lowerEH_RETURN(Op, DAG); + case ISD::ATOMIC_FENCE: return lowerATOMIC_FENCE(Op, DAG); + case ISD::SHL_PARTS: return lowerShiftLeftParts(Op, DAG); + case ISD::SRA_PARTS: return lowerShiftRightParts(Op, DAG, true); + case ISD::SRL_PARTS: return lowerShiftRightParts(Op, DAG, false); + case ISD::LOAD: return lowerLOAD(Op, DAG); + case ISD::STORE: return lowerSTORE(Op, DAG); + case ISD::ADD: return lowerADD(Op, DAG); + case ISD::FP_TO_SINT: return lowerFP_TO_SINT(Op, DAG); + } + return SDValue(); +} + +//===----------------------------------------------------------------------===// +// Lower helper functions +//===----------------------------------------------------------------------===// + +// addLiveIn - This helper function adds the specified physical register to the +// MachineFunction as a live in value. It also creates a corresponding +// virtual register for it. +static unsigned +addLiveIn(MachineFunction &MF, unsigned PReg, const TargetRegisterClass *RC) +{ + unsigned VReg = MF.getRegInfo().createVirtualRegister(RC); + MF.getRegInfo().addLiveIn(PReg, VReg); + return VReg; +} + +static MachineBasicBlock *expandPseudoDIV(MachineInstr *MI, + MachineBasicBlock &MBB, + const TargetInstrInfo &TII, + bool Is64Bit) { + if (NoZeroDivCheck) + return &MBB; + + // Insert instruction "teq $divisor_reg, $zero, 7". + MachineBasicBlock::iterator I(MI); + MachineInstrBuilder MIB; + MachineOperand &Divisor = MI->getOperand(2); + MIB = BuildMI(MBB, llvm::next(I), MI->getDebugLoc(), TII.get(Mips::TEQ)) + .addReg(Divisor.getReg(), getKillRegState(Divisor.isKill())) + .addReg(Mips::ZERO).addImm(7); + + // Use the 32-bit sub-register if this is a 64-bit division. + if (Is64Bit) + MIB->getOperand(0).setSubReg(Mips::sub_32); + + // Clear Divisor's kill flag. + Divisor.setIsKill(false); + return &MBB; +} + +MachineBasicBlock * +MipsTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + switch (MI->getOpcode()) { + default: + llvm_unreachable("Unexpected instr type to insert"); + case Mips::ATOMIC_LOAD_ADD_I8: + return emitAtomicBinaryPartword(MI, BB, 1, Mips::ADDu); + case Mips::ATOMIC_LOAD_ADD_I16: + return emitAtomicBinaryPartword(MI, BB, 2, Mips::ADDu); + case Mips::ATOMIC_LOAD_ADD_I32: + return emitAtomicBinary(MI, BB, 4, Mips::ADDu); + case Mips::ATOMIC_LOAD_ADD_I64: + return emitAtomicBinary(MI, BB, 8, Mips::DADDu); + + case Mips::ATOMIC_LOAD_AND_I8: + return emitAtomicBinaryPartword(MI, BB, 1, Mips::AND); + case Mips::ATOMIC_LOAD_AND_I16: + return emitAtomicBinaryPartword(MI, BB, 2, Mips::AND); + case Mips::ATOMIC_LOAD_AND_I32: + return emitAtomicBinary(MI, BB, 4, Mips::AND); + case Mips::ATOMIC_LOAD_AND_I64: + return emitAtomicBinary(MI, BB, 8, Mips::AND64); + + case Mips::ATOMIC_LOAD_OR_I8: + return emitAtomicBinaryPartword(MI, BB, 1, Mips::OR); + case Mips::ATOMIC_LOAD_OR_I16: + return emitAtomicBinaryPartword(MI, BB, 2, Mips::OR); + case Mips::ATOMIC_LOAD_OR_I32: + return emitAtomicBinary(MI, BB, 4, Mips::OR); + case Mips::ATOMIC_LOAD_OR_I64: + return emitAtomicBinary(MI, BB, 8, Mips::OR64); + + case Mips::ATOMIC_LOAD_XOR_I8: + return emitAtomicBinaryPartword(MI, BB, 1, Mips::XOR); + case Mips::ATOMIC_LOAD_XOR_I16: + return emitAtomicBinaryPartword(MI, BB, 2, Mips::XOR); + case Mips::ATOMIC_LOAD_XOR_I32: + return emitAtomicBinary(MI, BB, 4, Mips::XOR); + case Mips::ATOMIC_LOAD_XOR_I64: + return emitAtomicBinary(MI, BB, 8, Mips::XOR64); + + case Mips::ATOMIC_LOAD_NAND_I8: + return emitAtomicBinaryPartword(MI, BB, 1, 0, true); + case Mips::ATOMIC_LOAD_NAND_I16: + return emitAtomicBinaryPartword(MI, BB, 2, 0, true); + case Mips::ATOMIC_LOAD_NAND_I32: + return emitAtomicBinary(MI, BB, 4, 0, true); + case Mips::ATOMIC_LOAD_NAND_I64: + return emitAtomicBinary(MI, BB, 8, 0, true); + + case Mips::ATOMIC_LOAD_SUB_I8: + return emitAtomicBinaryPartword(MI, BB, 1, Mips::SUBu); + case Mips::ATOMIC_LOAD_SUB_I16: + return emitAtomicBinaryPartword(MI, BB, 2, Mips::SUBu); + case Mips::ATOMIC_LOAD_SUB_I32: + return emitAtomicBinary(MI, BB, 4, Mips::SUBu); + case Mips::ATOMIC_LOAD_SUB_I64: + return emitAtomicBinary(MI, BB, 8, Mips::DSUBu); + + case Mips::ATOMIC_SWAP_I8: + return emitAtomicBinaryPartword(MI, BB, 1, 0); + case Mips::ATOMIC_SWAP_I16: + return emitAtomicBinaryPartword(MI, BB, 2, 0); + case Mips::ATOMIC_SWAP_I32: + return emitAtomicBinary(MI, BB, 4, 0); + case Mips::ATOMIC_SWAP_I64: + return emitAtomicBinary(MI, BB, 8, 0); + + case Mips::ATOMIC_CMP_SWAP_I8: + return emitAtomicCmpSwapPartword(MI, BB, 1); + case Mips::ATOMIC_CMP_SWAP_I16: + return emitAtomicCmpSwapPartword(MI, BB, 2); + case Mips::ATOMIC_CMP_SWAP_I32: + return emitAtomicCmpSwap(MI, BB, 4); + case Mips::ATOMIC_CMP_SWAP_I64: + return emitAtomicCmpSwap(MI, BB, 8); + case Mips::PseudoSDIV: + case Mips::PseudoUDIV: + return expandPseudoDIV(MI, *BB, *getTargetMachine().getInstrInfo(), false); + case Mips::PseudoDSDIV: + case Mips::PseudoDUDIV: + return expandPseudoDIV(MI, *BB, *getTargetMachine().getInstrInfo(), true); + } +} + +// This function also handles Mips::ATOMIC_SWAP_I32 (when BinOpcode == 0), and +// Mips::ATOMIC_LOAD_NAND_I32 (when Nand == true) +MachineBasicBlock * +MipsTargetLowering::emitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, + unsigned Size, unsigned BinOpcode, + bool Nand) const { + assert((Size == 4 || Size == 8) && "Unsupported size for EmitAtomicBinary."); + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::getIntegerVT(Size * 8)); + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned LL, SC, AND, NOR, ZERO, BEQ; + + if (Size == 4) { + LL = Mips::LL; + SC = Mips::SC; + AND = Mips::AND; + NOR = Mips::NOR; + ZERO = Mips::ZERO; + BEQ = Mips::BEQ; + } + else { + LL = Mips::LLD; + SC = Mips::SCD; + AND = Mips::AND64; + NOR = Mips::NOR64; + ZERO = Mips::ZERO_64; + BEQ = Mips::BEQ64; + } + + unsigned OldVal = MI->getOperand(0).getReg(); + unsigned Ptr = MI->getOperand(1).getReg(); + unsigned Incr = MI->getOperand(2).getReg(); + + unsigned StoreVal = RegInfo.createVirtualRegister(RC); + unsigned AndRes = RegInfo.createVirtualRegister(RC); + unsigned Success = RegInfo.createVirtualRegister(RC); + + // insert new blocks after the current block + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineBasicBlock *loopMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineFunction::iterator It = BB; + ++It; + MF->insert(It, loopMBB); + MF->insert(It, exitMBB); + + // Transfer the remainder of BB and its successor edges to exitMBB. + exitMBB->splice(exitMBB->begin(), BB, + llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); + exitMBB->transferSuccessorsAndUpdatePHIs(BB); + + // thisMBB: + // ... + // fallthrough --> loopMBB + BB->addSuccessor(loopMBB); + loopMBB->addSuccessor(loopMBB); + loopMBB->addSuccessor(exitMBB); + + // loopMBB: + // ll oldval, 0(ptr) + // <binop> storeval, oldval, incr + // sc success, storeval, 0(ptr) + // beq success, $0, loopMBB + BB = loopMBB; + BuildMI(BB, DL, TII->get(LL), OldVal).addReg(Ptr).addImm(0); + if (Nand) { + // and andres, oldval, incr + // nor storeval, $0, andres + BuildMI(BB, DL, TII->get(AND), AndRes).addReg(OldVal).addReg(Incr); + BuildMI(BB, DL, TII->get(NOR), StoreVal).addReg(ZERO).addReg(AndRes); + } else if (BinOpcode) { + // <binop> storeval, oldval, incr + BuildMI(BB, DL, TII->get(BinOpcode), StoreVal).addReg(OldVal).addReg(Incr); + } else { + StoreVal = Incr; + } + BuildMI(BB, DL, TII->get(SC), Success).addReg(StoreVal).addReg(Ptr).addImm(0); + BuildMI(BB, DL, TII->get(BEQ)).addReg(Success).addReg(ZERO).addMBB(loopMBB); + + MI->eraseFromParent(); // The instruction is gone now. + + return exitMBB; +} + +MachineBasicBlock * +MipsTargetLowering::emitAtomicBinaryPartword(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned Size, unsigned BinOpcode, + bool Nand) const { + assert((Size == 1 || Size == 2) && + "Unsupported size for EmitAtomicBinaryPartial."); + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + + unsigned Dest = MI->getOperand(0).getReg(); + unsigned Ptr = MI->getOperand(1).getReg(); + unsigned Incr = MI->getOperand(2).getReg(); + + unsigned AlignedAddr = RegInfo.createVirtualRegister(RC); + unsigned ShiftAmt = RegInfo.createVirtualRegister(RC); + unsigned Mask = RegInfo.createVirtualRegister(RC); + unsigned Mask2 = RegInfo.createVirtualRegister(RC); + unsigned NewVal = RegInfo.createVirtualRegister(RC); + unsigned OldVal = RegInfo.createVirtualRegister(RC); + unsigned Incr2 = RegInfo.createVirtualRegister(RC); + unsigned MaskLSB2 = RegInfo.createVirtualRegister(RC); + unsigned PtrLSB2 = RegInfo.createVirtualRegister(RC); + unsigned MaskUpper = RegInfo.createVirtualRegister(RC); + unsigned AndRes = RegInfo.createVirtualRegister(RC); + unsigned BinOpRes = RegInfo.createVirtualRegister(RC); + unsigned MaskedOldVal0 = RegInfo.createVirtualRegister(RC); + unsigned StoreVal = RegInfo.createVirtualRegister(RC); + unsigned MaskedOldVal1 = RegInfo.createVirtualRegister(RC); + unsigned SrlRes = RegInfo.createVirtualRegister(RC); + unsigned SllRes = RegInfo.createVirtualRegister(RC); + unsigned Success = RegInfo.createVirtualRegister(RC); + + // insert new blocks after the current block + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineBasicBlock *loopMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineFunction::iterator It = BB; + ++It; + MF->insert(It, loopMBB); + MF->insert(It, sinkMBB); + MF->insert(It, exitMBB); + + // Transfer the remainder of BB and its successor edges to exitMBB. + exitMBB->splice(exitMBB->begin(), BB, + llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); + exitMBB->transferSuccessorsAndUpdatePHIs(BB); + + BB->addSuccessor(loopMBB); + loopMBB->addSuccessor(loopMBB); + loopMBB->addSuccessor(sinkMBB); + sinkMBB->addSuccessor(exitMBB); + + // thisMBB: + // addiu masklsb2,$0,-4 # 0xfffffffc + // and alignedaddr,ptr,masklsb2 + // andi ptrlsb2,ptr,3 + // sll shiftamt,ptrlsb2,3 + // ori maskupper,$0,255 # 0xff + // sll mask,maskupper,shiftamt + // nor mask2,$0,mask + // sll incr2,incr,shiftamt + + int64_t MaskImm = (Size == 1) ? 255 : 65535; + BuildMI(BB, DL, TII->get(Mips::ADDiu), MaskLSB2) + .addReg(Mips::ZERO).addImm(-4); + BuildMI(BB, DL, TII->get(Mips::AND), AlignedAddr) + .addReg(Ptr).addReg(MaskLSB2); + BuildMI(BB, DL, TII->get(Mips::ANDi), PtrLSB2).addReg(Ptr).addImm(3); + if (Subtarget->isLittle()) { + BuildMI(BB, DL, TII->get(Mips::SLL), ShiftAmt).addReg(PtrLSB2).addImm(3); + } else { + unsigned Off = RegInfo.createVirtualRegister(RC); + BuildMI(BB, DL, TII->get(Mips::XORi), Off) + .addReg(PtrLSB2).addImm((Size == 1) ? 3 : 2); + BuildMI(BB, DL, TII->get(Mips::SLL), ShiftAmt).addReg(Off).addImm(3); + } + BuildMI(BB, DL, TII->get(Mips::ORi), MaskUpper) + .addReg(Mips::ZERO).addImm(MaskImm); + BuildMI(BB, DL, TII->get(Mips::SLLV), Mask) + .addReg(MaskUpper).addReg(ShiftAmt); + BuildMI(BB, DL, TII->get(Mips::NOR), Mask2).addReg(Mips::ZERO).addReg(Mask); + BuildMI(BB, DL, TII->get(Mips::SLLV), Incr2).addReg(Incr).addReg(ShiftAmt); + + // atomic.load.binop + // loopMBB: + // ll oldval,0(alignedaddr) + // binop binopres,oldval,incr2 + // and newval,binopres,mask + // and maskedoldval0,oldval,mask2 + // or storeval,maskedoldval0,newval + // sc success,storeval,0(alignedaddr) + // beq success,$0,loopMBB + + // atomic.swap + // loopMBB: + // ll oldval,0(alignedaddr) + // and newval,incr2,mask + // and maskedoldval0,oldval,mask2 + // or storeval,maskedoldval0,newval + // sc success,storeval,0(alignedaddr) + // beq success,$0,loopMBB + + BB = loopMBB; + BuildMI(BB, DL, TII->get(Mips::LL), OldVal).addReg(AlignedAddr).addImm(0); + if (Nand) { + // and andres, oldval, incr2 + // nor binopres, $0, andres + // and newval, binopres, mask + BuildMI(BB, DL, TII->get(Mips::AND), AndRes).addReg(OldVal).addReg(Incr2); + BuildMI(BB, DL, TII->get(Mips::NOR), BinOpRes) + .addReg(Mips::ZERO).addReg(AndRes); + BuildMI(BB, DL, TII->get(Mips::AND), NewVal).addReg(BinOpRes).addReg(Mask); + } else if (BinOpcode) { + // <binop> binopres, oldval, incr2 + // and newval, binopres, mask + BuildMI(BB, DL, TII->get(BinOpcode), BinOpRes).addReg(OldVal).addReg(Incr2); + BuildMI(BB, DL, TII->get(Mips::AND), NewVal).addReg(BinOpRes).addReg(Mask); + } else { // atomic.swap + // and newval, incr2, mask + BuildMI(BB, DL, TII->get(Mips::AND), NewVal).addReg(Incr2).addReg(Mask); + } + + BuildMI(BB, DL, TII->get(Mips::AND), MaskedOldVal0) + .addReg(OldVal).addReg(Mask2); + BuildMI(BB, DL, TII->get(Mips::OR), StoreVal) + .addReg(MaskedOldVal0).addReg(NewVal); + BuildMI(BB, DL, TII->get(Mips::SC), Success) + .addReg(StoreVal).addReg(AlignedAddr).addImm(0); + BuildMI(BB, DL, TII->get(Mips::BEQ)) + .addReg(Success).addReg(Mips::ZERO).addMBB(loopMBB); + + // sinkMBB: + // and maskedoldval1,oldval,mask + // srl srlres,maskedoldval1,shiftamt + // sll sllres,srlres,24 + // sra dest,sllres,24 + BB = sinkMBB; + int64_t ShiftImm = (Size == 1) ? 24 : 16; + + BuildMI(BB, DL, TII->get(Mips::AND), MaskedOldVal1) + .addReg(OldVal).addReg(Mask); + BuildMI(BB, DL, TII->get(Mips::SRLV), SrlRes) + .addReg(MaskedOldVal1).addReg(ShiftAmt); + BuildMI(BB, DL, TII->get(Mips::SLL), SllRes) + .addReg(SrlRes).addImm(ShiftImm); + BuildMI(BB, DL, TII->get(Mips::SRA), Dest) + .addReg(SllRes).addImm(ShiftImm); + + MI->eraseFromParent(); // The instruction is gone now. + + return exitMBB; +} + +MachineBasicBlock * MipsTargetLowering::emitAtomicCmpSwap(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned Size) const { + assert((Size == 4 || Size == 8) && "Unsupported size for EmitAtomicCmpSwap."); + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::getIntegerVT(Size * 8)); + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned LL, SC, ZERO, BNE, BEQ; + + if (Size == 4) { + LL = Mips::LL; + SC = Mips::SC; + ZERO = Mips::ZERO; + BNE = Mips::BNE; + BEQ = Mips::BEQ; + } else { + LL = Mips::LLD; + SC = Mips::SCD; + ZERO = Mips::ZERO_64; + BNE = Mips::BNE64; + BEQ = Mips::BEQ64; + } + + unsigned Dest = MI->getOperand(0).getReg(); + unsigned Ptr = MI->getOperand(1).getReg(); + unsigned OldVal = MI->getOperand(2).getReg(); + unsigned NewVal = MI->getOperand(3).getReg(); + + unsigned Success = RegInfo.createVirtualRegister(RC); + + // insert new blocks after the current block + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineBasicBlock *loop1MBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *loop2MBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineFunction::iterator It = BB; + ++It; + MF->insert(It, loop1MBB); + MF->insert(It, loop2MBB); + MF->insert(It, exitMBB); + + // Transfer the remainder of BB and its successor edges to exitMBB. + exitMBB->splice(exitMBB->begin(), BB, + llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); + exitMBB->transferSuccessorsAndUpdatePHIs(BB); + + // thisMBB: + // ... + // fallthrough --> loop1MBB + BB->addSuccessor(loop1MBB); + loop1MBB->addSuccessor(exitMBB); + loop1MBB->addSuccessor(loop2MBB); + loop2MBB->addSuccessor(loop1MBB); + loop2MBB->addSuccessor(exitMBB); + + // loop1MBB: + // ll dest, 0(ptr) + // bne dest, oldval, exitMBB + BB = loop1MBB; + BuildMI(BB, DL, TII->get(LL), Dest).addReg(Ptr).addImm(0); + BuildMI(BB, DL, TII->get(BNE)) + .addReg(Dest).addReg(OldVal).addMBB(exitMBB); + + // loop2MBB: + // sc success, newval, 0(ptr) + // beq success, $0, loop1MBB + BB = loop2MBB; + BuildMI(BB, DL, TII->get(SC), Success) + .addReg(NewVal).addReg(Ptr).addImm(0); + BuildMI(BB, DL, TII->get(BEQ)) + .addReg(Success).addReg(ZERO).addMBB(loop1MBB); + + MI->eraseFromParent(); // The instruction is gone now. + + return exitMBB; +} + +MachineBasicBlock * +MipsTargetLowering::emitAtomicCmpSwapPartword(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned Size) const { + assert((Size == 1 || Size == 2) && + "Unsupported size for EmitAtomicCmpSwapPartial."); + + MachineFunction *MF = BB->getParent(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i32); + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + DebugLoc DL = MI->getDebugLoc(); + + unsigned Dest = MI->getOperand(0).getReg(); + unsigned Ptr = MI->getOperand(1).getReg(); + unsigned CmpVal = MI->getOperand(2).getReg(); + unsigned NewVal = MI->getOperand(3).getReg(); + + unsigned AlignedAddr = RegInfo.createVirtualRegister(RC); + unsigned ShiftAmt = RegInfo.createVirtualRegister(RC); + unsigned Mask = RegInfo.createVirtualRegister(RC); + unsigned Mask2 = RegInfo.createVirtualRegister(RC); + unsigned ShiftedCmpVal = RegInfo.createVirtualRegister(RC); + unsigned OldVal = RegInfo.createVirtualRegister(RC); + unsigned MaskedOldVal0 = RegInfo.createVirtualRegister(RC); + unsigned ShiftedNewVal = RegInfo.createVirtualRegister(RC); + unsigned MaskLSB2 = RegInfo.createVirtualRegister(RC); + unsigned PtrLSB2 = RegInfo.createVirtualRegister(RC); + unsigned MaskUpper = RegInfo.createVirtualRegister(RC); + unsigned MaskedCmpVal = RegInfo.createVirtualRegister(RC); + unsigned MaskedNewVal = RegInfo.createVirtualRegister(RC); + unsigned MaskedOldVal1 = RegInfo.createVirtualRegister(RC); + unsigned StoreVal = RegInfo.createVirtualRegister(RC); + unsigned SrlRes = RegInfo.createVirtualRegister(RC); + unsigned SllRes = RegInfo.createVirtualRegister(RC); + unsigned Success = RegInfo.createVirtualRegister(RC); + + // insert new blocks after the current block + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineBasicBlock *loop1MBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *loop2MBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineFunction::iterator It = BB; + ++It; + MF->insert(It, loop1MBB); + MF->insert(It, loop2MBB); + MF->insert(It, sinkMBB); + MF->insert(It, exitMBB); + + // Transfer the remainder of BB and its successor edges to exitMBB. + exitMBB->splice(exitMBB->begin(), BB, + llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); + exitMBB->transferSuccessorsAndUpdatePHIs(BB); + + BB->addSuccessor(loop1MBB); + loop1MBB->addSuccessor(sinkMBB); + loop1MBB->addSuccessor(loop2MBB); + loop2MBB->addSuccessor(loop1MBB); + loop2MBB->addSuccessor(sinkMBB); + sinkMBB->addSuccessor(exitMBB); + + // FIXME: computation of newval2 can be moved to loop2MBB. + // thisMBB: + // addiu masklsb2,$0,-4 # 0xfffffffc + // and alignedaddr,ptr,masklsb2 + // andi ptrlsb2,ptr,3 + // sll shiftamt,ptrlsb2,3 + // ori maskupper,$0,255 # 0xff + // sll mask,maskupper,shiftamt + // nor mask2,$0,mask + // andi maskedcmpval,cmpval,255 + // sll shiftedcmpval,maskedcmpval,shiftamt + // andi maskednewval,newval,255 + // sll shiftednewval,maskednewval,shiftamt + int64_t MaskImm = (Size == 1) ? 255 : 65535; + BuildMI(BB, DL, TII->get(Mips::ADDiu), MaskLSB2) + .addReg(Mips::ZERO).addImm(-4); + BuildMI(BB, DL, TII->get(Mips::AND), AlignedAddr) + .addReg(Ptr).addReg(MaskLSB2); + BuildMI(BB, DL, TII->get(Mips::ANDi), PtrLSB2).addReg(Ptr).addImm(3); + if (Subtarget->isLittle()) { + BuildMI(BB, DL, TII->get(Mips::SLL), ShiftAmt).addReg(PtrLSB2).addImm(3); + } else { + unsigned Off = RegInfo.createVirtualRegister(RC); + BuildMI(BB, DL, TII->get(Mips::XORi), Off) + .addReg(PtrLSB2).addImm((Size == 1) ? 3 : 2); + BuildMI(BB, DL, TII->get(Mips::SLL), ShiftAmt).addReg(Off).addImm(3); + } + BuildMI(BB, DL, TII->get(Mips::ORi), MaskUpper) + .addReg(Mips::ZERO).addImm(MaskImm); + BuildMI(BB, DL, TII->get(Mips::SLLV), Mask) + .addReg(MaskUpper).addReg(ShiftAmt); + BuildMI(BB, DL, TII->get(Mips::NOR), Mask2).addReg(Mips::ZERO).addReg(Mask); + BuildMI(BB, DL, TII->get(Mips::ANDi), MaskedCmpVal) + .addReg(CmpVal).addImm(MaskImm); + BuildMI(BB, DL, TII->get(Mips::SLLV), ShiftedCmpVal) + .addReg(MaskedCmpVal).addReg(ShiftAmt); + BuildMI(BB, DL, TII->get(Mips::ANDi), MaskedNewVal) + .addReg(NewVal).addImm(MaskImm); + BuildMI(BB, DL, TII->get(Mips::SLLV), ShiftedNewVal) + .addReg(MaskedNewVal).addReg(ShiftAmt); + + // loop1MBB: + // ll oldval,0(alginedaddr) + // and maskedoldval0,oldval,mask + // bne maskedoldval0,shiftedcmpval,sinkMBB + BB = loop1MBB; + BuildMI(BB, DL, TII->get(Mips::LL), OldVal).addReg(AlignedAddr).addImm(0); + BuildMI(BB, DL, TII->get(Mips::AND), MaskedOldVal0) + .addReg(OldVal).addReg(Mask); + BuildMI(BB, DL, TII->get(Mips::BNE)) + .addReg(MaskedOldVal0).addReg(ShiftedCmpVal).addMBB(sinkMBB); + + // loop2MBB: + // and maskedoldval1,oldval,mask2 + // or storeval,maskedoldval1,shiftednewval + // sc success,storeval,0(alignedaddr) + // beq success,$0,loop1MBB + BB = loop2MBB; + BuildMI(BB, DL, TII->get(Mips::AND), MaskedOldVal1) + .addReg(OldVal).addReg(Mask2); + BuildMI(BB, DL, TII->get(Mips::OR), StoreVal) + .addReg(MaskedOldVal1).addReg(ShiftedNewVal); + BuildMI(BB, DL, TII->get(Mips::SC), Success) + .addReg(StoreVal).addReg(AlignedAddr).addImm(0); + BuildMI(BB, DL, TII->get(Mips::BEQ)) + .addReg(Success).addReg(Mips::ZERO).addMBB(loop1MBB); + + // sinkMBB: + // srl srlres,maskedoldval0,shiftamt + // sll sllres,srlres,24 + // sra dest,sllres,24 + BB = sinkMBB; + int64_t ShiftImm = (Size == 1) ? 24 : 16; + + BuildMI(BB, DL, TII->get(Mips::SRLV), SrlRes) + .addReg(MaskedOldVal0).addReg(ShiftAmt); + BuildMI(BB, DL, TII->get(Mips::SLL), SllRes) + .addReg(SrlRes).addImm(ShiftImm); + BuildMI(BB, DL, TII->get(Mips::SRA), Dest) + .addReg(SllRes).addImm(ShiftImm); + + MI->eraseFromParent(); // The instruction is gone now. + + return exitMBB; +} + +//===----------------------------------------------------------------------===// +// Misc Lower Operation implementation +//===----------------------------------------------------------------------===// +SDValue MipsTargetLowering::lowerBR_JT(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + SDValue Table = Op.getOperand(1); + SDValue Index = Op.getOperand(2); + SDLoc DL(Op); + EVT PTy = getPointerTy(); + unsigned EntrySize = + DAG.getMachineFunction().getJumpTableInfo()->getEntrySize(*getDataLayout()); + + Index = DAG.getNode(ISD::MUL, DL, PTy, Index, + DAG.getConstant(EntrySize, PTy)); + SDValue Addr = DAG.getNode(ISD::ADD, DL, PTy, Index, Table); + + EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), EntrySize * 8); + Addr = DAG.getExtLoad(ISD::SEXTLOAD, DL, PTy, Chain, Addr, + MachinePointerInfo::getJumpTable(), MemVT, false, false, + 0); + Chain = Addr.getValue(1); + + if ((getTargetMachine().getRelocationModel() == Reloc::PIC_) || IsN64) { + // For PIC, the sequence is: + // BRIND(load(Jumptable + index) + RelocBase) + // RelocBase can be JumpTable, GOT or some sort of global base. + Addr = DAG.getNode(ISD::ADD, DL, PTy, Addr, + getPICJumpTableRelocBase(Table, DAG)); + } + + return DAG.getNode(ISD::BRIND, DL, MVT::Other, Chain, Addr); +} + +SDValue MipsTargetLowering::lowerBRCOND(SDValue Op, SelectionDAG &DAG) const { + // The first operand is the chain, the second is the condition, the third is + // the block to branch to if the condition is true. + SDValue Chain = Op.getOperand(0); + SDValue Dest = Op.getOperand(2); + SDLoc DL(Op); + + SDValue CondRes = createFPCmp(DAG, Op.getOperand(1)); + + // Return if flag is not set by a floating point comparison. + if (CondRes.getOpcode() != MipsISD::FPCmp) + return Op; + + SDValue CCNode = CondRes.getOperand(2); + Mips::CondCode CC = + (Mips::CondCode)cast<ConstantSDNode>(CCNode)->getZExtValue(); + unsigned Opc = invertFPCondCodeUser(CC) ? Mips::BRANCH_F : Mips::BRANCH_T; + SDValue BrCode = DAG.getConstant(Opc, MVT::i32); + SDValue FCC0 = DAG.getRegister(Mips::FCC0, MVT::i32); + return DAG.getNode(MipsISD::FPBrcond, DL, Op.getValueType(), Chain, BrCode, + FCC0, Dest, CondRes); +} + +SDValue MipsTargetLowering:: +lowerSELECT(SDValue Op, SelectionDAG &DAG) const +{ + SDValue Cond = createFPCmp(DAG, Op.getOperand(0)); + + // Return if flag is not set by a floating point comparison. + if (Cond.getOpcode() != MipsISD::FPCmp) + return Op; + + return createCMovFP(DAG, Cond, Op.getOperand(1), Op.getOperand(2), + SDLoc(Op)); +} + +SDValue MipsTargetLowering:: +lowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const +{ + SDLoc DL(Op); + EVT Ty = Op.getOperand(0).getValueType(); + SDValue Cond = DAG.getNode(ISD::SETCC, DL, + getSetCCResultType(*DAG.getContext(), Ty), + Op.getOperand(0), Op.getOperand(1), + Op.getOperand(4)); + + return DAG.getNode(ISD::SELECT, DL, Op.getValueType(), Cond, Op.getOperand(2), + Op.getOperand(3)); +} + +SDValue MipsTargetLowering::lowerSETCC(SDValue Op, SelectionDAG &DAG) const { + SDValue Cond = createFPCmp(DAG, Op); + + assert(Cond.getOpcode() == MipsISD::FPCmp && + "Floating point operand expected."); + + SDValue True = DAG.getConstant(1, MVT::i32); + SDValue False = DAG.getConstant(0, MVT::i32); + + return createCMovFP(DAG, Cond, True, False, SDLoc(Op)); +} + +SDValue MipsTargetLowering::lowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + // FIXME there isn't actually debug info here + SDLoc DL(Op); + EVT Ty = Op.getValueType(); + GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); + const GlobalValue *GV = N->getGlobal(); + + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) { + const MipsTargetObjectFile &TLOF = + (const MipsTargetObjectFile&)getObjFileLowering(); + + // %gp_rel relocation + if (TLOF.IsGlobalInSmallSection(GV, getTargetMachine())) { + SDValue GA = DAG.getTargetGlobalAddress(GV, DL, MVT::i32, 0, + MipsII::MO_GPREL); + SDValue GPRelNode = DAG.getNode(MipsISD::GPRel, DL, + DAG.getVTList(MVT::i32), &GA, 1); + SDValue GPReg = DAG.getRegister(Mips::GP, MVT::i32); + return DAG.getNode(ISD::ADD, DL, MVT::i32, GPReg, GPRelNode); + } + + // %hi/%lo relocation + return getAddrNonPIC(N, Ty, DAG); + } + + if (GV->hasInternalLinkage() || (GV->hasLocalLinkage() && !isa<Function>(GV))) + return getAddrLocal(N, Ty, DAG, HasMips64); + + if (LargeGOT) + return getAddrGlobalLargeGOT(N, Ty, DAG, MipsII::MO_GOT_HI16, + MipsII::MO_GOT_LO16, DAG.getEntryNode(), + MachinePointerInfo::getGOT()); + + return getAddrGlobal(N, Ty, DAG, + HasMips64 ? MipsII::MO_GOT_DISP : MipsII::MO_GOT16, + DAG.getEntryNode(), MachinePointerInfo::getGOT()); +} + +SDValue MipsTargetLowering::lowerBlockAddress(SDValue Op, + SelectionDAG &DAG) const { + BlockAddressSDNode *N = cast<BlockAddressSDNode>(Op); + EVT Ty = Op.getValueType(); + + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) + return getAddrNonPIC(N, Ty, DAG); + + return getAddrLocal(N, Ty, DAG, HasMips64); +} + +SDValue MipsTargetLowering:: +lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const +{ + // If the relocation model is PIC, use the General Dynamic TLS Model or + // Local Dynamic TLS model, otherwise use the Initial Exec or + // Local Exec TLS Model. + + GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op); + SDLoc DL(GA); + const GlobalValue *GV = GA->getGlobal(); + EVT PtrVT = getPointerTy(); + + TLSModel::Model model = getTargetMachine().getTLSModel(GV); + + if (model == TLSModel::GeneralDynamic || model == TLSModel::LocalDynamic) { + // General Dynamic and Local Dynamic TLS Model. + unsigned Flag = (model == TLSModel::LocalDynamic) ? MipsII::MO_TLSLDM + : MipsII::MO_TLSGD; + + SDValue TGA = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, Flag); + SDValue Argument = DAG.getNode(MipsISD::Wrapper, DL, PtrVT, + getGlobalReg(DAG, PtrVT), TGA); + unsigned PtrSize = PtrVT.getSizeInBits(); + IntegerType *PtrTy = Type::getIntNTy(*DAG.getContext(), PtrSize); + + SDValue TlsGetAddr = DAG.getExternalSymbol("__tls_get_addr", PtrVT); + + ArgListTy Args; + ArgListEntry Entry; + Entry.Node = Argument; + Entry.Ty = PtrTy; + Args.push_back(Entry); + + TargetLowering::CallLoweringInfo CLI(DAG.getEntryNode(), PtrTy, + false, false, false, false, 0, CallingConv::C, + /*IsTailCall=*/false, /*doesNotRet=*/false, + /*isReturnValueUsed=*/true, + TlsGetAddr, Args, DAG, DL); + std::pair<SDValue, SDValue> CallResult = LowerCallTo(CLI); + + SDValue Ret = CallResult.first; + + if (model != TLSModel::LocalDynamic) + return Ret; + + SDValue TGAHi = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, + MipsII::MO_DTPREL_HI); + SDValue Hi = DAG.getNode(MipsISD::Hi, DL, PtrVT, TGAHi); + SDValue TGALo = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, + MipsII::MO_DTPREL_LO); + SDValue Lo = DAG.getNode(MipsISD::Lo, DL, PtrVT, TGALo); + SDValue Add = DAG.getNode(ISD::ADD, DL, PtrVT, Hi, Ret); + return DAG.getNode(ISD::ADD, DL, PtrVT, Add, Lo); + } + + SDValue Offset; + if (model == TLSModel::InitialExec) { + // Initial Exec TLS Model + SDValue TGA = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, + MipsII::MO_GOTTPREL); + TGA = DAG.getNode(MipsISD::Wrapper, DL, PtrVT, getGlobalReg(DAG, PtrVT), + TGA); + Offset = DAG.getLoad(PtrVT, DL, + DAG.getEntryNode(), TGA, MachinePointerInfo(), + false, false, false, 0); + } else { + // Local Exec TLS Model + assert(model == TLSModel::LocalExec); + SDValue TGAHi = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, + MipsII::MO_TPREL_HI); + SDValue TGALo = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, + MipsII::MO_TPREL_LO); + SDValue Hi = DAG.getNode(MipsISD::Hi, DL, PtrVT, TGAHi); + SDValue Lo = DAG.getNode(MipsISD::Lo, DL, PtrVT, TGALo); + Offset = DAG.getNode(ISD::ADD, DL, PtrVT, Hi, Lo); + } + + SDValue ThreadPointer = DAG.getNode(MipsISD::ThreadPointer, DL, PtrVT); + return DAG.getNode(ISD::ADD, DL, PtrVT, ThreadPointer, Offset); +} + +SDValue MipsTargetLowering:: +lowerJumpTable(SDValue Op, SelectionDAG &DAG) const +{ + JumpTableSDNode *N = cast<JumpTableSDNode>(Op); + EVT Ty = Op.getValueType(); + + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) + return getAddrNonPIC(N, Ty, DAG); + + return getAddrLocal(N, Ty, DAG, HasMips64); +} + +SDValue MipsTargetLowering:: +lowerConstantPool(SDValue Op, SelectionDAG &DAG) const +{ + // gp_rel relocation + // FIXME: we should reference the constant pool using small data sections, + // but the asm printer currently doesn't support this feature without + // hacking it. This feature should come soon so we can uncomment the + // stuff below. + //if (IsInSmallSection(C->getType())) { + // SDValue GPRelNode = DAG.getNode(MipsISD::GPRel, MVT::i32, CP); + // SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32); + // ResNode = DAG.getNode(ISD::ADD, MVT::i32, GOT, GPRelNode); + ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); + EVT Ty = Op.getValueType(); + + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) + return getAddrNonPIC(N, Ty, DAG); + + return getAddrLocal(N, Ty, DAG, HasMips64); +} + +SDValue MipsTargetLowering::lowerVASTART(SDValue Op, SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + MipsFunctionInfo *FuncInfo = MF.getInfo<MipsFunctionInfo>(); + + SDLoc DL(Op); + 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); +} + +static SDValue lowerFCOPYSIGN32(SDValue Op, SelectionDAG &DAG, + bool HasExtractInsert) { + EVT TyX = Op.getOperand(0).getValueType(); + EVT TyY = Op.getOperand(1).getValueType(); + SDValue Const1 = DAG.getConstant(1, MVT::i32); + SDValue Const31 = DAG.getConstant(31, MVT::i32); + SDLoc DL(Op); + SDValue Res; + + // If operand is of type f64, extract the upper 32-bit. Otherwise, bitcast it + // to i32. + SDValue X = (TyX == MVT::f32) ? + DAG.getNode(ISD::BITCAST, DL, MVT::i32, Op.getOperand(0)) : + DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, Op.getOperand(0), + Const1); + SDValue Y = (TyY == MVT::f32) ? + DAG.getNode(ISD::BITCAST, DL, MVT::i32, Op.getOperand(1)) : + DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, Op.getOperand(1), + Const1); + + if (HasExtractInsert) { + // ext E, Y, 31, 1 ; extract bit31 of Y + // ins X, E, 31, 1 ; insert extracted bit at bit31 of X + SDValue E = DAG.getNode(MipsISD::Ext, DL, MVT::i32, Y, Const31, Const1); + Res = DAG.getNode(MipsISD::Ins, DL, MVT::i32, E, Const31, Const1, X); + } else { + // sll SllX, X, 1 + // srl SrlX, SllX, 1 + // srl SrlY, Y, 31 + // sll SllY, SrlX, 31 + // or Or, SrlX, SllY + SDValue SllX = DAG.getNode(ISD::SHL, DL, MVT::i32, X, Const1); + SDValue SrlX = DAG.getNode(ISD::SRL, DL, MVT::i32, SllX, Const1); + SDValue SrlY = DAG.getNode(ISD::SRL, DL, MVT::i32, Y, Const31); + SDValue SllY = DAG.getNode(ISD::SHL, DL, MVT::i32, SrlY, Const31); + Res = DAG.getNode(ISD::OR, DL, MVT::i32, SrlX, SllY); + } + + if (TyX == MVT::f32) + return DAG.getNode(ISD::BITCAST, DL, Op.getOperand(0).getValueType(), Res); + + SDValue LowX = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Op.getOperand(0), DAG.getConstant(0, MVT::i32)); + return DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, LowX, Res); +} + +static SDValue lowerFCOPYSIGN64(SDValue Op, SelectionDAG &DAG, + bool HasExtractInsert) { + unsigned WidthX = Op.getOperand(0).getValueSizeInBits(); + unsigned WidthY = Op.getOperand(1).getValueSizeInBits(); + EVT TyX = MVT::getIntegerVT(WidthX), TyY = MVT::getIntegerVT(WidthY); + SDValue Const1 = DAG.getConstant(1, MVT::i32); + SDLoc DL(Op); + + // Bitcast to integer nodes. + SDValue X = DAG.getNode(ISD::BITCAST, DL, TyX, Op.getOperand(0)); + SDValue Y = DAG.getNode(ISD::BITCAST, DL, TyY, Op.getOperand(1)); + + if (HasExtractInsert) { + // ext E, Y, width(Y) - 1, 1 ; extract bit width(Y)-1 of Y + // ins X, E, width(X) - 1, 1 ; insert extracted bit at bit width(X)-1 of X + SDValue E = DAG.getNode(MipsISD::Ext, DL, TyY, Y, + DAG.getConstant(WidthY - 1, MVT::i32), Const1); + + if (WidthX > WidthY) + E = DAG.getNode(ISD::ZERO_EXTEND, DL, TyX, E); + else if (WidthY > WidthX) + E = DAG.getNode(ISD::TRUNCATE, DL, TyX, E); + + SDValue I = DAG.getNode(MipsISD::Ins, DL, TyX, E, + DAG.getConstant(WidthX - 1, MVT::i32), Const1, X); + return DAG.getNode(ISD::BITCAST, DL, Op.getOperand(0).getValueType(), I); + } + + // (d)sll SllX, X, 1 + // (d)srl SrlX, SllX, 1 + // (d)srl SrlY, Y, width(Y)-1 + // (d)sll SllY, SrlX, width(Y)-1 + // or Or, SrlX, SllY + SDValue SllX = DAG.getNode(ISD::SHL, DL, TyX, X, Const1); + SDValue SrlX = DAG.getNode(ISD::SRL, DL, TyX, SllX, Const1); + SDValue SrlY = DAG.getNode(ISD::SRL, DL, TyY, Y, + DAG.getConstant(WidthY - 1, MVT::i32)); + + if (WidthX > WidthY) + SrlY = DAG.getNode(ISD::ZERO_EXTEND, DL, TyX, SrlY); + else if (WidthY > WidthX) + SrlY = DAG.getNode(ISD::TRUNCATE, DL, TyX, SrlY); + + SDValue SllY = DAG.getNode(ISD::SHL, DL, TyX, SrlY, + DAG.getConstant(WidthX - 1, MVT::i32)); + SDValue Or = DAG.getNode(ISD::OR, DL, TyX, SrlX, SllY); + return DAG.getNode(ISD::BITCAST, DL, Op.getOperand(0).getValueType(), Or); +} + +SDValue +MipsTargetLowering::lowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const { + if (Subtarget->hasMips64()) + return lowerFCOPYSIGN64(Op, DAG, Subtarget->hasExtractInsert()); + + return lowerFCOPYSIGN32(Op, DAG, Subtarget->hasExtractInsert()); +} + +static SDValue lowerFABS32(SDValue Op, SelectionDAG &DAG, + bool HasExtractInsert) { + SDValue Res, Const1 = DAG.getConstant(1, MVT::i32); + SDLoc DL(Op); + + // If operand is of type f64, extract the upper 32-bit. Otherwise, bitcast it + // to i32. + SDValue X = (Op.getValueType() == MVT::f32) ? + DAG.getNode(ISD::BITCAST, DL, MVT::i32, Op.getOperand(0)) : + DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, Op.getOperand(0), + Const1); + + // Clear MSB. + if (HasExtractInsert) + Res = DAG.getNode(MipsISD::Ins, DL, MVT::i32, + DAG.getRegister(Mips::ZERO, MVT::i32), + DAG.getConstant(31, MVT::i32), Const1, X); + else { + SDValue SllX = DAG.getNode(ISD::SHL, DL, MVT::i32, X, Const1); + Res = DAG.getNode(ISD::SRL, DL, MVT::i32, SllX, Const1); + } + + if (Op.getValueType() == MVT::f32) + return DAG.getNode(ISD::BITCAST, DL, MVT::f32, Res); + + SDValue LowX = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Op.getOperand(0), DAG.getConstant(0, MVT::i32)); + return DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, LowX, Res); +} + +static SDValue lowerFABS64(SDValue Op, SelectionDAG &DAG, + bool HasExtractInsert) { + SDValue Res, Const1 = DAG.getConstant(1, MVT::i32); + SDLoc DL(Op); + + // Bitcast to integer node. + SDValue X = DAG.getNode(ISD::BITCAST, DL, MVT::i64, Op.getOperand(0)); + + // Clear MSB. + if (HasExtractInsert) + Res = DAG.getNode(MipsISD::Ins, DL, MVT::i64, + DAG.getRegister(Mips::ZERO_64, MVT::i64), + DAG.getConstant(63, MVT::i32), Const1, X); + else { + SDValue SllX = DAG.getNode(ISD::SHL, DL, MVT::i64, X, Const1); + Res = DAG.getNode(ISD::SRL, DL, MVT::i64, SllX, Const1); + } + + return DAG.getNode(ISD::BITCAST, DL, MVT::f64, Res); +} + +SDValue +MipsTargetLowering::lowerFABS(SDValue Op, SelectionDAG &DAG) const { + if (Subtarget->hasMips64() && (Op.getValueType() == MVT::f64)) + return lowerFABS64(Op, DAG, Subtarget->hasExtractInsert()); + + return lowerFABS32(Op, DAG, Subtarget->hasExtractInsert()); +} + +SDValue MipsTargetLowering:: +lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { + // check the depth + assert((cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() == 0) && + "Frame address can only be determined for current frame."); + + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MFI->setFrameAddressIsTaken(true); + EVT VT = Op.getValueType(); + SDLoc DL(Op); + SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, + IsN64 ? Mips::FP_64 : Mips::FP, VT); + return FrameAddr; +} + +SDValue MipsTargetLowering::lowerRETURNADDR(SDValue Op, + SelectionDAG &DAG) const { + // check the depth + assert((cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue() == 0) && + "Return address can be determined only for current frame."); + + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MVT VT = Op.getSimpleValueType(); + unsigned RA = IsN64 ? Mips::RA_64 : Mips::RA; + MFI->setReturnAddressIsTaken(true); + + // Return RA, which contains the return address. Mark it an implicit live-in. + unsigned Reg = MF.addLiveIn(RA, getRegClassFor(VT)); + return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op), Reg, VT); +} + +// An EH_RETURN is the result of lowering llvm.eh.return which in turn is +// generated from __builtin_eh_return (offset, handler) +// The effect of this is to adjust the stack pointer by "offset" +// and then branch to "handler". +SDValue MipsTargetLowering::lowerEH_RETURN(SDValue Op, SelectionDAG &DAG) + const { + MachineFunction &MF = DAG.getMachineFunction(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + MipsFI->setCallsEhReturn(); + SDValue Chain = Op.getOperand(0); + SDValue Offset = Op.getOperand(1); + SDValue Handler = Op.getOperand(2); + SDLoc DL(Op); + EVT Ty = IsN64 ? MVT::i64 : MVT::i32; + + // Store stack offset in V1, store jump target in V0. Glue CopyToReg and + // EH_RETURN nodes, so that instructions are emitted back-to-back. + unsigned OffsetReg = IsN64 ? Mips::V1_64 : Mips::V1; + unsigned AddrReg = IsN64 ? Mips::V0_64 : Mips::V0; + Chain = DAG.getCopyToReg(Chain, DL, OffsetReg, Offset, SDValue()); + Chain = DAG.getCopyToReg(Chain, DL, AddrReg, Handler, Chain.getValue(1)); + return DAG.getNode(MipsISD::EH_RETURN, DL, MVT::Other, Chain, + DAG.getRegister(OffsetReg, Ty), + DAG.getRegister(AddrReg, getPointerTy()), + Chain.getValue(1)); +} + +SDValue MipsTargetLowering::lowerATOMIC_FENCE(SDValue Op, + SelectionDAG &DAG) const { + // FIXME: Need pseudo-fence for 'singlethread' fences + // FIXME: Set SType for weaker fences where supported/appropriate. + unsigned SType = 0; + SDLoc DL(Op); + return DAG.getNode(MipsISD::Sync, DL, MVT::Other, Op.getOperand(0), + DAG.getConstant(SType, MVT::i32)); +} + +SDValue MipsTargetLowering::lowerShiftLeftParts(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + SDValue Lo = Op.getOperand(0), Hi = Op.getOperand(1); + SDValue Shamt = Op.getOperand(2); + + // if shamt < 32: + // lo = (shl lo, shamt) + // hi = (or (shl hi, shamt) (srl (srl lo, 1), ~shamt)) + // else: + // lo = 0 + // hi = (shl lo, shamt[4:0]) + SDValue Not = DAG.getNode(ISD::XOR, DL, MVT::i32, Shamt, + DAG.getConstant(-1, MVT::i32)); + SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, MVT::i32, Lo, + DAG.getConstant(1, MVT::i32)); + SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, MVT::i32, ShiftRight1Lo, + Not); + SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, MVT::i32, Hi, Shamt); + SDValue Or = DAG.getNode(ISD::OR, DL, MVT::i32, ShiftLeftHi, ShiftRightLo); + SDValue ShiftLeftLo = DAG.getNode(ISD::SHL, DL, MVT::i32, Lo, Shamt); + SDValue Cond = DAG.getNode(ISD::AND, DL, MVT::i32, Shamt, + DAG.getConstant(0x20, MVT::i32)); + Lo = DAG.getNode(ISD::SELECT, DL, MVT::i32, Cond, + DAG.getConstant(0, MVT::i32), ShiftLeftLo); + Hi = DAG.getNode(ISD::SELECT, DL, MVT::i32, Cond, ShiftLeftLo, Or); + + SDValue Ops[2] = {Lo, Hi}; + return DAG.getMergeValues(Ops, 2, DL); +} + +SDValue MipsTargetLowering::lowerShiftRightParts(SDValue Op, SelectionDAG &DAG, + bool IsSRA) const { + SDLoc DL(Op); + SDValue Lo = Op.getOperand(0), Hi = Op.getOperand(1); + SDValue Shamt = Op.getOperand(2); + + // if shamt < 32: + // lo = (or (shl (shl hi, 1), ~shamt) (srl lo, shamt)) + // if isSRA: + // hi = (sra hi, shamt) + // else: + // hi = (srl hi, shamt) + // else: + // if isSRA: + // lo = (sra hi, shamt[4:0]) + // hi = (sra hi, 31) + // else: + // lo = (srl hi, shamt[4:0]) + // hi = 0 + SDValue Not = DAG.getNode(ISD::XOR, DL, MVT::i32, Shamt, + DAG.getConstant(-1, MVT::i32)); + SDValue ShiftLeft1Hi = DAG.getNode(ISD::SHL, DL, MVT::i32, Hi, + DAG.getConstant(1, MVT::i32)); + SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, MVT::i32, ShiftLeft1Hi, Not); + SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, MVT::i32, Lo, Shamt); + SDValue Or = DAG.getNode(ISD::OR, DL, MVT::i32, ShiftLeftHi, ShiftRightLo); + SDValue ShiftRightHi = DAG.getNode(IsSRA ? ISD::SRA : ISD::SRL, DL, MVT::i32, + Hi, Shamt); + SDValue Cond = DAG.getNode(ISD::AND, DL, MVT::i32, Shamt, + DAG.getConstant(0x20, MVT::i32)); + SDValue Shift31 = DAG.getNode(ISD::SRA, DL, MVT::i32, Hi, + DAG.getConstant(31, MVT::i32)); + Lo = DAG.getNode(ISD::SELECT, DL, MVT::i32, Cond, ShiftRightHi, Or); + Hi = DAG.getNode(ISD::SELECT, DL, MVT::i32, Cond, + IsSRA ? Shift31 : DAG.getConstant(0, MVT::i32), + ShiftRightHi); + + SDValue Ops[2] = {Lo, Hi}; + return DAG.getMergeValues(Ops, 2, DL); +} + +static SDValue createLoadLR(unsigned Opc, SelectionDAG &DAG, LoadSDNode *LD, + SDValue Chain, SDValue Src, unsigned Offset) { + SDValue Ptr = LD->getBasePtr(); + EVT VT = LD->getValueType(0), MemVT = LD->getMemoryVT(); + EVT BasePtrVT = Ptr.getValueType(); + SDLoc DL(LD); + SDVTList VTList = DAG.getVTList(VT, MVT::Other); + + if (Offset) + Ptr = DAG.getNode(ISD::ADD, DL, BasePtrVT, Ptr, + DAG.getConstant(Offset, BasePtrVT)); + + SDValue Ops[] = { Chain, Ptr, Src }; + return DAG.getMemIntrinsicNode(Opc, DL, VTList, Ops, 3, MemVT, + LD->getMemOperand()); +} + +// Expand an unaligned 32 or 64-bit integer load node. +SDValue MipsTargetLowering::lowerLOAD(SDValue Op, SelectionDAG &DAG) const { + LoadSDNode *LD = cast<LoadSDNode>(Op); + EVT MemVT = LD->getMemoryVT(); + + // Return if load is aligned or if MemVT is neither i32 nor i64. + if ((LD->getAlignment() >= MemVT.getSizeInBits() / 8) || + ((MemVT != MVT::i32) && (MemVT != MVT::i64))) + return SDValue(); + + bool IsLittle = Subtarget->isLittle(); + EVT VT = Op.getValueType(); + ISD::LoadExtType ExtType = LD->getExtensionType(); + SDValue Chain = LD->getChain(), Undef = DAG.getUNDEF(VT); + + assert((VT == MVT::i32) || (VT == MVT::i64)); + + // Expand + // (set dst, (i64 (load baseptr))) + // to + // (set tmp, (ldl (add baseptr, 7), undef)) + // (set dst, (ldr baseptr, tmp)) + if ((VT == MVT::i64) && (ExtType == ISD::NON_EXTLOAD)) { + SDValue LDL = createLoadLR(MipsISD::LDL, DAG, LD, Chain, Undef, + IsLittle ? 7 : 0); + return createLoadLR(MipsISD::LDR, DAG, LD, LDL.getValue(1), LDL, + IsLittle ? 0 : 7); + } + + SDValue LWL = createLoadLR(MipsISD::LWL, DAG, LD, Chain, Undef, + IsLittle ? 3 : 0); + SDValue LWR = createLoadLR(MipsISD::LWR, DAG, LD, LWL.getValue(1), LWL, + IsLittle ? 0 : 3); + + // Expand + // (set dst, (i32 (load baseptr))) or + // (set dst, (i64 (sextload baseptr))) or + // (set dst, (i64 (extload baseptr))) + // to + // (set tmp, (lwl (add baseptr, 3), undef)) + // (set dst, (lwr baseptr, tmp)) + if ((VT == MVT::i32) || (ExtType == ISD::SEXTLOAD) || + (ExtType == ISD::EXTLOAD)) + return LWR; + + assert((VT == MVT::i64) && (ExtType == ISD::ZEXTLOAD)); + + // Expand + // (set dst, (i64 (zextload baseptr))) + // to + // (set tmp0, (lwl (add baseptr, 3), undef)) + // (set tmp1, (lwr baseptr, tmp0)) + // (set tmp2, (shl tmp1, 32)) + // (set dst, (srl tmp2, 32)) + SDLoc DL(LD); + SDValue Const32 = DAG.getConstant(32, MVT::i32); + SDValue SLL = DAG.getNode(ISD::SHL, DL, MVT::i64, LWR, Const32); + SDValue SRL = DAG.getNode(ISD::SRL, DL, MVT::i64, SLL, Const32); + SDValue Ops[] = { SRL, LWR.getValue(1) }; + return DAG.getMergeValues(Ops, 2, DL); +} + +static SDValue createStoreLR(unsigned Opc, SelectionDAG &DAG, StoreSDNode *SD, + SDValue Chain, unsigned Offset) { + SDValue Ptr = SD->getBasePtr(), Value = SD->getValue(); + EVT MemVT = SD->getMemoryVT(), BasePtrVT = Ptr.getValueType(); + SDLoc DL(SD); + SDVTList VTList = DAG.getVTList(MVT::Other); + + if (Offset) + Ptr = DAG.getNode(ISD::ADD, DL, BasePtrVT, Ptr, + DAG.getConstant(Offset, BasePtrVT)); + + SDValue Ops[] = { Chain, Value, Ptr }; + return DAG.getMemIntrinsicNode(Opc, DL, VTList, Ops, 3, MemVT, + SD->getMemOperand()); +} + +// Expand an unaligned 32 or 64-bit integer store node. +static SDValue lowerUnalignedIntStore(StoreSDNode *SD, SelectionDAG &DAG, + bool IsLittle) { + SDValue Value = SD->getValue(), Chain = SD->getChain(); + EVT VT = Value.getValueType(); + + // Expand + // (store val, baseptr) or + // (truncstore val, baseptr) + // to + // (swl val, (add baseptr, 3)) + // (swr val, baseptr) + if ((VT == MVT::i32) || SD->isTruncatingStore()) { + SDValue SWL = createStoreLR(MipsISD::SWL, DAG, SD, Chain, + IsLittle ? 3 : 0); + return createStoreLR(MipsISD::SWR, DAG, SD, SWL, IsLittle ? 0 : 3); + } + + assert(VT == MVT::i64); + + // Expand + // (store val, baseptr) + // to + // (sdl val, (add baseptr, 7)) + // (sdr val, baseptr) + SDValue SDL = createStoreLR(MipsISD::SDL, DAG, SD, Chain, IsLittle ? 7 : 0); + return createStoreLR(MipsISD::SDR, DAG, SD, SDL, IsLittle ? 0 : 7); +} + +// Lower (store (fp_to_sint $fp) $ptr) to (store (TruncIntFP $fp), $ptr). +static SDValue lowerFP_TO_SINT_STORE(StoreSDNode *SD, SelectionDAG &DAG) { + SDValue Val = SD->getValue(); + + if (Val.getOpcode() != ISD::FP_TO_SINT) + return SDValue(); + + EVT FPTy = EVT::getFloatingPointVT(Val.getValueSizeInBits()); + SDValue Tr = DAG.getNode(MipsISD::TruncIntFP, SDLoc(Val), FPTy, + Val.getOperand(0)); + + return DAG.getStore(SD->getChain(), SDLoc(SD), Tr, SD->getBasePtr(), + SD->getPointerInfo(), SD->isVolatile(), + SD->isNonTemporal(), SD->getAlignment()); +} + +SDValue MipsTargetLowering::lowerSTORE(SDValue Op, SelectionDAG &DAG) const { + StoreSDNode *SD = cast<StoreSDNode>(Op); + EVT MemVT = SD->getMemoryVT(); + + // Lower unaligned integer stores. + if ((SD->getAlignment() < MemVT.getSizeInBits() / 8) && + ((MemVT == MVT::i32) || (MemVT == MVT::i64))) + return lowerUnalignedIntStore(SD, DAG, Subtarget->isLittle()); + + return lowerFP_TO_SINT_STORE(SD, DAG); +} + +SDValue MipsTargetLowering::lowerADD(SDValue Op, SelectionDAG &DAG) const { + if (Op->getOperand(0).getOpcode() != ISD::FRAMEADDR + || cast<ConstantSDNode> + (Op->getOperand(0).getOperand(0))->getZExtValue() != 0 + || Op->getOperand(1).getOpcode() != ISD::FRAME_TO_ARGS_OFFSET) + return SDValue(); + + // The pattern + // (add (frameaddr 0), (frame_to_args_offset)) + // results from lowering llvm.eh.dwarf.cfa intrinsic. Transform it to + // (add FrameObject, 0) + // where FrameObject is a fixed StackObject with offset 0 which points to + // the old stack pointer. + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + EVT ValTy = Op->getValueType(0); + int FI = MFI->CreateFixedObject(Op.getValueSizeInBits() / 8, 0, false); + SDValue InArgsAddr = DAG.getFrameIndex(FI, ValTy); + return DAG.getNode(ISD::ADD, SDLoc(Op), ValTy, InArgsAddr, + DAG.getConstant(0, ValTy)); +} + +SDValue MipsTargetLowering::lowerFP_TO_SINT(SDValue Op, + SelectionDAG &DAG) const { + EVT FPTy = EVT::getFloatingPointVT(Op.getValueSizeInBits()); + SDValue Trunc = DAG.getNode(MipsISD::TruncIntFP, SDLoc(Op), FPTy, + Op.getOperand(0)); + return DAG.getNode(ISD::BITCAST, SDLoc(Op), Op.getValueType(), Trunc); +} + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// TODO: Implement a generic logic using tblgen that can support this. +// Mips O32 ABI rules: +// --- +// i32 - Passed in A0, A1, A2, A3 and stack +// f32 - Only passed in f32 registers if no int reg has been used yet to hold +// an argument. Otherwise, passed in A1, A2, A3 and stack. +// f64 - Only passed in two aliased f32 registers if no int reg has been used +// yet to hold an argument. Otherwise, use A2, A3 and stack. If A1 is +// not used, it must be shadowed. If only A3 is avaiable, shadow it and +// go to stack. +// +// For vararg functions, all arguments are passed in A0, A1, A2, A3 and stack. +//===----------------------------------------------------------------------===// + +static bool CC_MipsO32(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, + CCState &State, const uint16_t *F64Regs) { + + static const unsigned IntRegsSize = 4, FloatRegsSize = 2; + + static const uint16_t IntRegs[] = { Mips::A0, Mips::A1, Mips::A2, Mips::A3 }; + static const uint16_t F32Regs[] = { Mips::F12, Mips::F14 }; + + // Do not process byval args here. + if (ArgFlags.isByVal()) + return true; + + // Promote i8 and i16 + if (LocVT == MVT::i8 || LocVT == MVT::i16) { + LocVT = MVT::i32; + if (ArgFlags.isSExt()) + LocInfo = CCValAssign::SExt; + else if (ArgFlags.isZExt()) + LocInfo = CCValAssign::ZExt; + else + LocInfo = CCValAssign::AExt; + } + + unsigned Reg; + + // f32 and f64 are allocated in A0, A1, A2, A3 when either of the following + // is true: function is vararg, argument is 3rd or higher, there is previous + // argument which is not f32 or f64. + bool AllocateFloatsInIntReg = State.isVarArg() || ValNo > 1 + || State.getFirstUnallocated(F32Regs, FloatRegsSize) != ValNo; + unsigned OrigAlign = ArgFlags.getOrigAlign(); + bool isI64 = (ValVT == MVT::i32 && OrigAlign == 8); + + if (ValVT == MVT::i32 || (ValVT == MVT::f32 && AllocateFloatsInIntReg)) { + Reg = State.AllocateReg(IntRegs, IntRegsSize); + // If this is the first part of an i64 arg, + // the allocated register must be either A0 or A2. + if (isI64 && (Reg == Mips::A1 || Reg == Mips::A3)) + Reg = State.AllocateReg(IntRegs, IntRegsSize); + LocVT = MVT::i32; + } else if (ValVT == MVT::f64 && AllocateFloatsInIntReg) { + // Allocate int register and shadow next int register. If first + // available register is Mips::A1 or Mips::A3, shadow it too. + Reg = State.AllocateReg(IntRegs, IntRegsSize); + if (Reg == Mips::A1 || Reg == Mips::A3) + Reg = State.AllocateReg(IntRegs, IntRegsSize); + State.AllocateReg(IntRegs, IntRegsSize); + LocVT = MVT::i32; + } else if (ValVT.isFloatingPoint() && !AllocateFloatsInIntReg) { + // we are guaranteed to find an available float register + if (ValVT == MVT::f32) { + Reg = State.AllocateReg(F32Regs, FloatRegsSize); + // Shadow int register + State.AllocateReg(IntRegs, IntRegsSize); + } else { + Reg = State.AllocateReg(F64Regs, FloatRegsSize); + // Shadow int registers + unsigned Reg2 = State.AllocateReg(IntRegs, IntRegsSize); + if (Reg2 == Mips::A1 || Reg2 == Mips::A3) + State.AllocateReg(IntRegs, IntRegsSize); + State.AllocateReg(IntRegs, IntRegsSize); + } + } else + llvm_unreachable("Cannot handle this ValVT."); + + if (!Reg) { + unsigned Offset = State.AllocateStack(ValVT.getSizeInBits() >> 3, + OrigAlign); + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); + } else + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + + return false; +} + +static bool CC_MipsO32_FP32(unsigned ValNo, MVT ValVT, + MVT LocVT, CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, CCState &State) { + static const uint16_t F64Regs[] = { Mips::D6, Mips::D7 }; + + return CC_MipsO32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State, F64Regs); +} + +static bool CC_MipsO32_FP64(unsigned ValNo, MVT ValVT, + MVT LocVT, CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, CCState &State) { + static const uint16_t F64Regs[] = { Mips::D12_64, Mips::D14_64 }; + + return CC_MipsO32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State, F64Regs); +} + +#include "MipsGenCallingConv.inc" + +//===----------------------------------------------------------------------===// +// Call Calling Convention Implementation +//===----------------------------------------------------------------------===// + +// Return next O32 integer argument register. +static unsigned getNextIntArgReg(unsigned Reg) { + assert((Reg == Mips::A0) || (Reg == Mips::A2)); + return (Reg == Mips::A0) ? Mips::A1 : Mips::A3; +} + +SDValue +MipsTargetLowering::passArgOnStack(SDValue StackPtr, unsigned Offset, + SDValue Chain, SDValue Arg, SDLoc DL, + bool IsTailCall, SelectionDAG &DAG) const { + if (!IsTailCall) { + SDValue PtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr, + DAG.getIntPtrConstant(Offset)); + return DAG.getStore(Chain, DL, Arg, PtrOff, MachinePointerInfo(), false, + false, 0); + } + + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + int FI = MFI->CreateFixedObject(Arg.getValueSizeInBits() / 8, Offset, false); + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); + return DAG.getStore(Chain, DL, Arg, FIN, MachinePointerInfo(), + /*isVolatile=*/ true, false, 0); +} + +void MipsTargetLowering:: +getOpndList(SmallVectorImpl<SDValue> &Ops, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage, + CallLoweringInfo &CLI, SDValue Callee, SDValue Chain) const { + // Insert node "GP copy globalreg" before call to function. + // + // R_MIPS_CALL* operators (emitted when non-internal functions are called + // in PIC mode) allow symbols to be resolved via lazy binding. + // The lazy binding stub requires GP to point to the GOT. + if (IsPICCall && !InternalLinkage) { + unsigned GPReg = IsN64 ? Mips::GP_64 : Mips::GP; + EVT Ty = IsN64 ? MVT::i64 : MVT::i32; + RegsToPass.push_back(std::make_pair(GPReg, getGlobalReg(CLI.DAG, Ty))); + } + + // 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 = CLI.DAG.getCopyToReg(Chain, CLI.DL, RegsToPass[i].first, + RegsToPass[i].second, InFlag); + InFlag = Chain.getValue(1); + } + + // 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(CLI.DAG.getRegister(RegsToPass[i].first, + RegsToPass[i].second.getValueType())); + + // Add a register mask operand representing the call-preserved registers. + const TargetRegisterInfo *TRI = getTargetMachine().getRegisterInfo(); + const uint32_t *Mask = TRI->getCallPreservedMask(CLI.CallConv); + assert(Mask && "Missing call preserved mask for calling convention"); + if (Subtarget->inMips16HardFloat()) { + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(CLI.Callee)) { + llvm::StringRef Sym = G->getGlobal()->getName(); + Function *F = G->getGlobal()->getParent()->getFunction(Sym); + if (F->hasFnAttribute("__Mips16RetHelper")) { + Mask = MipsRegisterInfo::getMips16RetHelperMask(); + } + } + } + Ops.push_back(CLI.DAG.getRegisterMask(Mask)); + + if (InFlag.getNode()) + Ops.push_back(InFlag); +} + +/// LowerCall - functions arguments are copied from virtual regs to +/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. +SDValue +MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl<SDValue> &InVals) const { + SelectionDAG &DAG = CLI.DAG; + SDLoc DL = CLI.DL; + SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; + SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; + SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + bool &IsTailCall = CLI.IsTailCall; + CallingConv::ID CallConv = CLI.CallConv; + bool IsVarArg = CLI.IsVarArg; + + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + const TargetFrameLowering *TFL = MF.getTarget().getFrameLowering(); + MipsFunctionInfo *FuncInfo = MF.getInfo<MipsFunctionInfo>(); + bool IsPIC = getTargetMachine().getRelocationModel() == Reloc::PIC_; + + // Analyze operands of the call, assigning locations to each operand. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), + getTargetMachine(), ArgLocs, *DAG.getContext()); + MipsCC::SpecialCallingConvType SpecialCallingConv = + getSpecialCallingConv(Callee); + MipsCC MipsCCInfo(CallConv, IsO32, Subtarget->isFP64bit(), CCInfo, + SpecialCallingConv); + + MipsCCInfo.analyzeCallOperands(Outs, IsVarArg, + Subtarget->mipsSEUsesSoftFloat(), + Callee.getNode(), CLI.Args); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NextStackOffset = CCInfo.getNextStackOffset(); + + // Check if it's really possible to do a tail call. + if (IsTailCall) + IsTailCall = + isEligibleForTailCallOptimization(MipsCCInfo, NextStackOffset, + *MF.getInfo<MipsFunctionInfo>()); + + if (IsTailCall) + ++NumTailCalls; + + // Chain is the output chain of the last Load/Store or CopyToReg node. + // ByValChain is the output chain of the last Memcpy node created for copying + // byval arguments to the stack. + unsigned StackAlignment = TFL->getStackAlignment(); + NextStackOffset = RoundUpToAlignment(NextStackOffset, StackAlignment); + SDValue NextStackOffsetVal = DAG.getIntPtrConstant(NextStackOffset, true); + + if (!IsTailCall) + Chain = DAG.getCALLSEQ_START(Chain, NextStackOffsetVal, DL); + + SDValue StackPtr = DAG.getCopyFromReg(Chain, DL, + IsN64 ? Mips::SP_64 : Mips::SP, + getPointerTy()); + + // With EABI is it possible to have 16 args on registers. + std::deque< std::pair<unsigned, SDValue> > RegsToPass; + SmallVector<SDValue, 8> MemOpChains; + MipsCC::byval_iterator ByValArg = MipsCCInfo.byval_begin(); + + // Walk the register/memloc assignments, inserting copies/loads. + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + SDValue Arg = OutVals[i]; + CCValAssign &VA = ArgLocs[i]; + MVT ValVT = VA.getValVT(), LocVT = VA.getLocVT(); + ISD::ArgFlagsTy Flags = Outs[i].Flags; + + // ByVal Arg. + if (Flags.isByVal()) { + assert(Flags.getByValSize() && + "ByVal args of size 0 should have been ignored by front-end."); + assert(ByValArg != MipsCCInfo.byval_end()); + assert(!IsTailCall && + "Do not tail-call optimize if there is a byval argument."); + passByValArg(Chain, DL, RegsToPass, MemOpChains, StackPtr, MFI, DAG, Arg, + MipsCCInfo, *ByValArg, Flags, Subtarget->isLittle()); + ++ByValArg; + continue; + } + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: + if (VA.isRegLoc()) { + if ((ValVT == MVT::f32 && LocVT == MVT::i32) || + (ValVT == MVT::f64 && LocVT == MVT::i64) || + (ValVT == MVT::i64 && LocVT == MVT::f64)) + Arg = DAG.getNode(ISD::BITCAST, DL, LocVT, Arg); + else if (ValVT == MVT::f64 && LocVT == MVT::i32) { + SDValue Lo = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Arg, DAG.getConstant(0, MVT::i32)); + SDValue Hi = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Arg, DAG.getConstant(1, MVT::i32)); + if (!Subtarget->isLittle()) + std::swap(Lo, Hi); + unsigned LocRegLo = VA.getLocReg(); + unsigned LocRegHigh = getNextIntArgReg(LocRegLo); + RegsToPass.push_back(std::make_pair(LocRegLo, Lo)); + RegsToPass.push_back(std::make_pair(LocRegHigh, Hi)); + continue; + } + } + break; + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, LocVT, Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, LocVT, Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, DL, LocVT, 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)); + continue; + } + + // Register can't get to this point... + assert(VA.isMemLoc()); + + // emit ISD::STORE whichs stores the + // parameter value to a stack Location + MemOpChains.push_back(passArgOnStack(StackPtr, VA.getLocMemOffset(), + Chain, Arg, DL, IsTailCall, DAG)); + } + + // 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()); + + // 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. + bool IsPICCall = (IsN64 || IsPIC); // true if calls are translated to jalr $25 + bool GlobalOrExternal = false, InternalLinkage = false; + SDValue CalleeLo; + EVT Ty = Callee.getValueType(); + + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) { + if (IsPICCall) { + const GlobalValue *Val = G->getGlobal(); + InternalLinkage = Val->hasInternalLinkage(); + + if (InternalLinkage) + Callee = getAddrLocal(G, Ty, DAG, HasMips64); + else if (LargeGOT) + Callee = getAddrGlobalLargeGOT(G, Ty, DAG, MipsII::MO_CALL_HI16, + MipsII::MO_CALL_LO16, Chain, + FuncInfo->callPtrInfo(Val)); + else + Callee = getAddrGlobal(G, Ty, DAG, MipsII::MO_GOT_CALL, Chain, + FuncInfo->callPtrInfo(Val)); + } else + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy(), 0, + MipsII::MO_NO_FLAG); + GlobalOrExternal = true; + } + else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) { + const char *Sym = S->getSymbol(); + + if (!IsN64 && !IsPIC) // !N64 && static + Callee = DAG.getTargetExternalSymbol(Sym, getPointerTy(), + MipsII::MO_NO_FLAG); + else if (LargeGOT) + Callee = getAddrGlobalLargeGOT(S, Ty, DAG, MipsII::MO_CALL_HI16, + MipsII::MO_CALL_LO16, Chain, + FuncInfo->callPtrInfo(Sym)); + else // N64 || PIC + Callee = getAddrGlobal(S, Ty, DAG, MipsII::MO_GOT_CALL, Chain, + FuncInfo->callPtrInfo(Sym)); + + GlobalOrExternal = true; + } + + SmallVector<SDValue, 8> Ops(1, Chain); + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + + getOpndList(Ops, RegsToPass, IsPICCall, GlobalOrExternal, InternalLinkage, + CLI, Callee, Chain); + + if (IsTailCall) + return DAG.getNode(MipsISD::TailCall, DL, MVT::Other, &Ops[0], Ops.size()); + + Chain = DAG.getNode(MipsISD::JmpLink, DL, NodeTys, &Ops[0], Ops.size()); + SDValue InFlag = Chain.getValue(1); + + // Create the CALLSEQ_END node. + Chain = DAG.getCALLSEQ_END(Chain, NextStackOffsetVal, + DAG.getIntPtrConstant(0, true), InFlag, DL); + 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, CLI.Callee.getNode(), CLI.RetTy); +} + +/// LowerCallResult - Lower the result values of a call into the +/// appropriate copies out of appropriate physical registers. +SDValue +MipsTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals, + const SDNode *CallNode, + const Type *RetTy) const { + // Assign locations to each value returned by this call. + SmallVector<CCValAssign, 16> RVLocs; + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), + getTargetMachine(), RVLocs, *DAG.getContext()); + MipsCC MipsCCInfo(CallConv, IsO32, Subtarget->isFP64bit(), CCInfo); + + MipsCCInfo.analyzeCallResult(Ins, Subtarget->mipsSEUsesSoftFloat(), + CallNode, RetTy); + + // Copy all of the result registers out of their specified physreg. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + SDValue Val = DAG.getCopyFromReg(Chain, DL, RVLocs[i].getLocReg(), + RVLocs[i].getLocVT(), InFlag); + Chain = Val.getValue(1); + InFlag = Val.getValue(2); + + if (RVLocs[i].getValVT() != RVLocs[i].getLocVT()) + Val = DAG.getNode(ISD::BITCAST, DL, RVLocs[i].getValVT(), Val); + + InVals.push_back(Val); + } + + 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 +MipsTargetLowering::LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + SDLoc DL, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) + const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + MipsFI->setVarArgsFrameIndex(0); + + // Used with vargs to acumulate store chains. + std::vector<SDValue> OutChains; + + // Assign locations to all of the incoming arguments. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), + getTargetMachine(), ArgLocs, *DAG.getContext()); + MipsCC MipsCCInfo(CallConv, IsO32, Subtarget->isFP64bit(), CCInfo); + Function::const_arg_iterator FuncArg = + DAG.getMachineFunction().getFunction()->arg_begin(); + bool UseSoftFloat = Subtarget->mipsSEUsesSoftFloat(); + + MipsCCInfo.analyzeFormalArguments(Ins, UseSoftFloat, FuncArg); + MipsFI->setFormalArgInfo(CCInfo.getNextStackOffset(), + MipsCCInfo.hasByValArg()); + + unsigned CurArgIdx = 0; + MipsCC::byval_iterator ByValArg = MipsCCInfo.byval_begin(); + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + std::advance(FuncArg, Ins[i].OrigArgIndex - CurArgIdx); + CurArgIdx = Ins[i].OrigArgIndex; + EVT ValVT = VA.getValVT(); + ISD::ArgFlagsTy Flags = Ins[i].Flags; + bool IsRegLoc = VA.isRegLoc(); + + if (Flags.isByVal()) { + assert(Flags.getByValSize() && + "ByVal args of size 0 should have been ignored by front-end."); + assert(ByValArg != MipsCCInfo.byval_end()); + copyByValRegs(Chain, DL, OutChains, DAG, Flags, InVals, &*FuncArg, + MipsCCInfo, *ByValArg); + ++ByValArg; + continue; + } + + // Arguments stored on registers + if (IsRegLoc) { + MVT RegVT = VA.getLocVT(); + unsigned ArgReg = VA.getLocReg(); + const TargetRegisterClass *RC = getRegClassFor(RegVT); + + // Transform the arguments stored on + // physical registers into virtual ones + unsigned Reg = addLiveIn(DAG.getMachineFunction(), ArgReg, 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 (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(ValVT)); + ArgValue = DAG.getNode(ISD::TRUNCATE, DL, ValVT, ArgValue); + } + + // Handle floating point arguments passed in integer registers and + // long double arguments passed in floating point registers. + if ((RegVT == MVT::i32 && ValVT == MVT::f32) || + (RegVT == MVT::i64 && ValVT == MVT::f64) || + (RegVT == MVT::f64 && ValVT == MVT::i64)) + ArgValue = DAG.getNode(ISD::BITCAST, DL, ValVT, ArgValue); + else if (IsO32 && RegVT == MVT::i32 && ValVT == MVT::f64) { + unsigned Reg2 = addLiveIn(DAG.getMachineFunction(), + getNextIntArgReg(ArgReg), RC); + SDValue ArgValue2 = DAG.getCopyFromReg(Chain, DL, Reg2, RegVT); + if (!Subtarget->isLittle()) + std::swap(ArgValue, ArgValue2); + ArgValue = DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, + ArgValue, ArgValue2); + } + + InVals.push_back(ArgValue); + } else { // VA.isRegLoc() + + // sanity check + assert(VA.isMemLoc()); + + // The stack pointer offset is relative to the caller stack frame. + int FI = MFI->CreateFixedObject(ValVT.getSizeInBits()/8, + VA.getLocMemOffset(), true); + + // Create load nodes to retrieve arguments from the stack + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); + SDValue Load = DAG.getLoad(ValVT, DL, Chain, FIN, + MachinePointerInfo::getFixedStack(FI), + false, false, false, 0); + InVals.push_back(Load); + OutChains.push_back(Load.getValue(1)); + } + } + + // The mips ABIs for returning structs by value requires that we copy + // the sret argument into $v0 for the return. Save the argument into + // a virtual register so that we can access it from the return points. + if (DAG.getMachineFunction().getFunction()->hasStructRetAttr()) { + unsigned Reg = MipsFI->getSRetReturnReg(); + if (!Reg) { + Reg = MF.getRegInfo(). + createVirtualRegister(getRegClassFor(IsN64 ? MVT::i64 : MVT::i32)); + MipsFI->setSRetReturnReg(Reg); + } + SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), DL, Reg, InVals[0]); + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Copy, Chain); + } + + if (IsVarArg) + writeVarArgRegs(OutChains, MipsCCInfo, Chain, DL, DAG); + + // 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 +//===----------------------------------------------------------------------===// + +bool +MipsTargetLowering::CanLowerReturn(CallingConv::ID CallConv, + MachineFunction &MF, bool IsVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + LLVMContext &Context) const { + SmallVector<CCValAssign, 16> RVLocs; + CCState CCInfo(CallConv, IsVarArg, MF, getTargetMachine(), + RVLocs, Context); + return CCInfo.CheckReturn(Outs, RetCC_Mips); +} + +SDValue +MipsTargetLowering::LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + SDLoc DL, SelectionDAG &DAG) const { + // CCValAssign - represent the assignment of + // the return value to a location + SmallVector<CCValAssign, 16> RVLocs; + MachineFunction &MF = DAG.getMachineFunction(); + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CallConv, IsVarArg, MF, getTargetMachine(), RVLocs, + *DAG.getContext()); + MipsCC MipsCCInfo(CallConv, IsO32, Subtarget->isFP64bit(), CCInfo); + + // Analyze return values. + MipsCCInfo.analyzeReturn(Outs, Subtarget->mipsSEUsesSoftFloat(), + MF.getFunction()->getReturnType()); + + SDValue Flag; + SmallVector<SDValue, 4> RetOps(1, Chain); + + // Copy the result values into the output registers. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + SDValue Val = OutVals[i]; + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + if (RVLocs[i].getValVT() != RVLocs[i].getLocVT()) + Val = DAG.getNode(ISD::BITCAST, DL, RVLocs[i].getLocVT(), Val); + + Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Flag); + + // Guarantee that all emitted copies are stuck together with flags. + Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); + } + + // The mips ABIs for returning structs by value requires that we copy + // the sret argument into $v0 for the return. We saved the argument into + // a virtual register in the entry block, so now we copy the value out + // and into $v0. + if (MF.getFunction()->hasStructRetAttr()) { + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + unsigned Reg = MipsFI->getSRetReturnReg(); + + if (!Reg) + llvm_unreachable("sret virtual register not created in the entry block"); + SDValue Val = DAG.getCopyFromReg(Chain, DL, Reg, getPointerTy()); + unsigned V0 = IsN64 ? Mips::V0_64 : Mips::V0; + + Chain = DAG.getCopyToReg(Chain, DL, V0, Val, Flag); + Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(V0, getPointerTy())); + } + + RetOps[0] = Chain; // Update chain. + + // Add the flag if we have it. + if (Flag.getNode()) + RetOps.push_back(Flag); + + // Return on Mips is always a "jr $ra" + return DAG.getNode(MipsISD::Ret, DL, MVT::Other, &RetOps[0], RetOps.size()); +} + +//===----------------------------------------------------------------------===// +// Mips Inline Assembly Support +//===----------------------------------------------------------------------===// + +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target. +MipsTargetLowering::ConstraintType MipsTargetLowering:: +getConstraintType(const std::string &Constraint) const +{ + // Mips specific constraints + // GCC config/mips/constraints.md + // + // 'd' : An address register. Equivalent to r + // unless generating MIPS16 code. + // 'y' : Equivalent to r; retained for + // backwards compatibility. + // 'c' : A register suitable for use in an indirect + // jump. This will always be $25 for -mabicalls. + // 'l' : The lo register. 1 word storage. + // 'x' : The hilo register pair. Double word storage. + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default : break; + case 'd': + case 'y': + case 'f': + case 'c': + case 'l': + case 'x': + return C_RegisterClass; + case 'R': + return C_Memory; + } + } + 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 +MipsTargetLowering::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': // FPU or MSA register + if (Subtarget->hasMSA() && type->isVectorTy() && + cast<VectorType>(type)->getBitWidth() == 128) + weight = CW_Register; + else if (type->isFloatTy()) + weight = CW_Register; + break; + case 'c': // $25 for indirect jumps + case 'l': // lo register + case 'x': // hilo register pair + if (type->isIntegerTy()) + weight = CW_SpecificReg; + break; + case 'I': // signed 16 bit immediate + case 'J': // integer zero + case 'K': // unsigned 16 bit immediate + case 'L': // signed 32 bit immediate where lower 16 bits are 0 + case 'N': // immediate in the range of -65535 to -1 (inclusive) + case 'O': // signed 15 bit immediate (+- 16383) + case 'P': // immediate in the range of 65535 to 1 (inclusive) + if (isa<ConstantInt>(CallOperandVal)) + weight = CW_Constant; + break; + case 'R': + weight = CW_Memory; + break; + } + return weight; +} + +/// This is a helper function to parse a physical register string and split it +/// into non-numeric and numeric parts (Prefix and Reg). The first boolean flag +/// that is returned indicates whether parsing was successful. The second flag +/// is true if the numeric part exists. +static std::pair<bool, bool> +parsePhysicalReg(const StringRef &C, std::string &Prefix, + unsigned long long &Reg) { + if (C.front() != '{' || C.back() != '}') + return std::make_pair(false, false); + + // Search for the first numeric character. + StringRef::const_iterator I, B = C.begin() + 1, E = C.end() - 1; + I = std::find_if(B, E, std::ptr_fun(isdigit)); + + Prefix.assign(B, I - B); + + // The second flag is set to false if no numeric characters were found. + if (I == E) + return std::make_pair(true, false); + + // Parse the numeric characters. + return std::make_pair(!getAsUnsignedInteger(StringRef(I, E - I), 10, Reg), + true); +} + +std::pair<unsigned, const TargetRegisterClass *> MipsTargetLowering:: +parseRegForInlineAsmConstraint(const StringRef &C, MVT VT) const { + const TargetRegisterInfo *TRI = getTargetMachine().getRegisterInfo(); + const TargetRegisterClass *RC; + std::string Prefix; + unsigned long long Reg; + + std::pair<bool, bool> R = parsePhysicalReg(C, Prefix, Reg); + + if (!R.first) + return std::make_pair((unsigned)0, (const TargetRegisterClass*)0); + + if ((Prefix == "hi" || Prefix == "lo")) { // Parse hi/lo. + // No numeric characters follow "hi" or "lo". + if (R.second) + return std::make_pair((unsigned)0, (const TargetRegisterClass*)0); + + RC = TRI->getRegClass(Prefix == "hi" ? + Mips::HI32RegClassID : Mips::LO32RegClassID); + return std::make_pair(*(RC->begin()), RC); + } else if (Prefix.compare(0, 4, "$msa") == 0) { + // Parse $msa(ir|csr|access|save|modify|request|map|unmap) + + // No numeric characters follow the name. + if (R.second) + return std::make_pair((unsigned)0, (const TargetRegisterClass *)0); + + Reg = StringSwitch<unsigned long long>(Prefix) + .Case("$msair", Mips::MSAIR) + .Case("$msacsr", Mips::MSACSR) + .Case("$msaaccess", Mips::MSAAccess) + .Case("$msasave", Mips::MSASave) + .Case("$msamodify", Mips::MSAModify) + .Case("$msarequest", Mips::MSARequest) + .Case("$msamap", Mips::MSAMap) + .Case("$msaunmap", Mips::MSAUnmap) + .Default(0); + + if (!Reg) + return std::make_pair((unsigned)0, (const TargetRegisterClass *)0); + + RC = TRI->getRegClass(Mips::MSACtrlRegClassID); + return std::make_pair(Reg, RC); + } + + if (!R.second) + return std::make_pair((unsigned)0, (const TargetRegisterClass*)0); + + if (Prefix == "$f") { // Parse $f0-$f31. + // If the size of FP registers is 64-bit or Reg is an even number, select + // the 64-bit register class. Otherwise, select the 32-bit register class. + if (VT == MVT::Other) + VT = (Subtarget->isFP64bit() || !(Reg % 2)) ? MVT::f64 : MVT::f32; + + RC = getRegClassFor(VT); + + if (RC == &Mips::AFGR64RegClass) { + assert(Reg % 2 == 0); + Reg >>= 1; + } + } else if (Prefix == "$fcc") // Parse $fcc0-$fcc7. + RC = TRI->getRegClass(Mips::FCCRegClassID); + else if (Prefix == "$w") { // Parse $w0-$w31. + RC = getRegClassFor((VT == MVT::Other) ? MVT::v16i8 : VT); + } else { // Parse $0-$31. + assert(Prefix == "$"); + RC = getRegClassFor((VT == MVT::Other) ? MVT::i32 : VT); + } + + assert(Reg < RC->getNumRegs()); + return std::make_pair(*(RC->begin() + Reg), RC); +} + +/// 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*> MipsTargetLowering:: +getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const +{ + if (Constraint.size() == 1) { + switch (Constraint[0]) { + case 'd': // Address register. Same as 'r' unless generating MIPS16 code. + case 'y': // Same as 'r'. Exists for compatibility. + case 'r': + if (VT == MVT::i32 || VT == MVT::i16 || VT == MVT::i8) { + if (Subtarget->inMips16Mode()) + return std::make_pair(0U, &Mips::CPU16RegsRegClass); + return std::make_pair(0U, &Mips::GPR32RegClass); + } + if (VT == MVT::i64 && !HasMips64) + return std::make_pair(0U, &Mips::GPR32RegClass); + if (VT == MVT::i64 && HasMips64) + return std::make_pair(0U, &Mips::GPR64RegClass); + // This will generate an error message + return std::make_pair(0u, static_cast<const TargetRegisterClass*>(0)); + case 'f': // FPU or MSA register + if (VT == MVT::v16i8) + return std::make_pair(0U, &Mips::MSA128BRegClass); + else if (VT == MVT::v8i16 || VT == MVT::v8f16) + return std::make_pair(0U, &Mips::MSA128HRegClass); + else if (VT == MVT::v4i32 || VT == MVT::v4f32) + return std::make_pair(0U, &Mips::MSA128WRegClass); + else if (VT == MVT::v2i64 || VT == MVT::v2f64) + return std::make_pair(0U, &Mips::MSA128DRegClass); + else if (VT == MVT::f32) + return std::make_pair(0U, &Mips::FGR32RegClass); + else if ((VT == MVT::f64) && (!Subtarget->isSingleFloat())) { + if (Subtarget->isFP64bit()) + return std::make_pair(0U, &Mips::FGR64RegClass); + return std::make_pair(0U, &Mips::AFGR64RegClass); + } + break; + case 'c': // register suitable for indirect jump + if (VT == MVT::i32) + return std::make_pair((unsigned)Mips::T9, &Mips::GPR32RegClass); + assert(VT == MVT::i64 && "Unexpected type."); + return std::make_pair((unsigned)Mips::T9_64, &Mips::GPR64RegClass); + case 'l': // register suitable for indirect jump + if (VT == MVT::i32) + return std::make_pair((unsigned)Mips::LO0, &Mips::LO32RegClass); + return std::make_pair((unsigned)Mips::LO0_64, &Mips::LO64RegClass); + case 'x': // register suitable for indirect jump + // Fixme: Not triggering the use of both hi and low + // This will generate an error message + return std::make_pair(0u, static_cast<const TargetRegisterClass*>(0)); + } + } + + std::pair<unsigned, const TargetRegisterClass *> R; + R = parseRegForInlineAsmConstraint(Constraint, VT); + + if (R.second) + return R; + + return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); +} + +/// LowerAsmOperandForConstraint - Lower the specified operand into the Ops +/// vector. If it is invalid, don't add anything to Ops. +void MipsTargetLowering::LowerAsmOperandForConstraint(SDValue Op, + std::string &Constraint, + std::vector<SDValue>&Ops, + SelectionDAG &DAG) const { + SDValue Result(0, 0); + + // Only support length 1 constraints for now. + if (Constraint.length() > 1) return; + + char ConstraintLetter = Constraint[0]; + switch (ConstraintLetter) { + default: break; // This will fall through to the generic implementation + case 'I': // Signed 16 bit constant + // If this fails, the parent routine will give an error + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + int64_t Val = C->getSExtValue(); + if (isInt<16>(Val)) { + Result = DAG.getTargetConstant(Val, Type); + break; + } + } + return; + case 'J': // integer zero + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + int64_t Val = C->getZExtValue(); + if (Val == 0) { + Result = DAG.getTargetConstant(0, Type); + break; + } + } + return; + case 'K': // unsigned 16 bit immediate + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + uint64_t Val = (uint64_t)C->getZExtValue(); + if (isUInt<16>(Val)) { + Result = DAG.getTargetConstant(Val, Type); + break; + } + } + return; + case 'L': // signed 32 bit immediate where lower 16 bits are 0 + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + int64_t Val = C->getSExtValue(); + if ((isInt<32>(Val)) && ((Val & 0xffff) == 0)){ + Result = DAG.getTargetConstant(Val, Type); + break; + } + } + return; + case 'N': // immediate in the range of -65535 to -1 (inclusive) + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + int64_t Val = C->getSExtValue(); + if ((Val >= -65535) && (Val <= -1)) { + Result = DAG.getTargetConstant(Val, Type); + break; + } + } + return; + case 'O': // signed 15 bit immediate + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + int64_t Val = C->getSExtValue(); + if ((isInt<15>(Val))) { + Result = DAG.getTargetConstant(Val, Type); + break; + } + } + return; + case 'P': // immediate in the range of 1 to 65535 (inclusive) + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + EVT Type = Op.getValueType(); + int64_t Val = C->getSExtValue(); + if ((Val <= 65535) && (Val >= 1)) { + Result = DAG.getTargetConstant(Val, Type); + break; + } + } + return; + } + + if (Result.getNode()) { + Ops.push_back(Result); + return; + } + + TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); +} + +bool MipsTargetLowering::isLegalAddressingMode(const AddrMode &AM, + Type *Ty) const { + // No global is ever allowed as a base. + if (AM.BaseGV) + return false; + + switch (AM.Scale) { + case 0: // "r+i" or just "i", depending on HasBaseReg. + break; + case 1: + if (!AM.HasBaseReg) // allow "r+i". + break; + return false; // disallow "r+r" or "r+r+i". + default: + return false; + } + + return true; +} + +bool +MipsTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { + // The Mips target isn't yet aware of offsets. + return false; +} + +EVT MipsTargetLowering::getOptimalMemOpType(uint64_t Size, unsigned DstAlign, + unsigned SrcAlign, + bool IsMemset, bool ZeroMemset, + bool MemcpyStrSrc, + MachineFunction &MF) const { + if (Subtarget->hasMips64()) + return MVT::i64; + + return MVT::i32; +} + +bool MipsTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { + if (VT != MVT::f32 && VT != MVT::f64) + return false; + if (Imm.isNegZero()) + return false; + return Imm.isZero(); +} + +unsigned MipsTargetLowering::getJumpTableEncoding() const { + if (IsN64) + return MachineJumpTableInfo::EK_GPRel64BlockAddress; + + return TargetLowering::getJumpTableEncoding(); +} + +/// This function returns true if CallSym is a long double emulation routine. +static bool isF128SoftLibCall(const char *CallSym) { + const char *const LibCalls[] = + {"__addtf3", "__divtf3", "__eqtf2", "__extenddftf2", "__extendsftf2", + "__fixtfdi", "__fixtfsi", "__fixtfti", "__fixunstfdi", "__fixunstfsi", + "__fixunstfti", "__floatditf", "__floatsitf", "__floattitf", + "__floatunditf", "__floatunsitf", "__floatuntitf", "__getf2", "__gttf2", + "__letf2", "__lttf2", "__multf3", "__netf2", "__powitf2", "__subtf3", + "__trunctfdf2", "__trunctfsf2", "__unordtf2", + "ceill", "copysignl", "cosl", "exp2l", "expl", "floorl", "fmal", "fmodl", + "log10l", "log2l", "logl", "nearbyintl", "powl", "rintl", "sinl", "sqrtl", + "truncl"}; + + const char *const *End = LibCalls + array_lengthof(LibCalls); + + // Check that LibCalls is sorted alphabetically. + MipsTargetLowering::LTStr Comp; + +#ifndef NDEBUG + for (const char *const *I = LibCalls; I < End - 1; ++I) + assert(Comp(*I, *(I + 1))); +#endif + + return std::binary_search(LibCalls, End, CallSym, Comp); +} + +/// This function returns true if Ty is fp128 or i128 which was originally a +/// fp128. +static bool originalTypeIsF128(const Type *Ty, const SDNode *CallNode) { + if (Ty->isFP128Ty()) + return true; + + const ExternalSymbolSDNode *ES = + dyn_cast_or_null<const ExternalSymbolSDNode>(CallNode); + + // If the Ty is i128 and the function being called is a long double emulation + // routine, then the original type is f128. + return (ES && Ty->isIntegerTy(128) && isF128SoftLibCall(ES->getSymbol())); +} + +MipsTargetLowering::MipsCC::SpecialCallingConvType + MipsTargetLowering::getSpecialCallingConv(SDValue Callee) const { + MipsCC::SpecialCallingConvType SpecialCallingConv = + MipsCC::NoSpecialCallingConv;; + if (Subtarget->inMips16HardFloat()) { + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) { + llvm::StringRef Sym = G->getGlobal()->getName(); + Function *F = G->getGlobal()->getParent()->getFunction(Sym); + if (F->hasFnAttribute("__Mips16RetHelper")) { + SpecialCallingConv = MipsCC::Mips16RetHelperConv; + } + } + } + return SpecialCallingConv; +} + +MipsTargetLowering::MipsCC::MipsCC( + CallingConv::ID CC, bool IsO32_, bool IsFP64_, CCState &Info, + MipsCC::SpecialCallingConvType SpecialCallingConv_) + : CCInfo(Info), CallConv(CC), IsO32(IsO32_), IsFP64(IsFP64_), + SpecialCallingConv(SpecialCallingConv_){ + // Pre-allocate reserved argument area. + CCInfo.AllocateStack(reservedArgArea(), 1); +} + + +void MipsTargetLowering::MipsCC:: +analyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Args, + bool IsVarArg, bool IsSoftFloat, const SDNode *CallNode, + std::vector<ArgListEntry> &FuncArgs) { + assert((CallConv != CallingConv::Fast || !IsVarArg) && + "CallingConv::Fast shouldn't be used for vararg functions."); + + unsigned NumOpnds = Args.size(); + llvm::CCAssignFn *FixedFn = fixedArgFn(), *VarFn = varArgFn(); + + for (unsigned I = 0; I != NumOpnds; ++I) { + MVT ArgVT = Args[I].VT; + ISD::ArgFlagsTy ArgFlags = Args[I].Flags; + bool R; + + if (ArgFlags.isByVal()) { + handleByValArg(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags); + continue; + } + + if (IsVarArg && !Args[I].IsFixed) + R = VarFn(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo); + else { + MVT RegVT = getRegVT(ArgVT, FuncArgs[Args[I].OrigArgIndex].Ty, CallNode, + IsSoftFloat); + R = FixedFn(I, ArgVT, RegVT, CCValAssign::Full, ArgFlags, CCInfo); + } + + if (R) { +#ifndef NDEBUG + dbgs() << "Call operand #" << I << " has unhandled type " + << EVT(ArgVT).getEVTString(); +#endif + llvm_unreachable(0); + } + } +} + +void MipsTargetLowering::MipsCC:: +analyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Args, + bool IsSoftFloat, Function::const_arg_iterator FuncArg) { + unsigned NumArgs = Args.size(); + llvm::CCAssignFn *FixedFn = fixedArgFn(); + unsigned CurArgIdx = 0; + + for (unsigned I = 0; I != NumArgs; ++I) { + MVT ArgVT = Args[I].VT; + ISD::ArgFlagsTy ArgFlags = Args[I].Flags; + std::advance(FuncArg, Args[I].OrigArgIndex - CurArgIdx); + CurArgIdx = Args[I].OrigArgIndex; + + if (ArgFlags.isByVal()) { + handleByValArg(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags); + continue; + } + + MVT RegVT = getRegVT(ArgVT, FuncArg->getType(), 0, IsSoftFloat); + + if (!FixedFn(I, ArgVT, RegVT, CCValAssign::Full, ArgFlags, CCInfo)) + continue; + +#ifndef NDEBUG + dbgs() << "Formal Arg #" << I << " has unhandled type " + << EVT(ArgVT).getEVTString(); +#endif + llvm_unreachable(0); + } +} + +template<typename Ty> +void MipsTargetLowering::MipsCC:: +analyzeReturn(const SmallVectorImpl<Ty> &RetVals, bool IsSoftFloat, + const SDNode *CallNode, const Type *RetTy) const { + CCAssignFn *Fn; + + if (IsSoftFloat && originalTypeIsF128(RetTy, CallNode)) + Fn = RetCC_F128Soft; + else + Fn = RetCC_Mips; + + for (unsigned I = 0, E = RetVals.size(); I < E; ++I) { + MVT VT = RetVals[I].VT; + ISD::ArgFlagsTy Flags = RetVals[I].Flags; + MVT RegVT = this->getRegVT(VT, RetTy, CallNode, IsSoftFloat); + + if (Fn(I, VT, RegVT, CCValAssign::Full, Flags, this->CCInfo)) { +#ifndef NDEBUG + dbgs() << "Call result #" << I << " has unhandled type " + << EVT(VT).getEVTString() << '\n'; +#endif + llvm_unreachable(0); + } + } +} + +void MipsTargetLowering::MipsCC:: +analyzeCallResult(const SmallVectorImpl<ISD::InputArg> &Ins, bool IsSoftFloat, + const SDNode *CallNode, const Type *RetTy) const { + analyzeReturn(Ins, IsSoftFloat, CallNode, RetTy); +} + +void MipsTargetLowering::MipsCC:: +analyzeReturn(const SmallVectorImpl<ISD::OutputArg> &Outs, bool IsSoftFloat, + const Type *RetTy) const { + analyzeReturn(Outs, IsSoftFloat, 0, RetTy); +} + +void MipsTargetLowering::MipsCC::handleByValArg(unsigned ValNo, MVT ValVT, + MVT LocVT, + CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags) { + assert(ArgFlags.getByValSize() && "Byval argument's size shouldn't be 0."); + + struct ByValArgInfo ByVal; + unsigned RegSize = regSize(); + unsigned ByValSize = RoundUpToAlignment(ArgFlags.getByValSize(), RegSize); + unsigned Align = std::min(std::max(ArgFlags.getByValAlign(), RegSize), + RegSize * 2); + + if (useRegsForByval()) + allocateRegs(ByVal, ByValSize, Align); + + // Allocate space on caller's stack. + ByVal.Address = CCInfo.AllocateStack(ByValSize - RegSize * ByVal.NumRegs, + Align); + CCInfo.addLoc(CCValAssign::getMem(ValNo, ValVT, ByVal.Address, LocVT, + LocInfo)); + ByValArgs.push_back(ByVal); +} + +unsigned MipsTargetLowering::MipsCC::numIntArgRegs() const { + return IsO32 ? array_lengthof(O32IntRegs) : array_lengthof(Mips64IntRegs); +} + +unsigned MipsTargetLowering::MipsCC::reservedArgArea() const { + return (IsO32 && (CallConv != CallingConv::Fast)) ? 16 : 0; +} + +const uint16_t *MipsTargetLowering::MipsCC::intArgRegs() const { + return IsO32 ? O32IntRegs : Mips64IntRegs; +} + +llvm::CCAssignFn *MipsTargetLowering::MipsCC::fixedArgFn() const { + if (CallConv == CallingConv::Fast) + return CC_Mips_FastCC; + + if (SpecialCallingConv == Mips16RetHelperConv) + return CC_Mips16RetHelper; + return IsO32 ? (IsFP64 ? CC_MipsO32_FP64 : CC_MipsO32_FP32) : CC_MipsN; +} + +llvm::CCAssignFn *MipsTargetLowering::MipsCC::varArgFn() const { + return IsO32 ? (IsFP64 ? CC_MipsO32_FP64 : CC_MipsO32_FP32) : CC_MipsN_VarArg; +} + +const uint16_t *MipsTargetLowering::MipsCC::shadowRegs() const { + return IsO32 ? O32IntRegs : Mips64DPRegs; +} + +void MipsTargetLowering::MipsCC::allocateRegs(ByValArgInfo &ByVal, + unsigned ByValSize, + unsigned Align) { + unsigned RegSize = regSize(), NumIntArgRegs = numIntArgRegs(); + const uint16_t *IntArgRegs = intArgRegs(), *ShadowRegs = shadowRegs(); + assert(!(ByValSize % RegSize) && !(Align % RegSize) && + "Byval argument's size and alignment should be a multiple of" + "RegSize."); + + ByVal.FirstIdx = CCInfo.getFirstUnallocated(IntArgRegs, NumIntArgRegs); + + // If Align > RegSize, the first arg register must be even. + if ((Align > RegSize) && (ByVal.FirstIdx % 2)) { + CCInfo.AllocateReg(IntArgRegs[ByVal.FirstIdx], ShadowRegs[ByVal.FirstIdx]); + ++ByVal.FirstIdx; + } + + // Mark the registers allocated. + for (unsigned I = ByVal.FirstIdx; ByValSize && (I < NumIntArgRegs); + ByValSize -= RegSize, ++I, ++ByVal.NumRegs) + CCInfo.AllocateReg(IntArgRegs[I], ShadowRegs[I]); +} + +MVT MipsTargetLowering::MipsCC::getRegVT(MVT VT, const Type *OrigTy, + const SDNode *CallNode, + bool IsSoftFloat) const { + if (IsSoftFloat || IsO32) + return VT; + + // Check if the original type was fp128. + if (originalTypeIsF128(OrigTy, CallNode)) { + assert(VT == MVT::i64); + return MVT::f64; + } + + return VT; +} + +void MipsTargetLowering:: +copyByValRegs(SDValue Chain, SDLoc DL, std::vector<SDValue> &OutChains, + SelectionDAG &DAG, const ISD::ArgFlagsTy &Flags, + SmallVectorImpl<SDValue> &InVals, const Argument *FuncArg, + const MipsCC &CC, const ByValArgInfo &ByVal) const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + unsigned RegAreaSize = ByVal.NumRegs * CC.regSize(); + unsigned FrameObjSize = std::max(Flags.getByValSize(), RegAreaSize); + int FrameObjOffset; + + if (RegAreaSize) + FrameObjOffset = (int)CC.reservedArgArea() - + (int)((CC.numIntArgRegs() - ByVal.FirstIdx) * CC.regSize()); + else + FrameObjOffset = ByVal.Address; + + // Create frame object. + EVT PtrTy = getPointerTy(); + int FI = MFI->CreateFixedObject(FrameObjSize, FrameObjOffset, true); + SDValue FIN = DAG.getFrameIndex(FI, PtrTy); + InVals.push_back(FIN); + + if (!ByVal.NumRegs) + return; + + // Copy arg registers. + MVT RegTy = MVT::getIntegerVT(CC.regSize() * 8); + const TargetRegisterClass *RC = getRegClassFor(RegTy); + + for (unsigned I = 0; I < ByVal.NumRegs; ++I) { + unsigned ArgReg = CC.intArgRegs()[ByVal.FirstIdx + I]; + unsigned VReg = addLiveIn(MF, ArgReg, RC); + unsigned Offset = I * CC.regSize(); + SDValue StorePtr = DAG.getNode(ISD::ADD, DL, PtrTy, FIN, + DAG.getConstant(Offset, PtrTy)); + SDValue Store = DAG.getStore(Chain, DL, DAG.getRegister(VReg, RegTy), + StorePtr, MachinePointerInfo(FuncArg, Offset), + false, false, 0); + OutChains.push_back(Store); + } +} + +// Copy byVal arg to registers and stack. +void MipsTargetLowering:: +passByValArg(SDValue Chain, SDLoc DL, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + SmallVectorImpl<SDValue> &MemOpChains, SDValue StackPtr, + MachineFrameInfo *MFI, SelectionDAG &DAG, SDValue Arg, + const MipsCC &CC, const ByValArgInfo &ByVal, + const ISD::ArgFlagsTy &Flags, bool isLittle) const { + unsigned ByValSize = Flags.getByValSize(); + unsigned Offset = 0; // Offset in # of bytes from the beginning of struct. + unsigned RegSize = CC.regSize(); + unsigned Alignment = std::min(Flags.getByValAlign(), RegSize); + EVT PtrTy = getPointerTy(), RegTy = MVT::getIntegerVT(RegSize * 8); + + if (ByVal.NumRegs) { + const uint16_t *ArgRegs = CC.intArgRegs(); + bool LeftoverBytes = (ByVal.NumRegs * RegSize > ByValSize); + unsigned I = 0; + + // Copy words to registers. + for (; I < ByVal.NumRegs - LeftoverBytes; ++I, Offset += RegSize) { + SDValue LoadPtr = DAG.getNode(ISD::ADD, DL, PtrTy, Arg, + DAG.getConstant(Offset, PtrTy)); + SDValue LoadVal = DAG.getLoad(RegTy, DL, Chain, LoadPtr, + MachinePointerInfo(), false, false, false, + Alignment); + MemOpChains.push_back(LoadVal.getValue(1)); + unsigned ArgReg = ArgRegs[ByVal.FirstIdx + I]; + RegsToPass.push_back(std::make_pair(ArgReg, LoadVal)); + } + + // Return if the struct has been fully copied. + if (ByValSize == Offset) + return; + + // Copy the remainder of the byval argument with sub-word loads and shifts. + if (LeftoverBytes) { + assert((ByValSize > Offset) && (ByValSize < Offset + RegSize) && + "Size of the remainder should be smaller than RegSize."); + SDValue Val; + + for (unsigned LoadSize = RegSize / 2, TotalSizeLoaded = 0; + Offset < ByValSize; LoadSize /= 2) { + unsigned RemSize = ByValSize - Offset; + + if (RemSize < LoadSize) + continue; + + // Load subword. + SDValue LoadPtr = DAG.getNode(ISD::ADD, DL, PtrTy, Arg, + DAG.getConstant(Offset, PtrTy)); + SDValue LoadVal = + DAG.getExtLoad(ISD::ZEXTLOAD, DL, RegTy, Chain, LoadPtr, + MachinePointerInfo(), MVT::getIntegerVT(LoadSize * 8), + false, false, Alignment); + MemOpChains.push_back(LoadVal.getValue(1)); + + // Shift the loaded value. + unsigned Shamt; + + if (isLittle) + Shamt = TotalSizeLoaded; + else + Shamt = (RegSize - (TotalSizeLoaded + LoadSize)) * 8; + + SDValue Shift = DAG.getNode(ISD::SHL, DL, RegTy, LoadVal, + DAG.getConstant(Shamt, MVT::i32)); + + if (Val.getNode()) + Val = DAG.getNode(ISD::OR, DL, RegTy, Val, Shift); + else + Val = Shift; + + Offset += LoadSize; + TotalSizeLoaded += LoadSize; + Alignment = std::min(Alignment, LoadSize); + } + + unsigned ArgReg = ArgRegs[ByVal.FirstIdx + I]; + RegsToPass.push_back(std::make_pair(ArgReg, Val)); + return; + } + } + + // Copy remainder of byval arg to it with memcpy. + unsigned MemCpySize = ByValSize - Offset; + SDValue Src = DAG.getNode(ISD::ADD, DL, PtrTy, Arg, + DAG.getConstant(Offset, PtrTy)); + SDValue Dst = DAG.getNode(ISD::ADD, DL, PtrTy, StackPtr, + DAG.getIntPtrConstant(ByVal.Address)); + Chain = DAG.getMemcpy(Chain, DL, Dst, Src, DAG.getConstant(MemCpySize, PtrTy), + Alignment, /*isVolatile=*/false, /*AlwaysInline=*/false, + MachinePointerInfo(0), MachinePointerInfo(0)); + MemOpChains.push_back(Chain); +} + +void MipsTargetLowering::writeVarArgRegs(std::vector<SDValue> &OutChains, + const MipsCC &CC, SDValue Chain, + SDLoc DL, SelectionDAG &DAG) const { + unsigned NumRegs = CC.numIntArgRegs(); + const uint16_t *ArgRegs = CC.intArgRegs(); + const CCState &CCInfo = CC.getCCInfo(); + unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs, NumRegs); + unsigned RegSize = CC.regSize(); + MVT RegTy = MVT::getIntegerVT(RegSize * 8); + const TargetRegisterClass *RC = getRegClassFor(RegTy); + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + // Offset of the first variable argument from stack pointer. + int VaArgOffset; + + if (NumRegs == Idx) + VaArgOffset = RoundUpToAlignment(CCInfo.getNextStackOffset(), RegSize); + else + VaArgOffset = (int)CC.reservedArgArea() - (int)(RegSize * (NumRegs - Idx)); + + // Record the frame index of the first variable argument + // which is a value necessary to VASTART. + int FI = MFI->CreateFixedObject(RegSize, VaArgOffset, true); + MipsFI->setVarArgsFrameIndex(FI); + + // Copy the integer registers that have not been used for argument passing + // to the argument register save area. For O32, the save area is allocated + // in the caller's stack frame, while for N32/64, it is allocated in the + // callee's stack frame. + for (unsigned I = Idx; I < NumRegs; ++I, VaArgOffset += RegSize) { + unsigned Reg = addLiveIn(MF, ArgRegs[I], RC); + SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegTy); + FI = MFI->CreateFixedObject(RegSize, VaArgOffset, true); + SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy()); + SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff, + MachinePointerInfo(), false, false, 0); + cast<StoreSDNode>(Store.getNode())->getMemOperand()->setValue(0); + OutChains.push_back(Store); + } +} diff --git a/contrib/llvm/lib/Target/Mips/MipsISelLowering.h b/contrib/llvm/lib/Target/Mips/MipsISelLowering.h new file mode 100644 index 000000000000..65f68f04315d --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsISelLowering.h @@ -0,0 +1,605 @@ +//===-- MipsISelLowering.h - Mips 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 Mips uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef MipsISELLOWERING_H +#define MipsISELLOWERING_H + +#include "Mips.h" +#include "MipsSubtarget.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/IR/Function.h" +#include "llvm/Target/TargetLowering.h" +#include <deque> +#include <string> + +namespace llvm { + namespace MipsISD { + enum NodeType { + // Start the numbering from where ISD NodeType finishes. + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + // Jump and link (call) + JmpLink, + + // Tail call + TailCall, + + // Get the Higher 16 bits from a 32-bit immediate + // No relation with Mips Hi register + Hi, + + // Get the Lower 16 bits from a 32-bit immediate + // No relation with Mips Lo register + Lo, + + // Handle gp_rel (small data/bss sections) relocation. + GPRel, + + // Thread Pointer + ThreadPointer, + + // Floating Point Branch Conditional + FPBrcond, + + // Floating Point Compare + FPCmp, + + // Floating Point Conditional Moves + CMovFP_T, + CMovFP_F, + + // FP-to-int truncation node. + TruncIntFP, + + // Return + Ret, + + EH_RETURN, + + // Node used to extract integer from accumulator. + MFHI, + MFLO, + + // Node used to insert integers to accumulator. + MTLOHI, + + // Mult nodes. + Mult, + Multu, + + // MAdd/Sub nodes + MAdd, + MAddu, + MSub, + MSubu, + + // DivRem(u) + DivRem, + DivRemU, + DivRem16, + DivRemU16, + + BuildPairF64, + ExtractElementF64, + + Wrapper, + + DynAlloc, + + Sync, + + Ext, + Ins, + + // EXTR.W instrinsic nodes. + EXTP, + EXTPDP, + EXTR_S_H, + EXTR_W, + EXTR_R_W, + EXTR_RS_W, + SHILO, + MTHLIP, + + // DPA.W intrinsic nodes. + MULSAQ_S_W_PH, + MAQ_S_W_PHL, + MAQ_S_W_PHR, + MAQ_SA_W_PHL, + MAQ_SA_W_PHR, + DPAU_H_QBL, + DPAU_H_QBR, + DPSU_H_QBL, + DPSU_H_QBR, + DPAQ_S_W_PH, + DPSQ_S_W_PH, + DPAQ_SA_L_W, + DPSQ_SA_L_W, + DPA_W_PH, + DPS_W_PH, + DPAQX_S_W_PH, + DPAQX_SA_W_PH, + DPAX_W_PH, + DPSX_W_PH, + DPSQX_S_W_PH, + DPSQX_SA_W_PH, + MULSA_W_PH, + + MULT, + MULTU, + MADD_DSP, + MADDU_DSP, + MSUB_DSP, + MSUBU_DSP, + + // DSP shift nodes. + SHLL_DSP, + SHRA_DSP, + SHRL_DSP, + + // DSP setcc and select_cc nodes. + SETCC_DSP, + SELECT_CC_DSP, + + // Vector comparisons. + // These take a vector and return a boolean. + VALL_ZERO, + VANY_ZERO, + VALL_NONZERO, + VANY_NONZERO, + + // These take a vector and return a vector bitmask. + VCEQ, + VCLE_S, + VCLE_U, + VCLT_S, + VCLT_U, + + // Element-wise vector max/min. + VSMAX, + VSMIN, + VUMAX, + VUMIN, + + // Vector Shuffle with mask as an operand + VSHF, // Generic shuffle + SHF, // 4-element set shuffle. + ILVEV, // Interleave even elements + ILVOD, // Interleave odd elements + ILVL, // Interleave left elements + ILVR, // Interleave right elements + PCKEV, // Pack even elements + PCKOD, // Pack odd elements + + // Combined (XOR (OR $a, $b), -1) + VNOR, + + // Extended vector element extraction + VEXTRACT_SEXT_ELT, + VEXTRACT_ZEXT_ELT, + + // Load/Store Left/Right nodes. + LWL = ISD::FIRST_TARGET_MEMORY_OPCODE, + LWR, + SWL, + SWR, + LDL, + LDR, + SDL, + SDR + }; + } + + //===--------------------------------------------------------------------===// + // TargetLowering Implementation + //===--------------------------------------------------------------------===// + class MipsFunctionInfo; + + class MipsTargetLowering : public TargetLowering { + public: + explicit MipsTargetLowering(MipsTargetMachine &TM); + + static const MipsTargetLowering *create(MipsTargetMachine &TM); + + virtual MVT getScalarShiftAmountTy(EVT LHSTy) const { return MVT::i32; } + + virtual void LowerOperationWrapper(SDNode *N, + SmallVectorImpl<SDValue> &Results, + SelectionDAG &DAG) const; + + /// LowerOperation - Provide custom lowering hooks for some operations. + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const; + + /// ReplaceNodeResults - Replace the results of node with an illegal result + /// type with new values built out of custom code. + /// + virtual void ReplaceNodeResults(SDNode *N, SmallVectorImpl<SDValue>&Results, + 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(LLVMContext &Context, EVT VT) const; + + virtual SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const; + + virtual MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const; + + struct LTStr { + bool operator()(const char *S1, const char *S2) const { + return strcmp(S1, S2) < 0; + } + }; + + protected: + SDValue getGlobalReg(SelectionDAG &DAG, EVT Ty) const; + + // This method creates the following nodes, which are necessary for + // computing a local symbol's address: + // + // (add (load (wrapper $gp, %got(sym)), %lo(sym)) + template<class NodeTy> + SDValue getAddrLocal(NodeTy *N, EVT Ty, SelectionDAG &DAG, + bool HasMips64) const { + SDLoc DL(N); + unsigned GOTFlag = HasMips64 ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT; + SDValue GOT = DAG.getNode(MipsISD::Wrapper, DL, Ty, getGlobalReg(DAG, Ty), + getTargetNode(N, Ty, DAG, GOTFlag)); + SDValue Load = DAG.getLoad(Ty, DL, DAG.getEntryNode(), GOT, + MachinePointerInfo::getGOT(), false, false, + false, 0); + unsigned LoFlag = HasMips64 ? MipsII::MO_GOT_OFST : MipsII::MO_ABS_LO; + SDValue Lo = DAG.getNode(MipsISD::Lo, DL, Ty, + getTargetNode(N, Ty, DAG, LoFlag)); + return DAG.getNode(ISD::ADD, DL, Ty, Load, Lo); + } + + // This method creates the following nodes, which are necessary for + // computing a global symbol's address: + // + // (load (wrapper $gp, %got(sym))) + template<class NodeTy> + SDValue getAddrGlobal(NodeTy *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag, SDValue Chain, + const MachinePointerInfo &PtrInfo) const { + SDLoc DL(N); + SDValue Tgt = DAG.getNode(MipsISD::Wrapper, DL, Ty, getGlobalReg(DAG, Ty), + getTargetNode(N, Ty, DAG, Flag)); + return DAG.getLoad(Ty, DL, Chain, Tgt, PtrInfo, false, false, false, 0); + } + + // This method creates the following nodes, which are necessary for + // computing a global symbol's address in large-GOT mode: + // + // (load (wrapper (add %hi(sym), $gp), %lo(sym))) + template<class NodeTy> + SDValue getAddrGlobalLargeGOT(NodeTy *N, EVT Ty, SelectionDAG &DAG, + unsigned HiFlag, unsigned LoFlag, + SDValue Chain, + const MachinePointerInfo &PtrInfo) const { + SDLoc DL(N); + SDValue Hi = DAG.getNode(MipsISD::Hi, DL, Ty, + getTargetNode(N, Ty, DAG, HiFlag)); + Hi = DAG.getNode(ISD::ADD, DL, Ty, Hi, getGlobalReg(DAG, Ty)); + SDValue Wrapper = DAG.getNode(MipsISD::Wrapper, DL, Ty, Hi, + getTargetNode(N, Ty, DAG, LoFlag)); + return DAG.getLoad(Ty, DL, Chain, Wrapper, PtrInfo, false, false, false, + 0); + } + + // This method creates the following nodes, which are necessary for + // computing a symbol's address in non-PIC mode: + // + // (add %hi(sym), %lo(sym)) + template<class NodeTy> + SDValue getAddrNonPIC(NodeTy *N, EVT Ty, SelectionDAG &DAG) const { + SDLoc DL(N); + SDValue Hi = getTargetNode(N, Ty, DAG, MipsII::MO_ABS_HI); + SDValue Lo = getTargetNode(N, Ty, DAG, MipsII::MO_ABS_LO); + return DAG.getNode(ISD::ADD, DL, Ty, + DAG.getNode(MipsISD::Hi, DL, Ty, Hi), + DAG.getNode(MipsISD::Lo, DL, Ty, Lo)); + } + + /// This function fills Ops, which is the list of operands that will later + /// be used when a function call node is created. It also generates + /// copyToReg nodes to set up argument registers. + virtual void + getOpndList(SmallVectorImpl<SDValue> &Ops, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage, + CallLoweringInfo &CLI, SDValue Callee, SDValue Chain) const; + + /// ByValArgInfo - Byval argument information. + struct ByValArgInfo { + unsigned FirstIdx; // Index of the first register used. + unsigned NumRegs; // Number of registers used for this argument. + unsigned Address; // Offset of the stack area used to pass this argument. + + ByValArgInfo() : FirstIdx(0), NumRegs(0), Address(0) {} + }; + + /// MipsCC - This class provides methods used to analyze formal and call + /// arguments and inquire about calling convention information. + class MipsCC { + public: + enum SpecialCallingConvType { + Mips16RetHelperConv, NoSpecialCallingConv + }; + + MipsCC(CallingConv::ID CallConv, bool IsO32, bool IsFP64, CCState &Info, + SpecialCallingConvType SpecialCallingConv = NoSpecialCallingConv); + + + void analyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs, + bool IsVarArg, bool IsSoftFloat, + const SDNode *CallNode, + std::vector<ArgListEntry> &FuncArgs); + void analyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Ins, + bool IsSoftFloat, + Function::const_arg_iterator FuncArg); + + void analyzeCallResult(const SmallVectorImpl<ISD::InputArg> &Ins, + bool IsSoftFloat, const SDNode *CallNode, + const Type *RetTy) const; + + void analyzeReturn(const SmallVectorImpl<ISD::OutputArg> &Outs, + bool IsSoftFloat, const Type *RetTy) const; + + const CCState &getCCInfo() const { return CCInfo; } + + /// hasByValArg - Returns true if function has byval arguments. + bool hasByValArg() const { return !ByValArgs.empty(); } + + /// regSize - Size (in number of bits) of integer registers. + unsigned regSize() const { return IsO32 ? 4 : 8; } + + /// numIntArgRegs - Number of integer registers available for calls. + unsigned numIntArgRegs() const; + + /// reservedArgArea - The size of the area the caller reserves for + /// register arguments. This is 16-byte if ABI is O32. + unsigned reservedArgArea() const; + + /// Return pointer to array of integer argument registers. + const uint16_t *intArgRegs() const; + + typedef SmallVectorImpl<ByValArgInfo>::const_iterator byval_iterator; + byval_iterator byval_begin() const { return ByValArgs.begin(); } + byval_iterator byval_end() const { return ByValArgs.end(); } + + private: + void handleByValArg(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags); + + /// useRegsForByval - Returns true if the calling convention allows the + /// use of registers to pass byval arguments. + bool useRegsForByval() const { return CallConv != CallingConv::Fast; } + + /// Return the function that analyzes fixed argument list functions. + llvm::CCAssignFn *fixedArgFn() const; + + /// Return the function that analyzes variable argument list functions. + llvm::CCAssignFn *varArgFn() const; + + const uint16_t *shadowRegs() const; + + void allocateRegs(ByValArgInfo &ByVal, unsigned ByValSize, + unsigned Align); + + /// Return the type of the register which is used to pass an argument or + /// return a value. This function returns f64 if the argument is an i64 + /// value which has been generated as a result of softening an f128 value. + /// Otherwise, it just returns VT. + MVT getRegVT(MVT VT, const Type *OrigTy, const SDNode *CallNode, + bool IsSoftFloat) const; + + template<typename Ty> + void analyzeReturn(const SmallVectorImpl<Ty> &RetVals, bool IsSoftFloat, + const SDNode *CallNode, const Type *RetTy) const; + + CCState &CCInfo; + CallingConv::ID CallConv; + bool IsO32, IsFP64; + SpecialCallingConvType SpecialCallingConv; + SmallVector<ByValArgInfo, 2> ByValArgs; + }; + protected: + SDValue lowerLOAD(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSTORE(SDValue Op, SelectionDAG &DAG) const; + + // Subtarget Info + const MipsSubtarget *Subtarget; + + bool HasMips64, IsN64, IsO32; + + private: + // Create a TargetGlobalAddress node. + SDValue getTargetNode(GlobalAddressSDNode *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag) const; + + // Create a TargetExternalSymbol node. + SDValue getTargetNode(ExternalSymbolSDNode *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag) const; + + // Create a TargetBlockAddress node. + SDValue getTargetNode(BlockAddressSDNode *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag) const; + + // Create a TargetJumpTable node. + SDValue getTargetNode(JumpTableSDNode *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag) const; + + // Create a TargetConstantPool node. + SDValue getTargetNode(ConstantPoolSDNode *N, EVT Ty, SelectionDAG &DAG, + unsigned Flag) const; + + MipsCC::SpecialCallingConvType getSpecialCallingConv(SDValue Callee) const; + // Lower Operand helpers + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + SDLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals, + const SDNode *CallNode, const Type *RetTy) const; + + // Lower Operand specifics + SDValue lowerBR_JT(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerBRCOND(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerConstantPool(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerJumpTable(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSELECT(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSETCC(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerFABS(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerATOMIC_FENCE(SDValue Op, SelectionDAG& DAG) const; + SDValue lowerShiftLeftParts(SDValue Op, SelectionDAG& DAG) const; + SDValue lowerShiftRightParts(SDValue Op, SelectionDAG& DAG, + bool IsSRA) const; + SDValue lowerADD(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) const; + + /// isEligibleForTailCallOptimization - Check whether the call is eligible + /// for tail call optimization. + virtual bool + isEligibleForTailCallOptimization(const MipsCC &MipsCCInfo, + unsigned NextStackOffset, + const MipsFunctionInfo& FI) const = 0; + + /// copyByValArg - Copy argument registers which were used to pass a byval + /// argument to the stack. Create a stack frame object for the byval + /// argument. + void copyByValRegs(SDValue Chain, SDLoc DL, + std::vector<SDValue> &OutChains, SelectionDAG &DAG, + const ISD::ArgFlagsTy &Flags, + SmallVectorImpl<SDValue> &InVals, + const Argument *FuncArg, + const MipsCC &CC, const ByValArgInfo &ByVal) const; + + /// passByValArg - Pass a byval argument in registers or on stack. + void passByValArg(SDValue Chain, SDLoc DL, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + SmallVectorImpl<SDValue> &MemOpChains, SDValue StackPtr, + MachineFrameInfo *MFI, SelectionDAG &DAG, SDValue Arg, + const MipsCC &CC, const ByValArgInfo &ByVal, + const ISD::ArgFlagsTy &Flags, bool isLittle) const; + + /// writeVarArgRegs - Write variable function arguments passed in registers + /// to the stack. Also create a stack frame object for the first variable + /// argument. + void writeVarArgRegs(std::vector<SDValue> &OutChains, const MipsCC &CC, + SDValue Chain, SDLoc DL, SelectionDAG &DAG) const; + + virtual SDValue + LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + SDLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + SDValue passArgOnStack(SDValue StackPtr, unsigned Offset, SDValue Chain, + SDValue Arg, SDLoc DL, bool IsTailCall, + SelectionDAG &DAG) const; + + virtual SDValue + LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl<SDValue> &InVals) const; + + virtual bool + CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, + bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + LLVMContext &Context) const; + + virtual SDValue + LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + SDLoc dl, SelectionDAG &DAG) 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; + + /// This function parses registers that appear in inline-asm constraints. + /// It returns pair (0, 0) on failure. + std::pair<unsigned, const TargetRegisterClass *> + parseRegForInlineAsmConstraint(const StringRef &C, MVT VT) const; + + std::pair<unsigned, const TargetRegisterClass*> + getRegForInlineAsmConstraint(const std::string &Constraint, + MVT VT) const; + + /// LowerAsmOperandForConstraint - Lower the specified operand into the Ops + /// vector. If it is invalid, don't add anything to Ops. If hasMemory is + /// true it means one of the asm constraint of the inline asm instruction + /// being processed is 'm'. + virtual void LowerAsmOperandForConstraint(SDValue Op, + std::string &Constraint, + std::vector<SDValue> &Ops, + SelectionDAG &DAG) const; + + virtual bool isLegalAddressingMode(const AddrMode &AM, Type *Ty) const; + + virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; + + virtual EVT getOptimalMemOpType(uint64_t Size, unsigned DstAlign, + unsigned SrcAlign, + bool IsMemset, bool ZeroMemset, + bool MemcpyStrSrc, + MachineFunction &MF) 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; + + virtual unsigned getJumpTableEncoding() const; + + MachineBasicBlock *emitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB, + unsigned Size, unsigned BinOpcode, bool Nand = false) const; + MachineBasicBlock *emitAtomicBinaryPartword(MachineInstr *MI, + MachineBasicBlock *BB, unsigned Size, unsigned BinOpcode, + bool Nand = false) const; + MachineBasicBlock *emitAtomicCmpSwap(MachineInstr *MI, + MachineBasicBlock *BB, unsigned Size) const; + MachineBasicBlock *emitAtomicCmpSwapPartword(MachineInstr *MI, + MachineBasicBlock *BB, unsigned Size) const; + }; + + /// Create MipsTargetLowering objects. + const MipsTargetLowering *createMips16TargetLowering(MipsTargetMachine &TM); + const MipsTargetLowering *createMipsSETargetLowering(MipsTargetMachine &TM); +} + +#endif // MipsISELLOWERING_H diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td b/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td new file mode 100644 index 000000000000..9f7ce9aa72b0 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsInstrFPU.td @@ -0,0 +1,605 @@ +//===-- MipsInstrFPU.td - Mips FPU Instruction Information -*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the Mips FPU instruction set. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Floating Point Instructions +// ------------------------ +// * 64bit fp: +// - 32 64-bit registers (default mode) +// - 16 even 32-bit registers (32-bit compatible mode) for +// single and double access. +// * 32bit fp: +// - 16 even 32-bit registers - single and double (aliased) +// - 32 32-bit registers (within single-only mode) +//===----------------------------------------------------------------------===// + +// Floating Point Compare and Branch +def SDT_MipsFPBrcond : SDTypeProfile<0, 3, [SDTCisInt<0>, + SDTCisVT<1, i32>, + SDTCisVT<2, OtherVT>]>; +def SDT_MipsFPCmp : SDTypeProfile<0, 3, [SDTCisSameAs<0, 1>, SDTCisFP<1>, + SDTCisVT<2, i32>]>; +def SDT_MipsCMovFP : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisVT<2, i32>, + SDTCisSameAs<1, 3>]>; +def SDT_MipsTruncIntFP : SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisFP<1>]>; +def SDT_MipsBuildPairF64 : SDTypeProfile<1, 2, [SDTCisVT<0, f64>, + SDTCisVT<1, i32>, + SDTCisSameAs<1, 2>]>; +def SDT_MipsExtractElementF64 : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, + SDTCisVT<1, f64>, + SDTCisVT<2, i32>]>; + +def MipsFPCmp : SDNode<"MipsISD::FPCmp", SDT_MipsFPCmp, [SDNPOutGlue]>; +def MipsCMovFP_T : SDNode<"MipsISD::CMovFP_T", SDT_MipsCMovFP, [SDNPInGlue]>; +def MipsCMovFP_F : SDNode<"MipsISD::CMovFP_F", SDT_MipsCMovFP, [SDNPInGlue]>; +def MipsFPBrcond : SDNode<"MipsISD::FPBrcond", SDT_MipsFPBrcond, + [SDNPHasChain, SDNPOptInGlue]>; +def MipsTruncIntFP : SDNode<"MipsISD::TruncIntFP", SDT_MipsTruncIntFP>; +def MipsBuildPairF64 : SDNode<"MipsISD::BuildPairF64", SDT_MipsBuildPairF64>; +def MipsExtractElementF64 : SDNode<"MipsISD::ExtractElementF64", + SDT_MipsExtractElementF64>; + +// Operand for printing out a condition code. +let PrintMethod = "printFCCOperand", DecoderMethod = "DecodeCondCode" in + def condcode : Operand<i32>; + +//===----------------------------------------------------------------------===// +// Feature predicates. +//===----------------------------------------------------------------------===// + +def IsFP64bit : Predicate<"Subtarget.isFP64bit()">, + AssemblerPredicate<"FeatureFP64Bit">; +def NotFP64bit : Predicate<"!Subtarget.isFP64bit()">, + AssemblerPredicate<"!FeatureFP64Bit">; +def IsSingleFloat : Predicate<"Subtarget.isSingleFloat()">, + AssemblerPredicate<"FeatureSingleFloat">; +def IsNotSingleFloat : Predicate<"!Subtarget.isSingleFloat()">, + AssemblerPredicate<"!FeatureSingleFloat">; + +// FP immediate patterns. +def fpimm0 : PatLeaf<(fpimm), [{ + return N->isExactlyValue(+0.0); +}]>; + +def fpimm0neg : PatLeaf<(fpimm), [{ + return N->isExactlyValue(-0.0); +}]>; + +//===----------------------------------------------------------------------===// +// Instruction Class Templates +// +// A set of multiclasses is used to address the register usage. +// +// S32 - single precision in 16 32bit even fp registers +// single precision in 32 32bit fp registers in SingleOnly mode +// S64 - single precision in 32 64bit fp registers (In64BitMode) +// D32 - double precision in 16 32bit even fp registers +// D64 - double precision in 32 64bit fp registers (In64BitMode) +// +// Only S32 and D32 are supported right now. +//===----------------------------------------------------------------------===// + +class ADDS_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, bit IsComm, + SDPatternOperator OpNode= null_frag> : + InstSE<(outs RC:$fd), (ins RC:$fs, RC:$ft), + !strconcat(opstr, "\t$fd, $fs, $ft"), + [(set RC:$fd, (OpNode RC:$fs, RC:$ft))], Itin, FrmFR> { + let isCommutable = IsComm; +} + +multiclass ADDS_M<string opstr, InstrItinClass Itin, bit IsComm, + SDPatternOperator OpNode = null_frag> { + def _D32 : ADDS_FT<opstr, AFGR64Opnd, Itin, IsComm, OpNode>, + Requires<[NotFP64bit, HasStdEnc]>; + def _D64 : ADDS_FT<opstr, FGR64Opnd, Itin, IsComm, OpNode>, + Requires<[IsFP64bit, HasStdEnc]> { + string DecoderNamespace = "Mips64"; + } +} + +class ABSS_FT<string opstr, RegisterOperand DstRC, RegisterOperand SrcRC, + InstrItinClass Itin, SDPatternOperator OpNode= null_frag> : + InstSE<(outs DstRC:$fd), (ins SrcRC:$fs), !strconcat(opstr, "\t$fd, $fs"), + [(set DstRC:$fd, (OpNode SrcRC:$fs))], Itin, FrmFR>, + NeverHasSideEffects; + +multiclass ABSS_M<string opstr, InstrItinClass Itin, + SDPatternOperator OpNode= null_frag> { + def _D32 : ABSS_FT<opstr, AFGR64Opnd, AFGR64Opnd, Itin, OpNode>, + Requires<[NotFP64bit, HasStdEnc]>; + def _D64 : ABSS_FT<opstr, FGR64Opnd, FGR64Opnd, Itin, OpNode>, + Requires<[IsFP64bit, HasStdEnc]> { + string DecoderNamespace = "Mips64"; + } +} + +multiclass ROUND_M<string opstr, InstrItinClass Itin> { + def _D32 : ABSS_FT<opstr, FGR32Opnd, AFGR64Opnd, Itin>, + Requires<[NotFP64bit, HasStdEnc]>; + def _D64 : ABSS_FT<opstr, FGR32Opnd, FGR64Opnd, Itin>, + Requires<[IsFP64bit, HasStdEnc]> { + let DecoderNamespace = "Mips64"; + } +} + +class MFC1_FT<string opstr, RegisterOperand DstRC, RegisterOperand SrcRC, + InstrItinClass Itin, SDPatternOperator OpNode= null_frag> : + InstSE<(outs DstRC:$rt), (ins SrcRC:$fs), !strconcat(opstr, "\t$rt, $fs"), + [(set DstRC:$rt, (OpNode SrcRC:$fs))], Itin, FrmFR>; + +class MTC1_FT<string opstr, RegisterOperand DstRC, RegisterOperand SrcRC, + InstrItinClass Itin, SDPatternOperator OpNode= null_frag> : + InstSE<(outs DstRC:$fs), (ins SrcRC:$rt), !strconcat(opstr, "\t$rt, $fs"), + [(set DstRC:$fs, (OpNode SrcRC:$rt))], Itin, FrmFR>; + +class LW_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, + SDPatternOperator OpNode= null_frag> : + InstSE<(outs RC:$rt), (ins mem:$addr), !strconcat(opstr, "\t$rt, $addr"), + [(set RC:$rt, (OpNode addrDefault:$addr))], Itin, FrmFI> { + let DecoderMethod = "DecodeFMem"; + let mayLoad = 1; +} + +class SW_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, + SDPatternOperator OpNode= null_frag> : + InstSE<(outs), (ins RC:$rt, mem:$addr), !strconcat(opstr, "\t$rt, $addr"), + [(OpNode RC:$rt, addrDefault:$addr)], Itin, FrmFI> { + let DecoderMethod = "DecodeFMem"; + let mayStore = 1; +} + +class MADDS_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, + SDPatternOperator OpNode = null_frag> : + InstSE<(outs RC:$fd), (ins RC:$fr, RC:$fs, RC:$ft), + !strconcat(opstr, "\t$fd, $fr, $fs, $ft"), + [(set RC:$fd, (OpNode (fmul RC:$fs, RC:$ft), RC:$fr))], Itin, FrmFR>; + +class NMADDS_FT<string opstr, RegisterOperand RC, InstrItinClass Itin, + SDPatternOperator OpNode = null_frag> : + InstSE<(outs RC:$fd), (ins RC:$fr, RC:$fs, RC:$ft), + !strconcat(opstr, "\t$fd, $fr, $fs, $ft"), + [(set RC:$fd, (fsub fpimm0, (OpNode (fmul RC:$fs, RC:$ft), RC:$fr)))], + Itin, FrmFR>; + +class LWXC1_FT<string opstr, RegisterOperand DRC, + InstrItinClass Itin, SDPatternOperator OpNode = null_frag> : + InstSE<(outs DRC:$fd), (ins PtrRC:$base, PtrRC:$index), + !strconcat(opstr, "\t$fd, ${index}(${base})"), + [(set DRC:$fd, (OpNode (add iPTR:$base, iPTR:$index)))], Itin, FrmFI> { + let AddedComplexity = 20; +} + +class SWXC1_FT<string opstr, RegisterOperand DRC, + InstrItinClass Itin, SDPatternOperator OpNode = null_frag> : + InstSE<(outs), (ins DRC:$fs, PtrRC:$base, PtrRC:$index), + !strconcat(opstr, "\t$fs, ${index}(${base})"), + [(OpNode DRC:$fs, (add iPTR:$base, iPTR:$index))], Itin, FrmFI> { + let AddedComplexity = 20; +} + +class BC1F_FT<string opstr, InstrItinClass Itin, + SDPatternOperator Op = null_frag> : + InstSE<(outs), (ins FCCRegsOpnd:$fcc, brtarget:$offset), + !strconcat(opstr, "\t$fcc, $offset"), + [(MipsFPBrcond Op, FCCRegsOpnd:$fcc, bb:$offset)], Itin, FrmFI> { + let isBranch = 1; + let isTerminator = 1; + let hasDelaySlot = 1; + let Defs = [AT]; +} + +class CEQS_FT<string typestr, RegisterClass RC, InstrItinClass Itin, + SDPatternOperator OpNode = null_frag> : + InstSE<(outs), (ins RC:$fs, RC:$ft, condcode:$cond), + !strconcat("c.$cond.", typestr, "\t$fs, $ft"), + [(OpNode RC:$fs, RC:$ft, imm:$cond)], Itin, FrmFR> { + let Defs = [FCC0]; + let isCodeGenOnly = 1; +} + +class C_COND_FT<string CondStr, string Typestr, RegisterOperand RC> : + InstSE<(outs), (ins RC:$fs, RC:$ft), + !strconcat("c.", CondStr, ".", Typestr, "\t$fs, $ft"), [], IIFcmp, + FrmFR>; + +multiclass C_COND_M<string TypeStr, RegisterOperand RC, bits<5> fmt> { + def C_F_#NAME : C_COND_FT<"f", TypeStr, RC>, C_COND_FM<fmt, 0>; + def C_UN_#NAME : C_COND_FT<"un", TypeStr, RC>, C_COND_FM<fmt, 1>; + def C_EQ_#NAME : C_COND_FT<"eq", TypeStr, RC>, C_COND_FM<fmt, 2>; + def C_UEQ_#NAME : C_COND_FT<"ueq", TypeStr, RC>, C_COND_FM<fmt, 3>; + def C_OLT_#NAME : C_COND_FT<"olt", TypeStr, RC>, C_COND_FM<fmt, 4>; + def C_ULT_#NAME : C_COND_FT<"ult", TypeStr, RC>, C_COND_FM<fmt, 5>; + def C_OLE_#NAME : C_COND_FT<"ole", TypeStr, RC>, C_COND_FM<fmt, 6>; + def C_ULE_#NAME : C_COND_FT<"ule", TypeStr, RC>, C_COND_FM<fmt, 7>; + def C_SF_#NAME : C_COND_FT<"sf", TypeStr, RC>, C_COND_FM<fmt, 8>; + def C_NGLE_#NAME : C_COND_FT<"ngle", TypeStr, RC>, C_COND_FM<fmt, 9>; + def C_SEQ_#NAME : C_COND_FT<"seq", TypeStr, RC>, C_COND_FM<fmt, 10>; + def C_NGL_#NAME : C_COND_FT<"ngl", TypeStr, RC>, C_COND_FM<fmt, 11>; + def C_LT_#NAME : C_COND_FT<"lt", TypeStr, RC>, C_COND_FM<fmt, 12>; + def C_NGE_#NAME : C_COND_FT<"nge", TypeStr, RC>, C_COND_FM<fmt, 13>; + def C_LE_#NAME : C_COND_FT<"le", TypeStr, RC>, C_COND_FM<fmt, 14>; + def C_NGT_#NAME : C_COND_FT<"ngt", TypeStr, RC>, C_COND_FM<fmt, 15>; +} + +defm S : C_COND_M<"s", FGR32Opnd, 16>; +defm D32 : C_COND_M<"d", AFGR64Opnd, 17>, + Requires<[NotFP64bit, HasStdEnc]>; +let DecoderNamespace = "Mips64" in +defm D64 : C_COND_M<"d", FGR64Opnd, 17>, Requires<[IsFP64bit, HasStdEnc]>; + +//===----------------------------------------------------------------------===// +// Floating Point Instructions +//===----------------------------------------------------------------------===// +def ROUND_W_S : ABSS_FT<"round.w.s", FGR32Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0xc, 16>; +def TRUNC_W_S : ABSS_FT<"trunc.w.s", FGR32Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0xd, 16>; +def CEIL_W_S : ABSS_FT<"ceil.w.s", FGR32Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0xe, 16>; +def FLOOR_W_S : ABSS_FT<"floor.w.s", FGR32Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0xf, 16>; +def CVT_W_S : ABSS_FT<"cvt.w.s", FGR32Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0x24, 16>; + +defm ROUND_W : ROUND_M<"round.w.d", IIFcvt>, ABSS_FM<0xc, 17>; +defm TRUNC_W : ROUND_M<"trunc.w.d", IIFcvt>, ABSS_FM<0xd, 17>; +defm CEIL_W : ROUND_M<"ceil.w.d", IIFcvt>, ABSS_FM<0xe, 17>; +defm FLOOR_W : ROUND_M<"floor.w.d", IIFcvt>, ABSS_FM<0xf, 17>; +defm CVT_W : ROUND_M<"cvt.w.d", IIFcvt>, ABSS_FM<0x24, 17>; + +let Predicates = [IsFP64bit, HasStdEnc], DecoderNamespace = "Mips64" in { + def ROUND_L_S : ABSS_FT<"round.l.s", FGR64Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0x8, 16>; + def ROUND_L_D64 : ABSS_FT<"round.l.d", FGR64Opnd, FGR64Opnd, IIFcvt>, + ABSS_FM<0x8, 17>; + def TRUNC_L_S : ABSS_FT<"trunc.l.s", FGR64Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0x9, 16>; + def TRUNC_L_D64 : ABSS_FT<"trunc.l.d", FGR64Opnd, FGR64Opnd, IIFcvt>, + ABSS_FM<0x9, 17>; + def CEIL_L_S : ABSS_FT<"ceil.l.s", FGR64Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0xa, 16>; + def CEIL_L_D64 : ABSS_FT<"ceil.l.d", FGR64Opnd, FGR64Opnd, IIFcvt>, + ABSS_FM<0xa, 17>; + def FLOOR_L_S : ABSS_FT<"floor.l.s", FGR64Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0xb, 16>; + def FLOOR_L_D64 : ABSS_FT<"floor.l.d", FGR64Opnd, FGR64Opnd, IIFcvt>, + ABSS_FM<0xb, 17>; +} + +def CVT_S_W : ABSS_FT<"cvt.s.w", FGR32Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0x20, 20>; +def CVT_L_S : ABSS_FT<"cvt.l.s", FGR64Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0x25, 16>; +def CVT_L_D64: ABSS_FT<"cvt.l.d", FGR64Opnd, FGR64Opnd, IIFcvt>, + ABSS_FM<0x25, 17>; + +let Predicates = [NotFP64bit, HasStdEnc] in { + def CVT_S_D32 : ABSS_FT<"cvt.s.d", FGR32Opnd, AFGR64Opnd, IIFcvt>, + ABSS_FM<0x20, 17>; + def CVT_D32_W : ABSS_FT<"cvt.d.w", AFGR64Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0x21, 20>; + def CVT_D32_S : ABSS_FT<"cvt.d.s", AFGR64Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0x21, 16>; +} + +let Predicates = [IsFP64bit, HasStdEnc], DecoderNamespace = "Mips64" in { + def CVT_S_D64 : ABSS_FT<"cvt.s.d", FGR32Opnd, FGR64Opnd, IIFcvt>, + ABSS_FM<0x20, 17>; + def CVT_S_L : ABSS_FT<"cvt.s.l", FGR32Opnd, FGR64Opnd, IIFcvt>, + ABSS_FM<0x20, 21>; + def CVT_D64_W : ABSS_FT<"cvt.d.w", FGR64Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0x21, 20>; + def CVT_D64_S : ABSS_FT<"cvt.d.s", FGR64Opnd, FGR32Opnd, IIFcvt>, + ABSS_FM<0x21, 16>; + def CVT_D64_L : ABSS_FT<"cvt.d.l", FGR64Opnd, FGR64Opnd, IIFcvt>, + ABSS_FM<0x21, 21>; +} + +let isPseudo = 1, isCodeGenOnly = 1 in { + def PseudoCVT_S_W : ABSS_FT<"", FGR32Opnd, GPR32Opnd, IIFcvt>; + def PseudoCVT_D32_W : ABSS_FT<"", AFGR64Opnd, GPR32Opnd, IIFcvt>; + def PseudoCVT_S_L : ABSS_FT<"", FGR64Opnd, GPR64Opnd, IIFcvt>; + def PseudoCVT_D64_W : ABSS_FT<"", FGR64Opnd, GPR32Opnd, IIFcvt>; + def PseudoCVT_D64_L : ABSS_FT<"", FGR64Opnd, GPR64Opnd, IIFcvt>; +} + +let Predicates = [NoNaNsFPMath, HasStdEnc] in { + def FABS_S : ABSS_FT<"abs.s", FGR32Opnd, FGR32Opnd, IIFcvt, fabs>, + ABSS_FM<0x5, 16>; + def FNEG_S : ABSS_FT<"neg.s", FGR32Opnd, FGR32Opnd, IIFcvt, fneg>, + ABSS_FM<0x7, 16>; + defm FABS : ABSS_M<"abs.d", IIFcvt, fabs>, ABSS_FM<0x5, 17>; + defm FNEG : ABSS_M<"neg.d", IIFcvt, fneg>, ABSS_FM<0x7, 17>; +} + +def FSQRT_S : ABSS_FT<"sqrt.s", FGR32Opnd, FGR32Opnd, IIFsqrtSingle, + fsqrt>, ABSS_FM<0x4, 16>; +defm FSQRT : ABSS_M<"sqrt.d", IIFsqrtDouble, fsqrt>, ABSS_FM<0x4, 17>; + +// The odd-numbered registers are only referenced when doing loads, +// stores, and moves between floating-point and integer registers. +// When defining instructions, we reference all 32-bit registers, +// regardless of register aliasing. + +/// Move Control Registers From/To CPU Registers +def CFC1 : MFC1_FT<"cfc1", GPR32Opnd, CCROpnd, IIFmove>, MFC1_FM<2>; +def CTC1 : MTC1_FT<"ctc1", CCROpnd, GPR32Opnd, IIFmove>, MFC1_FM<6>; +def MFC1 : MFC1_FT<"mfc1", GPR32Opnd, FGR32Opnd, IIFmoveC1, bitconvert>, + MFC1_FM<0>; +def MTC1 : MTC1_FT<"mtc1", FGR32Opnd, GPR32Opnd, IIFmoveC1, bitconvert>, + MFC1_FM<4>; +def MFHC1 : MFC1_FT<"mfhc1", GPR32Opnd, FGRH32Opnd, IIFmoveC1>, + MFC1_FM<3>; +def MTHC1 : MTC1_FT<"mthc1", FGRH32Opnd, GPR32Opnd, IIFmoveC1>, + MFC1_FM<7>; +def DMFC1 : MFC1_FT<"dmfc1", GPR64Opnd, FGR64Opnd, IIFmoveC1, + bitconvert>, MFC1_FM<1>; +def DMTC1 : MTC1_FT<"dmtc1", FGR64Opnd, GPR64Opnd, IIFmoveC1, + bitconvert>, MFC1_FM<5>; + +def FMOV_S : ABSS_FT<"mov.s", FGR32Opnd, FGR32Opnd, IIFmove>, + ABSS_FM<0x6, 16>; +def FMOV_D32 : ABSS_FT<"mov.d", AFGR64Opnd, AFGR64Opnd, IIFmove>, + ABSS_FM<0x6, 17>, Requires<[NotFP64bit, HasStdEnc]>; +def FMOV_D64 : ABSS_FT<"mov.d", FGR64Opnd, FGR64Opnd, IIFmove>, + ABSS_FM<0x6, 17>, Requires<[IsFP64bit, HasStdEnc]> { + let DecoderNamespace = "Mips64"; +} + +/// Floating Point Memory Instructions +let Predicates = [HasStdEnc] in { + def LWC1 : LW_FT<"lwc1", FGR32Opnd, IIFLoad, load>, LW_FM<0x31>; + def SWC1 : SW_FT<"swc1", FGR32Opnd, IIFStore, store>, LW_FM<0x39>; +} + +let Predicates = [IsFP64bit, HasStdEnc], DecoderNamespace = "Mips64" in { + def LDC164 : LW_FT<"ldc1", FGR64Opnd, IIFLoad, load>, LW_FM<0x35>; + def SDC164 : SW_FT<"sdc1", FGR64Opnd, IIFStore, store>, LW_FM<0x3d>; +} + +let Predicates = [NotFP64bit, HasStdEnc] in { + def LDC1 : LW_FT<"ldc1", AFGR64Opnd, IIFLoad, load>, LW_FM<0x35>; + def SDC1 : SW_FT<"sdc1", AFGR64Opnd, IIFStore, store>, LW_FM<0x3d>; +} + +/// Cop2 Memory Instructions +let Predicates = [HasStdEnc] in { + def LWC2 : LW_FT<"lwc2", COP2Opnd, NoItinerary, load>, LW_FM<0x32>; + def SWC2 : SW_FT<"swc2", COP2Opnd, NoItinerary, store>, LW_FM<0x3a>; + def LDC2 : LW_FT<"ldc2", COP2Opnd, NoItinerary, load>, LW_FM<0x36>; + def SDC2 : SW_FT<"sdc2", COP2Opnd, NoItinerary, store>, LW_FM<0x3e>; +} + +// Indexed loads and stores. +let Predicates = [HasFPIdx, HasStdEnc] in { + def LWXC1 : LWXC1_FT<"lwxc1", FGR32Opnd, IIFLoad, load>, LWXC1_FM<0>; + def SWXC1 : SWXC1_FT<"swxc1", FGR32Opnd, IIFStore, store>, SWXC1_FM<8>; +} + +let Predicates = [HasFPIdx, NotFP64bit, HasStdEnc] in { + def LDXC1 : LWXC1_FT<"ldxc1", AFGR64Opnd, IIFLoad, load>, LWXC1_FM<1>; + def SDXC1 : SWXC1_FT<"sdxc1", AFGR64Opnd, IIFStore, store>, SWXC1_FM<9>; +} + +let Predicates = [HasFPIdx, IsFP64bit, HasStdEnc], + DecoderNamespace="Mips64" in { + def LDXC164 : LWXC1_FT<"ldxc1", FGR64Opnd, IIFLoad, load>, LWXC1_FM<1>; + def SDXC164 : SWXC1_FT<"sdxc1", FGR64Opnd, IIFStore, store>, SWXC1_FM<9>; +} + +// Load/store doubleword indexed unaligned. +let Predicates = [NotFP64bit, HasStdEnc] in { + def LUXC1 : LWXC1_FT<"luxc1", AFGR64Opnd, IIFLoad>, LWXC1_FM<0x5>; + def SUXC1 : SWXC1_FT<"suxc1", AFGR64Opnd, IIFStore>, SWXC1_FM<0xd>; +} + +let Predicates = [IsFP64bit, HasStdEnc], DecoderNamespace="Mips64" in { + def LUXC164 : LWXC1_FT<"luxc1", FGR64Opnd, IIFLoad>, LWXC1_FM<0x5>; + def SUXC164 : SWXC1_FT<"suxc1", FGR64Opnd, IIFStore>, SWXC1_FM<0xd>; +} + +/// Floating-point Aritmetic +def FADD_S : ADDS_FT<"add.s", FGR32Opnd, IIFadd, 1, fadd>, + ADDS_FM<0x00, 16>; +defm FADD : ADDS_M<"add.d", IIFadd, 1, fadd>, ADDS_FM<0x00, 17>; +def FDIV_S : ADDS_FT<"div.s", FGR32Opnd, IIFdivSingle, 0, fdiv>, + ADDS_FM<0x03, 16>; +defm FDIV : ADDS_M<"div.d", IIFdivDouble, 0, fdiv>, ADDS_FM<0x03, 17>; +def FMUL_S : ADDS_FT<"mul.s", FGR32Opnd, IIFmulSingle, 1, fmul>, + ADDS_FM<0x02, 16>; +defm FMUL : ADDS_M<"mul.d", IIFmulDouble, 1, fmul>, ADDS_FM<0x02, 17>; +def FSUB_S : ADDS_FT<"sub.s", FGR32Opnd, IIFadd, 0, fsub>, + ADDS_FM<0x01, 16>; +defm FSUB : ADDS_M<"sub.d", IIFadd, 0, fsub>, ADDS_FM<0x01, 17>; + +let Predicates = [HasMips32r2, HasStdEnc] in { + def MADD_S : MADDS_FT<"madd.s", FGR32Opnd, IIFmulSingle, fadd>, + MADDS_FM<4, 0>; + def MSUB_S : MADDS_FT<"msub.s", FGR32Opnd, IIFmulSingle, fsub>, + MADDS_FM<5, 0>; +} + +let Predicates = [HasMips32r2, NoNaNsFPMath, HasStdEnc] in { + def NMADD_S : NMADDS_FT<"nmadd.s", FGR32Opnd, IIFmulSingle, fadd>, + MADDS_FM<6, 0>; + def NMSUB_S : NMADDS_FT<"nmsub.s", FGR32Opnd, IIFmulSingle, fsub>, + MADDS_FM<7, 0>; +} + +let Predicates = [HasMips32r2, NotFP64bit, HasStdEnc] in { + def MADD_D32 : MADDS_FT<"madd.d", AFGR64Opnd, IIFmulDouble, fadd>, + MADDS_FM<4, 1>; + def MSUB_D32 : MADDS_FT<"msub.d", AFGR64Opnd, IIFmulDouble, fsub>, + MADDS_FM<5, 1>; +} + +let Predicates = [HasMips32r2, NotFP64bit, NoNaNsFPMath, HasStdEnc] in { + def NMADD_D32 : NMADDS_FT<"nmadd.d", AFGR64Opnd, IIFmulDouble, fadd>, + MADDS_FM<6, 1>; + def NMSUB_D32 : NMADDS_FT<"nmsub.d", AFGR64Opnd, IIFmulDouble, fsub>, + MADDS_FM<7, 1>; +} + +let Predicates = [HasMips32r2, IsFP64bit, HasStdEnc], isCodeGenOnly=1 in { + def MADD_D64 : MADDS_FT<"madd.d", FGR64Opnd, IIFmulDouble, fadd>, + MADDS_FM<4, 1>; + def MSUB_D64 : MADDS_FT<"msub.d", FGR64Opnd, IIFmulDouble, fsub>, + MADDS_FM<5, 1>; +} + +let Predicates = [HasMips32r2, IsFP64bit, NoNaNsFPMath, HasStdEnc], + isCodeGenOnly=1 in { + def NMADD_D64 : NMADDS_FT<"nmadd.d", FGR64Opnd, IIFmulDouble, fadd>, + MADDS_FM<6, 1>; + def NMSUB_D64 : NMADDS_FT<"nmsub.d", FGR64Opnd, IIFmulDouble, fsub>, + MADDS_FM<7, 1>; +} + +//===----------------------------------------------------------------------===// +// Floating Point Branch Codes +//===----------------------------------------------------------------------===// +// Mips branch codes. These correspond to condcode in MipsInstrInfo.h. +// They must be kept in synch. +def MIPS_BRANCH_F : PatLeaf<(i32 0)>; +def MIPS_BRANCH_T : PatLeaf<(i32 1)>; + +def BC1F : BC1F_FT<"bc1f", IIBranch, MIPS_BRANCH_F>, BC1F_FM<0, 0>; +def BC1T : BC1F_FT<"bc1t", IIBranch, MIPS_BRANCH_T>, BC1F_FM<0, 1>; + +//===----------------------------------------------------------------------===// +// Floating Point Flag Conditions +//===----------------------------------------------------------------------===// +// Mips condition codes. They must correspond to condcode in MipsInstrInfo.h. +// They must be kept in synch. +def MIPS_FCOND_F : PatLeaf<(i32 0)>; +def MIPS_FCOND_UN : PatLeaf<(i32 1)>; +def MIPS_FCOND_OEQ : PatLeaf<(i32 2)>; +def MIPS_FCOND_UEQ : PatLeaf<(i32 3)>; +def MIPS_FCOND_OLT : PatLeaf<(i32 4)>; +def MIPS_FCOND_ULT : PatLeaf<(i32 5)>; +def MIPS_FCOND_OLE : PatLeaf<(i32 6)>; +def MIPS_FCOND_ULE : PatLeaf<(i32 7)>; +def MIPS_FCOND_SF : PatLeaf<(i32 8)>; +def MIPS_FCOND_NGLE : PatLeaf<(i32 9)>; +def MIPS_FCOND_SEQ : PatLeaf<(i32 10)>; +def MIPS_FCOND_NGL : PatLeaf<(i32 11)>; +def MIPS_FCOND_LT : PatLeaf<(i32 12)>; +def MIPS_FCOND_NGE : PatLeaf<(i32 13)>; +def MIPS_FCOND_LE : PatLeaf<(i32 14)>; +def MIPS_FCOND_NGT : PatLeaf<(i32 15)>; + +/// Floating Point Compare +def FCMP_S32 : CEQS_FT<"s", FGR32, IIFcmp, MipsFPCmp>, CEQS_FM<16>; +def FCMP_D32 : CEQS_FT<"d", AFGR64, IIFcmp, MipsFPCmp>, CEQS_FM<17>, + Requires<[NotFP64bit, HasStdEnc]>; +let DecoderNamespace = "Mips64" in +def FCMP_D64 : CEQS_FT<"d", FGR64, IIFcmp, MipsFPCmp>, CEQS_FM<17>, + Requires<[IsFP64bit, HasStdEnc]>; + +//===----------------------------------------------------------------------===// +// Floating Point Pseudo-Instructions +//===----------------------------------------------------------------------===// + +// This pseudo instr gets expanded into 2 mtc1 instrs after register +// allocation. +class BuildPairF64Base<RegisterOperand RO> : + PseudoSE<(outs RO:$dst), (ins GPR32Opnd:$lo, GPR32Opnd:$hi), + [(set RO:$dst, (MipsBuildPairF64 GPR32Opnd:$lo, GPR32Opnd:$hi))]>; + +def BuildPairF64 : BuildPairF64Base<AFGR64Opnd>, + Requires<[NotFP64bit, HasStdEnc]>; +def BuildPairF64_64 : BuildPairF64Base<FGR64Opnd>, + Requires<[IsFP64bit, HasStdEnc]>; + +// This pseudo instr gets expanded into 2 mfc1 instrs after register +// allocation. +// if n is 0, lower part of src is extracted. +// if n is 1, higher part of src is extracted. +class ExtractElementF64Base<RegisterOperand RO> : + PseudoSE<(outs GPR32Opnd:$dst), (ins RO:$src, i32imm:$n), + [(set GPR32Opnd:$dst, (MipsExtractElementF64 RO:$src, imm:$n))]>; + +def ExtractElementF64 : ExtractElementF64Base<AFGR64Opnd>, + Requires<[NotFP64bit, HasStdEnc]>; +def ExtractElementF64_64 : ExtractElementF64Base<FGR64Opnd>, + Requires<[IsFP64bit, HasStdEnc]>; + +//===----------------------------------------------------------------------===// +// InstAliases. +//===----------------------------------------------------------------------===// +def : InstAlias<"bc1t $offset", (BC1T FCC0, brtarget:$offset)>; +def : InstAlias<"bc1f $offset", (BC1F FCC0, brtarget:$offset)>; + +//===----------------------------------------------------------------------===// +// Floating Point Patterns +//===----------------------------------------------------------------------===// +def : MipsPat<(f32 fpimm0), (MTC1 ZERO)>; +def : MipsPat<(f32 fpimm0neg), (FNEG_S (MTC1 ZERO))>; + +def : MipsPat<(f32 (sint_to_fp GPR32Opnd:$src)), + (PseudoCVT_S_W GPR32Opnd:$src)>; +def : MipsPat<(MipsTruncIntFP FGR32Opnd:$src), + (TRUNC_W_S FGR32Opnd:$src)>; + +let Predicates = [NotFP64bit, HasStdEnc] in { + def : MipsPat<(f64 (sint_to_fp GPR32Opnd:$src)), + (PseudoCVT_D32_W GPR32Opnd:$src)>; + def : MipsPat<(MipsTruncIntFP AFGR64Opnd:$src), + (TRUNC_W_D32 AFGR64Opnd:$src)>; + def : MipsPat<(f32 (fround AFGR64Opnd:$src)), + (CVT_S_D32 AFGR64Opnd:$src)>; + def : MipsPat<(f64 (fextend FGR32Opnd:$src)), + (CVT_D32_S FGR32Opnd:$src)>; +} + +let Predicates = [IsFP64bit, HasStdEnc] in { + def : MipsPat<(f64 fpimm0), (DMTC1 ZERO_64)>; + def : MipsPat<(f64 fpimm0neg), (FNEG_D64 (DMTC1 ZERO_64))>; + + def : MipsPat<(f64 (sint_to_fp GPR32Opnd:$src)), + (PseudoCVT_D64_W GPR32Opnd:$src)>; + def : MipsPat<(f32 (sint_to_fp GPR64Opnd:$src)), + (EXTRACT_SUBREG (PseudoCVT_S_L GPR64Opnd:$src), sub_lo)>; + def : MipsPat<(f64 (sint_to_fp GPR64Opnd:$src)), + (PseudoCVT_D64_L GPR64Opnd:$src)>; + + def : MipsPat<(MipsTruncIntFP FGR64Opnd:$src), + (TRUNC_W_D64 FGR64Opnd:$src)>; + def : MipsPat<(MipsTruncIntFP FGR32Opnd:$src), + (TRUNC_L_S FGR32Opnd:$src)>; + def : MipsPat<(MipsTruncIntFP FGR64Opnd:$src), + (TRUNC_L_D64 FGR64Opnd:$src)>; + + def : MipsPat<(f32 (fround FGR64Opnd:$src)), + (CVT_S_D64 FGR64Opnd:$src)>; + def : MipsPat<(f64 (fextend FGR32Opnd:$src)), + (CVT_D64_S FGR32Opnd:$src)>; +} + +// Patterns for loads/stores with a reg+imm operand. +let AddedComplexity = 40 in { + let Predicates = [HasStdEnc] in { + def : LoadRegImmPat<LWC1, f32, load>; + def : StoreRegImmPat<SWC1, f32>; + } + + let Predicates = [IsFP64bit, HasStdEnc] in { + def : LoadRegImmPat<LDC164, f64, load>; + def : StoreRegImmPat<SDC164, f64>; + } + + let Predicates = [NotFP64bit, HasStdEnc] in { + def : LoadRegImmPat<LDC1, f64, load>; + def : StoreRegImmPat<SDC1, f64>; + } +} diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td b/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td new file mode 100644 index 000000000000..737a018c67af --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsInstrFormats.td @@ -0,0 +1,754 @@ +//===-- MipsInstrFormats.td - Mips Instruction Formats -----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Describe MIPS instructions format +// +// CPU INSTRUCTION FORMATS +// +// opcode - operation code. +// rs - src reg. +// rt - dst reg (on a 2 regs instr) or src reg (on a 3 reg instr). +// rd - dst reg, only used on 3 regs instr. +// shamt - only used on shift instructions, contains the shift amount. +// funct - combined with opcode field give us an operation code. +// +//===----------------------------------------------------------------------===// + +// 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<4> val> { + bits<4> Value = val; +} + +def Pseudo : Format<0>; +def FrmR : Format<1>; +def FrmI : Format<2>; +def FrmJ : Format<3>; +def FrmFR : Format<4>; +def FrmFI : Format<5>; +def FrmOther : Format<6>; // Instruction w/ a custom format + +class MMRel; + +def Std2MicroMips : InstrMapping { + let FilterClass = "MMRel"; + // Instructions with the same BaseOpcode and isNVStore values form a row. + let RowFields = ["BaseOpcode"]; + // Instructions with the same predicate sense form a column. + let ColFields = ["Arch"]; + // The key column is the unpredicated instructions. + let KeyCol = ["se"]; + // Value columns are PredSense=true and PredSense=false + let ValueCols = [["se"], ["micromips"]]; +} + +class StdArch { + string Arch = "se"; +} + +// Generic Mips Format +class MipsInst<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin, Format f>: Instruction +{ + field bits<32> Inst; + Format Form = f; + + let Namespace = "Mips"; + + let Size = 4; + + bits<6> Opcode = 0; + + // Top 6 bits are the 'opcode' field + let Inst{31-26} = Opcode; + + let OutOperandList = outs; + let InOperandList = ins; + + let AsmString = asmstr; + let Pattern = pattern; + let Itinerary = itin; + + // + // Attributes specific to Mips instructions... + // + bits<4> FormBits = Form.Value; + + // TSFlags layout should be kept in sync with MipsInstrInfo.h. + let TSFlags{3-0} = FormBits; + + let DecoderNamespace = "Mips"; + + field bits<32> SoftFail = 0; +} + +// Mips32/64 Instruction Format +class InstSE<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin, Format f, string opstr = ""> : + MipsInst<outs, ins, asmstr, pattern, itin, f> { + let Predicates = [HasStdEnc]; + string BaseOpcode = opstr; + string Arch; +} + +// Mips Pseudo Instructions Format +class MipsPseudo<dag outs, dag ins, list<dag> pattern, + InstrItinClass itin = IIPseudo> : + MipsInst<outs, ins, "", pattern, itin, Pseudo> { + let isCodeGenOnly = 1; + let isPseudo = 1; +} + +// Mips32/64 Pseudo Instruction Format +class PseudoSE<dag outs, dag ins, list<dag> pattern, + InstrItinClass itin = IIPseudo>: + MipsPseudo<outs, ins, pattern, itin> { + let Predicates = [HasStdEnc]; +} + +// Pseudo-instructions for alternate assembly syntax (never used by codegen). +// These are aliases that require C++ handling to convert to the target +// instruction, while InstAliases can be handled directly by tblgen. +class MipsAsmPseudoInst<dag outs, dag ins, string asmstr>: + MipsInst<outs, ins, asmstr, [], IIPseudo, Pseudo> { + let isPseudo = 1; + let Pattern = []; +} +//===----------------------------------------------------------------------===// +// Format R instruction class in Mips : <|opcode|rs|rt|rd|shamt|funct|> +//===----------------------------------------------------------------------===// + +class FR<bits<6> op, bits<6> _funct, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + InstSE<outs, ins, asmstr, pattern, itin, FrmR> +{ + bits<5> rd; + bits<5> rs; + bits<5> rt; + bits<5> shamt; + bits<6> funct; + + let Opcode = op; + let funct = _funct; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = shamt; + let Inst{5-0} = funct; +} + +//===----------------------------------------------------------------------===// +// Format I instruction class in Mips : <|opcode|rs|rt|immediate|> +//===----------------------------------------------------------------------===// + +class FI<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin>: InstSE<outs, ins, asmstr, pattern, itin, FrmI> +{ + bits<5> rt; + bits<5> rs; + bits<16> imm16; + + let Opcode = op; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +class BranchBase<bits<6> op, dag outs, dag ins, string asmstr, + list<dag> pattern, InstrItinClass itin>: + InstSE<outs, ins, asmstr, pattern, itin, FrmI> +{ + bits<5> rs; + bits<5> rt; + bits<16> imm16; + + let Opcode = op; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +//===----------------------------------------------------------------------===// +// Format J instruction class in Mips : <|opcode|address|> +//===----------------------------------------------------------------------===// + +class FJ<bits<6> op> : StdArch +{ + bits<26> target; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-0} = target; +} + +//===----------------------------------------------------------------------===// +// MFC instruction class in Mips : <|op|mf|rt|rd|0000000|sel|> +//===----------------------------------------------------------------------===// +class MFC3OP_FM<bits<6> op, bits<5> mfmt> +{ + bits<5> rt; + bits<5> rd; + bits<3> sel; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = mfmt; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-3} = 0; + let Inst{2-0} = sel; +} + +class ADD_FM<bits<6> op, bits<6> funct> : StdArch { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +class ADDI_FM<bits<6> op> : StdArch { + bits<5> rs; + bits<5> rt; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +class SRA_FM<bits<6> funct, bit rotate> : StdArch { + bits<5> rd; + bits<5> rt; + bits<5> shamt; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-22} = 0; + let Inst{21} = rotate; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = shamt; + let Inst{5-0} = funct; +} + +class SRLV_FM<bits<6> funct, bit rotate> : StdArch { + bits<5> rd; + bits<5> rt; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-7} = 0; + let Inst{6} = rotate; + let Inst{5-0} = funct; +} + +class BEQ_FM<bits<6> op> : StdArch { + bits<5> rs; + bits<5> rt; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = offset; +} + +class BGEZ_FM<bits<6> op, bits<5> funct> : StdArch { + bits<5> rs; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rs; + let Inst{20-16} = funct; + let Inst{15-0} = offset; +} + +class SLTI_FM<bits<6> op> : StdArch { + bits<5> rt; + bits<5> rs; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +class MFLO_FM<bits<6> funct> : StdArch { + bits<5> rd; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-16} = 0; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +class MTLO_FM<bits<6> funct> : StdArch { + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rs; + let Inst{20-6} = 0; + let Inst{5-0} = funct; +} + +class SEB_FM<bits<5> funct, bits<6> funct2> : StdArch { + bits<5> rd; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0x1f; + let Inst{25-21} = 0; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = funct; + let Inst{5-0} = funct2; +} + +class CLO_FM<bits<6> funct> : StdArch { + bits<5> rd; + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0x1c; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = funct; + let rt = rd; +} + +class LUI_FM : StdArch { + bits<5> rt; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = 0xf; + let Inst{25-21} = 0; + let Inst{20-16} = rt; + let Inst{15-0} = imm16; +} + +class JALR_FM : StdArch { + bits<5> rd; + bits<5> rs; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rs; + let Inst{20-16} = 0; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = 9; +} + +class BGEZAL_FM<bits<5> funct> : StdArch { + bits<5> rs; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = 1; + let Inst{25-21} = rs; + let Inst{20-16} = funct; + let Inst{15-0} = offset; +} + +class SYNC_FM { + bits<5> stype; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{10-6} = stype; + let Inst{5-0} = 0xf; +} + +class MULT_FM<bits<6> op, bits<6> funct> : StdArch { + bits<5> rs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-6} = 0; + let Inst{5-0} = funct; +} + +class EXT_FM<bits<6> funct> : StdArch { + bits<5> rt; + bits<5> rs; + bits<5> pos; + bits<5> size; + + bits<32> Inst; + + let Inst{31-26} = 0x1f; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = size; + let Inst{10-6} = pos; + let Inst{5-0} = funct; +} + +class RDHWR_FM { + bits<5> rt; + bits<5> rd; + + bits<32> Inst; + + let Inst{31-26} = 0x1f; + let Inst{25-21} = 0; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = 0x3b; +} + +class TEQ_FM<bits<6> funct> : StdArch { + bits<5> rs; + bits<5> rt; + bits<10> code_; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-6} = code_; + let Inst{5-0} = funct; +} + +class TEQI_FM<bits<5> funct> : StdArch { + bits<5> rs; + bits<16> imm16; + + bits<32> Inst; + + let Inst{31-26} = 1; + let Inst{25-21} = rs; + let Inst{20-16} = funct; + let Inst{15-0} = imm16; +} +//===----------------------------------------------------------------------===// +// System calls format <op|code_|funct> +//===----------------------------------------------------------------------===// + +class SYS_FM<bits<6> funct> +{ + bits<20> code_; + bits<32> Inst; + let Inst{31-26} = 0x0; + let Inst{25-6} = code_; + let Inst{5-0} = funct; +} + +//===----------------------------------------------------------------------===// +// Break instruction format <op|code_1|funct> +//===----------------------------------------------------------------------===// + +class BRK_FM<bits<6> funct> +{ + bits<10> code_1; + bits<10> code_2; + bits<32> Inst; + let Inst{31-26} = 0x0; + let Inst{25-16} = code_1; + let Inst{15-6} = code_2; + let Inst{5-0} = funct; +} + +//===----------------------------------------------------------------------===// +// Exception return format <Cop0|1|0|funct> +//===----------------------------------------------------------------------===// + +class ER_FM<bits<6> funct> +{ + bits<32> Inst; + let Inst{31-26} = 0x10; + let Inst{25} = 1; + let Inst{24-6} = 0; + let Inst{5-0} = funct; +} + + +//===----------------------------------------------------------------------===// +// Enable/disable interrupt instruction format <Cop0|MFMC0|rt|12|0|sc|0|0> +//===----------------------------------------------------------------------===// + +class EI_FM<bits<1> sc> +{ + bits<32> Inst; + bits<5> rt; + let Inst{31-26} = 0x10; + let Inst{25-21} = 0xb; + let Inst{20-16} = rt; + let Inst{15-11} = 0xc; + let Inst{10-6} = 0; + let Inst{5} = sc; + let Inst{4-0} = 0; +} + +//===----------------------------------------------------------------------===// +// +// FLOATING POINT INSTRUCTION FORMATS +// +// opcode - operation code. +// fs - src reg. +// ft - dst reg (on a 2 regs instr) or src reg (on a 3 reg instr). +// fd - dst reg, only used on 3 regs instr. +// fmt - double or single precision. +// funct - combined with opcode field give us an operation code. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Format FI instruction class in Mips : <|opcode|base|ft|immediate|> +//===----------------------------------------------------------------------===// + +class FFI<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern>: + InstSE<outs, ins, asmstr, pattern, NoItinerary, FrmFI> +{ + bits<5> ft; + bits<5> base; + bits<16> imm16; + + let Opcode = op; + + let Inst{25-21} = base; + let Inst{20-16} = ft; + let Inst{15-0} = imm16; +} + +class ADDS_FM<bits<6> funct, bits<5> fmt> { + bits<5> fd; + bits<5> fs; + bits<5> ft; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = fmt; + let Inst{20-16} = ft; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} + +class ABSS_FM<bits<6> funct, bits<5> fmt> { + bits<5> fd; + bits<5> fs; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = fmt; + let Inst{20-16} = 0; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} + +class MFC1_FM<bits<5> funct> { + bits<5> rt; + bits<5> fs; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = funct; + let Inst{20-16} = rt; + let Inst{15-11} = fs; + let Inst{10-0} = 0; +} + +class LW_FM<bits<6> op> : StdArch { + bits<5> rt; + bits<21> addr; + + bits<32> Inst; + + let Inst{31-26} = op; + let Inst{25-21} = addr{20-16}; + let Inst{20-16} = rt; + let Inst{15-0} = addr{15-0}; +} + +class MADDS_FM<bits<3> funct, bits<3> fmt> { + bits<5> fd; + bits<5> fr; + bits<5> fs; + bits<5> ft; + + bits<32> Inst; + + let Inst{31-26} = 0x13; + let Inst{25-21} = fr; + let Inst{20-16} = ft; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-3} = funct; + let Inst{2-0} = fmt; +} + +class LWXC1_FM<bits<6> funct> { + bits<5> fd; + bits<5> base; + bits<5> index; + + bits<32> Inst; + + let Inst{31-26} = 0x13; + let Inst{25-21} = base; + let Inst{20-16} = index; + let Inst{15-11} = 0; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} + +class SWXC1_FM<bits<6> funct> { + bits<5> fs; + bits<5> base; + bits<5> index; + + bits<32> Inst; + + let Inst{31-26} = 0x13; + let Inst{25-21} = base; + let Inst{20-16} = index; + let Inst{15-11} = fs; + let Inst{10-6} = 0; + let Inst{5-0} = funct; +} + +class BC1F_FM<bit nd, bit tf> { + bits<3> fcc; + bits<16> offset; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = 0x8; + let Inst{20-18} = fcc; + let Inst{17} = nd; + let Inst{16} = tf; + let Inst{15-0} = offset; +} + +class CEQS_FM<bits<5> fmt> { + bits<5> fs; + bits<5> ft; + bits<4> cond; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = fmt; + let Inst{20-16} = ft; + let Inst{15-11} = fs; + let Inst{10-8} = 0; // cc + let Inst{7-4} = 0x3; + let Inst{3-0} = cond; +} + +class C_COND_FM<bits<5> fmt, bits<4> c> : CEQS_FM<fmt> { + let cond = c; +} + +class CMov_I_F_FM<bits<6> funct, bits<5> fmt> { + bits<5> fd; + bits<5> fs; + bits<5> rt; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = fmt; + let Inst{20-16} = rt; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = funct; +} + +class CMov_F_I_FM<bit tf> : StdArch { + bits<5> rd; + bits<5> rs; + bits<3> fcc; + + bits<32> Inst; + + let Inst{31-26} = 0; + let Inst{25-21} = rs; + let Inst{20-18} = fcc; + let Inst{17} = 0; + let Inst{16} = tf; + let Inst{15-11} = rd; + let Inst{10-6} = 0; + let Inst{5-0} = 1; +} + +class CMov_F_F_FM<bits<5> fmt, bit tf> { + bits<5> fd; + bits<5> fs; + bits<3> fcc; + + bits<32> Inst; + + let Inst{31-26} = 0x11; + let Inst{25-21} = fmt; + let Inst{20-18} = fcc; + let Inst{17} = 0; + let Inst{16} = tf; + let Inst{15-11} = fs; + let Inst{10-6} = fd; + let Inst{5-0} = 0x11; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp new file mode 100644 index 000000000000..0ebad0584757 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.cpp @@ -0,0 +1,295 @@ +//===-- MipsInstrInfo.cpp - Mips 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 Mips implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "MipsInstrInfo.h" +#include "InstPrinter/MipsInstPrinter.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsMachineFunction.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +#define GET_INSTRINFO_CTOR_DTOR +#include "MipsGenInstrInfo.inc" + +using namespace llvm; + +// Pin the vtable to this file. +void MipsInstrInfo::anchor() {} + +MipsInstrInfo::MipsInstrInfo(MipsTargetMachine &tm, unsigned UncondBr) + : MipsGenInstrInfo(Mips::ADJCALLSTACKDOWN, Mips::ADJCALLSTACKUP), + TM(tm), UncondBrOpc(UncondBr) {} + +const MipsInstrInfo *MipsInstrInfo::create(MipsTargetMachine &TM) { + if (TM.getSubtargetImpl()->inMips16Mode()) + return llvm::createMips16InstrInfo(TM); + + return llvm::createMipsSEInstrInfo(TM); +} + +bool MipsInstrInfo::isZeroImm(const MachineOperand &op) const { + return op.isImm() && op.getImm() == 0; +} + +/// insertNoop - If data hazard condition is found insert the target nop +/// instruction. +void MipsInstrInfo:: +insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const +{ + DebugLoc DL; + BuildMI(MBB, MI, DL, get(Mips::NOP)); +} + +MachineMemOperand *MipsInstrInfo::GetMemOperand(MachineBasicBlock &MBB, int FI, + unsigned Flag) const { + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo &MFI = *MF.getFrameInfo(); + unsigned Align = MFI.getObjectAlignment(FI); + + return MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(FI), Flag, + MFI.getObjectSize(FI), Align); +} + +//===----------------------------------------------------------------------===// +// Branch Analysis +//===----------------------------------------------------------------------===// + +void MipsInstrInfo::AnalyzeCondBr(const MachineInstr *Inst, unsigned Opc, + MachineBasicBlock *&BB, + SmallVectorImpl<MachineOperand> &Cond) const { + assert(getAnalyzableBrOpc(Opc) && "Not an analyzable branch"); + int NumOp = Inst->getNumExplicitOperands(); + + // for both int and fp branches, the last explicit operand is the + // MBB. + BB = Inst->getOperand(NumOp-1).getMBB(); + Cond.push_back(MachineOperand::CreateImm(Opc)); + + for (int i=0; i<NumOp-1; i++) + Cond.push_back(Inst->getOperand(i)); +} + +bool MipsInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const { + SmallVector<MachineInstr*, 2> BranchInstrs; + BranchType BT = AnalyzeBranch(MBB, TBB, FBB, Cond, AllowModify, BranchInstrs); + + return (BT == BT_None) || (BT == BT_Indirect); +} + +void MipsInstrInfo::BuildCondBr(MachineBasicBlock &MBB, + MachineBasicBlock *TBB, DebugLoc DL, + const SmallVectorImpl<MachineOperand>& Cond) + const { + unsigned Opc = Cond[0].getImm(); + const MCInstrDesc &MCID = get(Opc); + MachineInstrBuilder MIB = BuildMI(&MBB, DL, MCID); + + for (unsigned i = 1; i < Cond.size(); ++i) { + if (Cond[i].isReg()) + MIB.addReg(Cond[i].getReg()); + else if (Cond[i].isImm()) + MIB.addImm(Cond[i].getImm()); + else + assert(true && "Cannot copy operand"); + } + MIB.addMBB(TBB); +} + +unsigned MipsInstrInfo:: +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"); + + // # of condition operands: + // Unconditional branches: 0 + // Floating point branches: 1 (opc) + // Int BranchZero: 2 (opc, reg) + // Int Branch: 3 (opc, reg0, reg1) + assert((Cond.size() <= 3) && + "# of Mips branch conditions must be <= 3!"); + + // Two-way Conditional branch. + if (FBB) { + BuildCondBr(MBB, TBB, DL, Cond); + BuildMI(&MBB, DL, get(UncondBrOpc)).addMBB(FBB); + return 2; + } + + // One way branch. + // Unconditional branch. + if (Cond.empty()) + BuildMI(&MBB, DL, get(UncondBrOpc)).addMBB(TBB); + else // Conditional branch. + BuildCondBr(MBB, TBB, DL, Cond); + return 1; +} + +unsigned MipsInstrInfo:: +RemoveBranch(MachineBasicBlock &MBB) const +{ + MachineBasicBlock::reverse_iterator I = MBB.rbegin(), REnd = MBB.rend(); + MachineBasicBlock::reverse_iterator FirstBr; + unsigned removed; + + // Skip all the debug instructions. + while (I != REnd && I->isDebugValue()) + ++I; + + FirstBr = I; + + // Up to 2 branches are removed. + // Note that indirect branches are not removed. + for(removed = 0; I != REnd && removed < 2; ++I, ++removed) + if (!getAnalyzableBrOpc(I->getOpcode())) + break; + + MBB.erase(I.base(), FirstBr.base()); + + return removed; +} + +/// ReverseBranchCondition - Return the inverse opcode of the +/// specified Branch instruction. +bool MipsInstrInfo:: +ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const +{ + assert( (Cond.size() && Cond.size() <= 3) && + "Invalid Mips branch condition!"); + Cond[0].setImm(getOppositeBranchOpc(Cond[0].getImm())); + return false; +} + +MipsInstrInfo::BranchType MipsInstrInfo:: +AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify, + SmallVectorImpl<MachineInstr*> &BranchInstrs) const { + + MachineBasicBlock::reverse_iterator I = MBB.rbegin(), REnd = MBB.rend(); + + // Skip all the debug instructions. + while (I != REnd && I->isDebugValue()) + ++I; + + if (I == REnd || !isUnpredicatedTerminator(&*I)) { + // This block ends with no branches (it just falls through to its succ). + // Leave TBB/FBB null. + TBB = FBB = NULL; + return BT_NoBranch; + } + + MachineInstr *LastInst = &*I; + unsigned LastOpc = LastInst->getOpcode(); + BranchInstrs.push_back(LastInst); + + // Not an analyzable branch (e.g., indirect jump). + if (!getAnalyzableBrOpc(LastOpc)) + return LastInst->isIndirectBranch() ? BT_Indirect : BT_None; + + // Get the second to last instruction in the block. + unsigned SecondLastOpc = 0; + MachineInstr *SecondLastInst = NULL; + + if (++I != REnd) { + SecondLastInst = &*I; + SecondLastOpc = getAnalyzableBrOpc(SecondLastInst->getOpcode()); + + // Not an analyzable branch (must be an indirect jump). + if (isUnpredicatedTerminator(SecondLastInst) && !SecondLastOpc) + return BT_None; + } + + // If there is only one terminator instruction, process it. + if (!SecondLastOpc) { + // Unconditional branch. + if (LastOpc == UncondBrOpc) { + TBB = LastInst->getOperand(0).getMBB(); + return BT_Uncond; + } + + // Conditional branch + AnalyzeCondBr(LastInst, LastOpc, TBB, Cond); + return BT_Cond; + } + + // If we reached here, there are two branches. + // If there are three terminators, we don't know what sort of block this is. + if (++I != REnd && isUnpredicatedTerminator(&*I)) + return BT_None; + + BranchInstrs.insert(BranchInstrs.begin(), SecondLastInst); + + // If second to last instruction is an unconditional branch, + // analyze it and remove the last instruction. + if (SecondLastOpc == UncondBrOpc) { + // Return if the last instruction cannot be removed. + if (!AllowModify) + return BT_None; + + TBB = SecondLastInst->getOperand(0).getMBB(); + LastInst->eraseFromParent(); + BranchInstrs.pop_back(); + return BT_Uncond; + } + + // Conditional branch followed by an unconditional branch. + // The last one must be unconditional. + if (LastOpc != UncondBrOpc) + return BT_None; + + AnalyzeCondBr(SecondLastInst, SecondLastOpc, TBB, Cond); + FBB = LastInst->getOperand(0).getMBB(); + + return BT_CondUncond; +} + +/// Return the number of bytes of code the specified instruction may be. +unsigned MipsInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const { + switch (MI->getOpcode()) { + default: + return MI->getDesc().getSize(); + case TargetOpcode::INLINEASM: { // Inline Asm: Variable size. + const MachineFunction *MF = MI->getParent()->getParent(); + const char *AsmStr = MI->getOperand(0).getSymbolName(); + return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo()); + } + case Mips::CONSTPOOL_ENTRY: + // If this machine instr is a constant pool entry, its size is recorded as + // operand #2. + return MI->getOperand(2).getImm(); + } +} + +MachineInstrBuilder +MipsInstrInfo::genInstrWithNewOpc(unsigned NewOpc, + MachineBasicBlock::iterator I) const { + MachineInstrBuilder MIB; + MIB = BuildMI(*I->getParent(), I, I->getDebugLoc(), get(NewOpc)); + + for (unsigned J = 0, E = I->getDesc().getNumOperands(); J < E; ++J) + MIB.addOperand(I->getOperand(J)); + + MIB.setMemRefs(I->memoperands_begin(), I->memoperands_end()); + return MIB; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.h b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.h new file mode 100644 index 000000000000..d9ac961cd33c --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.h @@ -0,0 +1,144 @@ +//===-- MipsInstrInfo.h - Mips 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 Mips implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSINSTRUCTIONINFO_H +#define MIPSINSTRUCTIONINFO_H + +#include "Mips.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsRegisterInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "MipsGenInstrInfo.inc" + +namespace llvm { + +class MipsInstrInfo : public MipsGenInstrInfo { + virtual void anchor(); +protected: + MipsTargetMachine &TM; + unsigned UncondBrOpc; + +public: + enum BranchType { + BT_None, // Couldn't analyze branch. + BT_NoBranch, // No branches found. + BT_Uncond, // One unconditional branch. + BT_Cond, // One conditional branch. + BT_CondUncond, // A conditional branch followed by an unconditional branch. + BT_Indirect // One indirct branch. + }; + + explicit MipsInstrInfo(MipsTargetMachine &TM, unsigned UncondBrOpc); + + static const MipsInstrInfo *create(MipsTargetMachine &TM); + + /// Branch Analysis + virtual bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const; + + virtual unsigned RemoveBranch(MachineBasicBlock &MBB) const; + + virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond, + DebugLoc DL) const; + + virtual + bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const; + + BranchType AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify, + SmallVectorImpl<MachineInstr*> &BranchInstrs) const; + + /// Insert nop instruction when hazard condition is found + virtual void insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const; + + /// 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 MipsRegisterInfo &getRegisterInfo() const = 0; + + virtual unsigned getOppositeBranchOpc(unsigned Opc) const = 0; + + /// Return the number of bytes of code the specified instruction may be. + unsigned GetInstSizeInBytes(const MachineInstr *MI) const; + + virtual void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + storeRegToStack(MBB, MBBI, SrcReg, isKill, FrameIndex, RC, TRI, 0); + } + + virtual void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + loadRegFromStack(MBB, MBBI, DestReg, FrameIndex, RC, TRI, 0); + } + + virtual void storeRegToStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const = 0; + + virtual void loadRegFromStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const = 0; + + /// Create an instruction which has the same operands and memory operands + /// as MI but has a new opcode. + MachineInstrBuilder genInstrWithNewOpc(unsigned NewOpc, + MachineBasicBlock::iterator I) const; + +protected: + bool isZeroImm(const MachineOperand &op) const; + + MachineMemOperand *GetMemOperand(MachineBasicBlock &MBB, int FI, + unsigned Flag) const; + +private: + virtual unsigned getAnalyzableBrOpc(unsigned Opc) const = 0; + + void AnalyzeCondBr(const MachineInstr *Inst, unsigned Opc, + MachineBasicBlock *&BB, + SmallVectorImpl<MachineOperand> &Cond) const; + + void BuildCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB, DebugLoc DL, + const SmallVectorImpl<MachineOperand>& Cond) const; +}; + +/// Create MipsInstrInfo objects. +const MipsInstrInfo *createMips16InstrInfo(MipsTargetMachine &TM); +const MipsInstrInfo *createMipsSEInstrInfo(MipsTargetMachine &TM); + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td new file mode 100644 index 000000000000..ebdbaa416fcc --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsInstrInfo.td @@ -0,0 +1,1421 @@ +//===- MipsInstrInfo.td - Target Description for Mips Target -*- tablegen -*-=// +// +// 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 Mips implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + + +//===----------------------------------------------------------------------===// +// Mips profiles and nodes +//===----------------------------------------------------------------------===// + +def SDT_MipsJmpLink : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>; +def SDT_MipsCMov : SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, + SDTCisSameAs<1, 2>, + SDTCisSameAs<3, 4>, + SDTCisInt<4>]>; +def SDT_MipsCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>; +def SDT_MipsCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; +def SDT_MFLOHI : SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisVT<1, untyped>]>; +def SDT_MTLOHI : SDTypeProfile<1, 2, [SDTCisVT<0, untyped>, + SDTCisInt<1>, SDTCisSameAs<1, 2>]>; +def SDT_MipsMultDiv : SDTypeProfile<1, 2, [SDTCisVT<0, untyped>, SDTCisInt<1>, + SDTCisSameAs<1, 2>]>; +def SDT_MipsMAddMSub : SDTypeProfile<1, 3, + [SDTCisVT<0, untyped>, SDTCisSameAs<0, 3>, + SDTCisVT<1, i32>, SDTCisSameAs<1, 2>]>; +def SDT_MipsDivRem16 : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisSameAs<0, 1>]>; + +def SDT_MipsThreadPointer : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>; + +def SDT_Sync : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; + +def SDT_Ext : SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<0, 1>, + SDTCisVT<2, i32>, SDTCisSameAs<2, 3>]>; +def SDT_Ins : SDTypeProfile<1, 4, [SDTCisInt<0>, SDTCisSameAs<0, 1>, + SDTCisVT<2, i32>, SDTCisSameAs<2, 3>, + SDTCisSameAs<0, 4>]>; + +def SDTMipsLoadLR : SDTypeProfile<1, 2, + [SDTCisInt<0>, SDTCisPtrTy<1>, + SDTCisSameAs<0, 2>]>; + +// Call +def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink, + [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, + SDNPVariadic]>; + +// Tail call +def MipsTailCall : SDNode<"MipsISD::TailCall", SDT_MipsJmpLink, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + +// Hi and Lo nodes are used to handle global addresses. Used on +// MipsISelLowering to lower stuff like GlobalAddress, ExternalSymbol +// static model. (nothing to do with Mips Registers Hi and Lo) +def MipsHi : SDNode<"MipsISD::Hi", SDTIntUnaryOp>; +def MipsLo : SDNode<"MipsISD::Lo", SDTIntUnaryOp>; +def MipsGPRel : SDNode<"MipsISD::GPRel", SDTIntUnaryOp>; + +// TlsGd node is used to handle General Dynamic TLS +def MipsTlsGd : SDNode<"MipsISD::TlsGd", SDTIntUnaryOp>; + +// TprelHi and TprelLo nodes are used to handle Local Exec TLS +def MipsTprelHi : SDNode<"MipsISD::TprelHi", SDTIntUnaryOp>; +def MipsTprelLo : SDNode<"MipsISD::TprelLo", SDTIntUnaryOp>; + +// Thread pointer +def MipsThreadPointer: SDNode<"MipsISD::ThreadPointer", SDT_MipsThreadPointer>; + +// Return +def MipsRet : SDNode<"MipsISD::Ret", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + +// These are target-independent nodes, but have target-specific formats. +def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_MipsCallSeqStart, + [SDNPHasChain, SDNPSideEffect, SDNPOutGlue]>; +def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_MipsCallSeqEnd, + [SDNPHasChain, SDNPSideEffect, + SDNPOptInGlue, SDNPOutGlue]>; + +// Nodes used to extract LO/HI registers. +def MipsMFHI : SDNode<"MipsISD::MFHI", SDT_MFLOHI>; +def MipsMFLO : SDNode<"MipsISD::MFLO", SDT_MFLOHI>; + +// Node used to insert 32-bit integers to LOHI register pair. +def MipsMTLOHI : SDNode<"MipsISD::MTLOHI", SDT_MTLOHI>; + +// Mult nodes. +def MipsMult : SDNode<"MipsISD::Mult", SDT_MipsMultDiv>; +def MipsMultu : SDNode<"MipsISD::Multu", SDT_MipsMultDiv>; + +// MAdd*/MSub* nodes +def MipsMAdd : SDNode<"MipsISD::MAdd", SDT_MipsMAddMSub>; +def MipsMAddu : SDNode<"MipsISD::MAddu", SDT_MipsMAddMSub>; +def MipsMSub : SDNode<"MipsISD::MSub", SDT_MipsMAddMSub>; +def MipsMSubu : SDNode<"MipsISD::MSubu", SDT_MipsMAddMSub>; + +// DivRem(u) nodes +def MipsDivRem : SDNode<"MipsISD::DivRem", SDT_MipsMultDiv>; +def MipsDivRemU : SDNode<"MipsISD::DivRemU", SDT_MipsMultDiv>; +def MipsDivRem16 : SDNode<"MipsISD::DivRem16", SDT_MipsDivRem16, + [SDNPOutGlue]>; +def MipsDivRemU16 : SDNode<"MipsISD::DivRemU16", SDT_MipsDivRem16, + [SDNPOutGlue]>; + +// Target constant nodes that are not part of any isel patterns and remain +// unchanged can cause instructions with illegal operands to be emitted. +// Wrapper node patterns give the instruction selector a chance to replace +// target constant nodes that would otherwise remain unchanged with ADDiu +// nodes. Without these wrapper node patterns, the following conditional move +// instruction is emitted when function cmov2 in test/CodeGen/Mips/cmov.ll is +// compiled: +// movn %got(d)($gp), %got(c)($gp), $4 +// This instruction is illegal since movn can take only register operands. + +def MipsWrapper : SDNode<"MipsISD::Wrapper", SDTIntBinOp>; + +def MipsSync : SDNode<"MipsISD::Sync", SDT_Sync, [SDNPHasChain,SDNPSideEffect]>; + +def MipsExt : SDNode<"MipsISD::Ext", SDT_Ext>; +def MipsIns : SDNode<"MipsISD::Ins", SDT_Ins>; + +def MipsLWL : SDNode<"MipsISD::LWL", SDTMipsLoadLR, + [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; +def MipsLWR : SDNode<"MipsISD::LWR", SDTMipsLoadLR, + [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; +def MipsSWL : SDNode<"MipsISD::SWL", SDTStore, + [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; +def MipsSWR : SDNode<"MipsISD::SWR", SDTStore, + [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; +def MipsLDL : SDNode<"MipsISD::LDL", SDTMipsLoadLR, + [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; +def MipsLDR : SDNode<"MipsISD::LDR", SDTMipsLoadLR, + [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; +def MipsSDL : SDNode<"MipsISD::SDL", SDTStore, + [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; +def MipsSDR : SDNode<"MipsISD::SDR", SDTStore, + [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; + +//===----------------------------------------------------------------------===// +// Mips Instruction Predicate Definitions. +//===----------------------------------------------------------------------===// +def HasSEInReg : Predicate<"Subtarget.hasSEInReg()">, + AssemblerPredicate<"FeatureSEInReg">; +def HasBitCount : Predicate<"Subtarget.hasBitCount()">, + AssemblerPredicate<"FeatureBitCount">; +def HasSwap : Predicate<"Subtarget.hasSwap()">, + AssemblerPredicate<"FeatureSwap">; +def HasCondMov : Predicate<"Subtarget.hasCondMov()">, + AssemblerPredicate<"FeatureCondMov">; +def HasFPIdx : Predicate<"Subtarget.hasFPIdx()">, + AssemblerPredicate<"FeatureFPIdx">; +def HasMips32 : Predicate<"Subtarget.hasMips32()">, + AssemblerPredicate<"FeatureMips32">; +def HasMips32r2 : Predicate<"Subtarget.hasMips32r2()">, + AssemblerPredicate<"FeatureMips32r2">; +def HasMips64 : Predicate<"Subtarget.hasMips64()">, + AssemblerPredicate<"FeatureMips64">; +def NotMips64 : Predicate<"!Subtarget.hasMips64()">, + AssemblerPredicate<"!FeatureMips64">; +def HasMips64r2 : Predicate<"Subtarget.hasMips64r2()">, + AssemblerPredicate<"FeatureMips64r2">; +def IsN64 : Predicate<"Subtarget.isABI_N64()">, + AssemblerPredicate<"FeatureN64">; +def NotN64 : Predicate<"!Subtarget.isABI_N64()">, + AssemblerPredicate<"!FeatureN64">; +def InMips16Mode : Predicate<"Subtarget.inMips16Mode()">, + AssemblerPredicate<"FeatureMips16">; +def RelocStatic : Predicate<"TM.getRelocationModel() == Reloc::Static">, + AssemblerPredicate<"FeatureMips32">; +def RelocPIC : Predicate<"TM.getRelocationModel() == Reloc::PIC_">, + AssemblerPredicate<"FeatureMips32">; +def NoNaNsFPMath : Predicate<"TM.Options.NoNaNsFPMath">, + AssemblerPredicate<"FeatureMips32">; +def HasStdEnc : Predicate<"Subtarget.hasStandardEncoding()">, + AssemblerPredicate<"!FeatureMips16">; +def NotDSP : Predicate<"!Subtarget.hasDSP()">; +def InMicroMips : Predicate<"Subtarget.inMicroMipsMode()">, + AssemblerPredicate<"FeatureMicroMips">; +def NotInMicroMips : Predicate<"!Subtarget.inMicroMipsMode()">, + AssemblerPredicate<"!FeatureMicroMips">; +def IsLE : Predicate<"Subtarget.isLittle()">; +def IsBE : Predicate<"!Subtarget.isLittle()">; + +class MipsPat<dag pattern, dag result> : Pat<pattern, result> { + let Predicates = [HasStdEnc]; +} + +class IsCommutable { + bit isCommutable = 1; +} + +class IsBranch { + bit isBranch = 1; +} + +class IsReturn { + bit isReturn = 1; +} + +class IsCall { + bit isCall = 1; +} + +class IsTailCall { + bit isCall = 1; + bit isTerminator = 1; + bit isReturn = 1; + bit isBarrier = 1; + bit hasExtraSrcRegAllocReq = 1; + bit isCodeGenOnly = 1; +} + +class IsAsCheapAsAMove { + bit isAsCheapAsAMove = 1; +} + +class NeverHasSideEffects { + bit neverHasSideEffects = 1; +} + +//===----------------------------------------------------------------------===// +// Instruction format superclass +//===----------------------------------------------------------------------===// + +include "MipsInstrFormats.td" + +//===----------------------------------------------------------------------===// +// Mips Operand, Complex Patterns and Transformations Definitions. +//===----------------------------------------------------------------------===// + +// Instruction operand types +def jmptarget : Operand<OtherVT> { + let EncoderMethod = "getJumpTargetOpValue"; +} +def brtarget : Operand<OtherVT> { + let EncoderMethod = "getBranchTargetOpValue"; + let OperandType = "OPERAND_PCREL"; + let DecoderMethod = "DecodeBranchTarget"; +} +def calltarget : Operand<iPTR> { + let EncoderMethod = "getJumpTargetOpValue"; +} + +def simm16 : Operand<i32> { + let DecoderMethod= "DecodeSimm16"; +} + +def simm20 : Operand<i32> { +} + +def uimm20 : Operand<i32> { +} + +def uimm10 : Operand<i32> { +} + +def simm16_64 : Operand<i64> { + let DecoderMethod = "DecodeSimm16"; +} + +// Unsigned Operand +def uimm5 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; +} + +def uimm6 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; +} + +def uimm16 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; +} + +def pcrel16 : Operand<i32> { +} + +def MipsMemAsmOperand : AsmOperandClass { + let Name = "Mem"; + let ParserMethod = "parseMemOperand"; +} + +def MipsInvertedImmoperand : AsmOperandClass { + let Name = "InvNum"; + let RenderMethod = "addImmOperands"; + let ParserMethod = "parseInvNum"; +} + +def PtrRegAsmOperand : AsmOperandClass { + let Name = "PtrReg"; + let ParserMethod = "parsePtrReg"; +} + + +def InvertedImOperand : Operand<i32> { + let ParserMatchClass = MipsInvertedImmoperand; +} + +// Address operand +def mem : Operand<iPTR> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops ptr_rc, simm16); + let EncoderMethod = "getMemEncoding"; + let ParserMatchClass = MipsMemAsmOperand; + let OperandType = "OPERAND_MEMORY"; +} + +def mem_ea : Operand<iPTR> { + let PrintMethod = "printMemOperandEA"; + let MIOperandInfo = (ops ptr_rc, simm16); + let EncoderMethod = "getMemEncoding"; + let OperandType = "OPERAND_MEMORY"; +} + +def PtrRC : Operand<iPTR> { + let MIOperandInfo = (ops ptr_rc); + let DecoderMethod = "DecodePtrRegisterClass"; + let ParserMatchClass = PtrRegAsmOperand; +} + +// size operand of ext instruction +def size_ext : Operand<i32> { + let EncoderMethod = "getSizeExtEncoding"; + let DecoderMethod = "DecodeExtSize"; +} + +// size operand of ins instruction +def size_ins : Operand<i32> { + let EncoderMethod = "getSizeInsEncoding"; + let DecoderMethod = "DecodeInsSize"; +} + +// Transformation Function - get the lower 16 bits. +def LO16 : SDNodeXForm<imm, [{ + return getImm(N, N->getZExtValue() & 0xFFFF); +}]>; + +// Transformation Function - get the higher 16 bits. +def HI16 : SDNodeXForm<imm, [{ + return getImm(N, (N->getZExtValue() >> 16) & 0xFFFF); +}]>; + +// Plus 1. +def Plus1 : SDNodeXForm<imm, [{ return getImm(N, N->getSExtValue() + 1); }]>; + +// Node immediate fits as 16-bit sign extended on target immediate. +// e.g. addi, andi +def immSExt8 : PatLeaf<(imm), [{ return isInt<8>(N->getSExtValue()); }]>; + +// Node immediate fits as 16-bit sign extended on target immediate. +// e.g. addi, andi +def immSExt16 : PatLeaf<(imm), [{ return isInt<16>(N->getSExtValue()); }]>; + +// Node immediate fits as 15-bit sign extended on target immediate. +// e.g. addi, andi +def immSExt15 : PatLeaf<(imm), [{ return isInt<15>(N->getSExtValue()); }]>; + +// 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), [{ + if (N->getValueType(0) == MVT::i32) + return (uint32_t)N->getZExtValue() == (unsigned short)N->getZExtValue(); + else + return (uint64_t)N->getZExtValue() == (unsigned short)N->getZExtValue(); +}], LO16>; + +// Immediate can be loaded with LUi (32-bit int with lower 16-bit cleared). +def immLow16Zero : PatLeaf<(imm), [{ + int64_t Val = N->getSExtValue(); + return isInt<32>(Val) && !(Val & 0xffff); +}]>; + +// shamt field must fit in 5 bits. +def immZExt5 : ImmLeaf<i32, [{return Imm == (Imm & 0x1f);}]>; + +// True if (N + 1) fits in 16-bit field. +def immSExt16Plus1 : PatLeaf<(imm), [{ + return isInt<17>(N->getSExtValue()) && isInt<16>(N->getSExtValue() + 1); +}]>; + +// Mips Address Mode! SDNode frameindex could possibily be a match +// since load and store instructions from stack used it. +def addr : + ComplexPattern<iPTR, 2, "selectIntAddr", [frameindex]>; + +def addrRegImm : + ComplexPattern<iPTR, 2, "selectAddrRegImm", [frameindex]>; + +def addrRegReg : + ComplexPattern<iPTR, 2, "selectAddrRegReg", [frameindex]>; + +def addrDefault : + ComplexPattern<iPTR, 2, "selectAddrDefault", [frameindex]>; + +//===----------------------------------------------------------------------===// +// Instructions specific format +//===----------------------------------------------------------------------===// + +// Arithmetic and logical instructions with 3 register operands. +class ArithLogicR<string opstr, RegisterOperand RO, bit isComm = 0, + InstrItinClass Itin = NoItinerary, + SDPatternOperator OpNode = null_frag>: + InstSE<(outs RO:$rd), (ins RO:$rs, RO:$rt), + !strconcat(opstr, "\t$rd, $rs, $rt"), + [(set RO:$rd, (OpNode RO:$rs, RO:$rt))], Itin, FrmR, opstr> { + let isCommutable = isComm; + let isReMaterializable = 1; +} + +// Arithmetic and logical instructions with 2 register operands. +class ArithLogicI<string opstr, Operand Od, RegisterOperand RO, + InstrItinClass Itin = NoItinerary, + SDPatternOperator imm_type = null_frag, + SDPatternOperator OpNode = null_frag> : + InstSE<(outs RO:$rt), (ins RO:$rs, Od:$imm16), + !strconcat(opstr, "\t$rt, $rs, $imm16"), + [(set RO:$rt, (OpNode RO:$rs, imm_type:$imm16))], + Itin, FrmI, opstr> { + let isReMaterializable = 1; + let TwoOperandAliasConstraint = "$rs = $rt"; +} + +// Arithmetic Multiply ADD/SUB +class MArithR<string opstr, bit isComm = 0> : + InstSE<(outs), (ins GPR32Opnd:$rs, GPR32Opnd:$rt), + !strconcat(opstr, "\t$rs, $rt"), [], IIImult, FrmR, opstr> { + let Defs = [HI0, LO0]; + let Uses = [HI0, LO0]; + let isCommutable = isComm; +} + +// Logical +class LogicNOR<string opstr, RegisterOperand RO>: + InstSE<(outs RO:$rd), (ins RO:$rs, RO:$rt), + !strconcat(opstr, "\t$rd, $rs, $rt"), + [(set RO:$rd, (not (or RO:$rs, RO:$rt)))], IIArith, FrmR, opstr> { + let isCommutable = 1; +} + +// Shifts +class shift_rotate_imm<string opstr, Operand ImmOpnd, + RegisterOperand RO, SDPatternOperator OpNode = null_frag, + SDPatternOperator PF = null_frag> : + InstSE<(outs RO:$rd), (ins RO:$rt, ImmOpnd:$shamt), + !strconcat(opstr, "\t$rd, $rt, $shamt"), + [(set RO:$rd, (OpNode RO:$rt, PF:$shamt))], IIArith, FrmR, opstr>; + +class shift_rotate_reg<string opstr, RegisterOperand RO, + SDPatternOperator OpNode = null_frag>: + InstSE<(outs RO:$rd), (ins RO:$rt, GPR32Opnd:$rs), + !strconcat(opstr, "\t$rd, $rt, $rs"), + [(set RO:$rd, (OpNode RO:$rt, GPR32Opnd:$rs))], IIArith, FrmR, opstr>; + +// Load Upper Imediate +class LoadUpper<string opstr, RegisterOperand RO, Operand Imm>: + InstSE<(outs RO:$rt), (ins Imm:$imm16), !strconcat(opstr, "\t$rt, $imm16"), + [], IIArith, FrmI, opstr>, IsAsCheapAsAMove { + let neverHasSideEffects = 1; + let isReMaterializable = 1; +} + +// Memory Load/Store +class Load<string opstr, DAGOperand RO, SDPatternOperator OpNode = null_frag, + InstrItinClass Itin = NoItinerary, ComplexPattern Addr = addr> : + InstSE<(outs RO:$rt), (ins mem:$addr), !strconcat(opstr, "\t$rt, $addr"), + [(set RO:$rt, (OpNode Addr:$addr))], Itin, FrmI, opstr> { + let DecoderMethod = "DecodeMem"; + let canFoldAsLoad = 1; + let mayLoad = 1; +} + +class Store<string opstr, DAGOperand RO, SDPatternOperator OpNode = null_frag, + InstrItinClass Itin = NoItinerary, ComplexPattern Addr = addr> : + InstSE<(outs), (ins RO:$rt, mem:$addr), !strconcat(opstr, "\t$rt, $addr"), + [(OpNode RO:$rt, Addr:$addr)], Itin, FrmI, opstr> { + let DecoderMethod = "DecodeMem"; + let mayStore = 1; +} + +// Load/Store Left/Right +let canFoldAsLoad = 1 in +class LoadLeftRight<string opstr, SDNode OpNode, RegisterOperand RO, + InstrItinClass Itin> : + InstSE<(outs RO:$rt), (ins mem:$addr, RO:$src), + !strconcat(opstr, "\t$rt, $addr"), + [(set RO:$rt, (OpNode addr:$addr, RO:$src))], Itin, FrmI> { + let DecoderMethod = "DecodeMem"; + string Constraints = "$src = $rt"; +} + +class StoreLeftRight<string opstr, SDNode OpNode, RegisterOperand RO, + InstrItinClass Itin> : + InstSE<(outs), (ins RO:$rt, mem:$addr), !strconcat(opstr, "\t$rt, $addr"), + [(OpNode RO:$rt, addr:$addr)], Itin, FrmI> { + let DecoderMethod = "DecodeMem"; +} + +// Conditional Branch +class CBranch<string opstr, DAGOperand opnd, PatFrag cond_op, + RegisterOperand RO> : + InstSE<(outs), (ins RO:$rs, RO:$rt, opnd:$offset), + !strconcat(opstr, "\t$rs, $rt, $offset"), + [(brcond (i32 (cond_op RO:$rs, RO:$rt)), bb:$offset)], IIBranch, + FrmI, opstr> { + let isBranch = 1; + let isTerminator = 1; + let hasDelaySlot = 1; + let Defs = [AT]; +} + +class CBranchZero<string opstr, DAGOperand opnd, PatFrag cond_op, + RegisterOperand RO> : + InstSE<(outs), (ins RO:$rs, opnd:$offset), + !strconcat(opstr, "\t$rs, $offset"), + [(brcond (i32 (cond_op RO:$rs, 0)), bb:$offset)], IIBranch, + FrmI, opstr> { + let isBranch = 1; + let isTerminator = 1; + let hasDelaySlot = 1; + let Defs = [AT]; +} + +// SetCC +class SetCC_R<string opstr, PatFrag cond_op, RegisterOperand RO> : + InstSE<(outs GPR32Opnd:$rd), (ins RO:$rs, RO:$rt), + !strconcat(opstr, "\t$rd, $rs, $rt"), + [(set GPR32Opnd:$rd, (cond_op RO:$rs, RO:$rt))], + IIslt, FrmR, opstr>; + +class SetCC_I<string opstr, PatFrag cond_op, Operand Od, PatLeaf imm_type, + RegisterOperand RO>: + InstSE<(outs GPR32Opnd:$rt), (ins RO:$rs, Od:$imm16), + !strconcat(opstr, "\t$rt, $rs, $imm16"), + [(set GPR32Opnd:$rt, (cond_op RO:$rs, imm_type:$imm16))], + IIslt, FrmI, opstr>; + +// Jump +class JumpFJ<DAGOperand opnd, string opstr, SDPatternOperator operator, + SDPatternOperator targetoperator, string bopstr> : + InstSE<(outs), (ins opnd:$target), !strconcat(opstr, "\t$target"), + [(operator targetoperator:$target)], IIBranch, FrmJ, bopstr> { + let isTerminator=1; + let isBarrier=1; + let hasDelaySlot = 1; + let DecoderMethod = "DecodeJumpTarget"; + let Defs = [AT]; +} + +// Unconditional branch +class UncondBranch<Instruction BEQInst> : + PseudoSE<(outs), (ins brtarget:$offset), [(br bb:$offset)], IIBranch>, + PseudoInstExpansion<(BEQInst ZERO, ZERO, brtarget:$offset)> { + let isBranch = 1; + let isTerminator = 1; + let isBarrier = 1; + let hasDelaySlot = 1; + let Predicates = [RelocPIC, HasStdEnc]; + let Defs = [AT]; +} + +// Base class for indirect branch and return instruction classes. +let isTerminator=1, isBarrier=1, hasDelaySlot = 1 in +class JumpFR<string opstr, RegisterOperand RO, + SDPatternOperator operator = null_frag>: + InstSE<(outs), (ins RO:$rs), "jr\t$rs", [(operator RO:$rs)], IIBranch, + FrmR, opstr>; + +// Indirect branch +class IndirectBranch<string opstr, RegisterOperand RO> : + JumpFR<opstr, RO, brind> { + let isBranch = 1; + let isIndirectBranch = 1; +} + +// Return instruction +class RetBase<string opstr, RegisterOperand RO>: JumpFR<opstr, RO> { + let isReturn = 1; + let isCodeGenOnly = 1; + let hasCtrlDep = 1; + let hasExtraSrcRegAllocReq = 1; +} + +// Jump and Link (Call) +let isCall=1, hasDelaySlot=1, Defs = [RA] in { + class JumpLink<string opstr, DAGOperand opnd> : + InstSE<(outs), (ins opnd:$target), !strconcat(opstr, "\t$target"), + [(MipsJmpLink imm:$target)], IIBranch, FrmJ, opstr> { + let DecoderMethod = "DecodeJumpTarget"; + } + + class JumpLinkRegPseudo<RegisterOperand RO, Instruction JALRInst, + Register RetReg, RegisterOperand ResRO = RO>: + PseudoSE<(outs), (ins RO:$rs), [(MipsJmpLink RO:$rs)], IIBranch>, + PseudoInstExpansion<(JALRInst RetReg, ResRO:$rs)>; + + class JumpLinkReg<string opstr, RegisterOperand RO>: + InstSE<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"), + [], IIBranch, FrmR, opstr>; + + class BGEZAL_FT<string opstr, DAGOperand opnd, RegisterOperand RO> : + InstSE<(outs), (ins RO:$rs, opnd:$offset), + !strconcat(opstr, "\t$rs, $offset"), [], IIBranch, FrmI, opstr>; + +} + +class BAL_BR_Pseudo<Instruction RealInst> : + PseudoSE<(outs), (ins brtarget:$offset), [], IIBranch>, + PseudoInstExpansion<(RealInst ZERO, brtarget:$offset)> { + let isBranch = 1; + let isTerminator = 1; + let isBarrier = 1; + let hasDelaySlot = 1; + let Defs = [RA]; +} + +// Syscall +class SYS_FT<string opstr> : + InstSE<(outs), (ins uimm20:$code_), + !strconcat(opstr, "\t$code_"), [], NoItinerary, FrmI>; +// Break +class BRK_FT<string opstr> : + InstSE<(outs), (ins uimm10:$code_1, uimm10:$code_2), + !strconcat(opstr, "\t$code_1, $code_2"), [], NoItinerary, FrmOther>; + +// (D)Eret +class ER_FT<string opstr> : + InstSE<(outs), (ins), + opstr, [], NoItinerary, FrmOther>; + +// Interrupts +class DEI_FT<string opstr, RegisterOperand RO> : + InstSE<(outs RO:$rt), (ins), + !strconcat(opstr, "\t$rt"), [], NoItinerary, FrmOther>; + +// Wait +class WAIT_FT<string opstr> : + InstSE<(outs), (ins), opstr, [], NoItinerary, FrmOther> { + let Inst{31-26} = 0x10; + let Inst{25} = 1; + let Inst{24-6} = 0; + let Inst{5-0} = 0x20; +} + +// Sync +let hasSideEffects = 1 in +class SYNC_FT : + InstSE<(outs), (ins i32imm:$stype), "sync $stype", [(MipsSync imm:$stype)], + NoItinerary, FrmOther>; + +let hasSideEffects = 1 in +class TEQ_FT<string opstr, RegisterOperand RO> : + InstSE<(outs), (ins RO:$rs, RO:$rt, uimm16:$code_), + !strconcat(opstr, "\t$rs, $rt, $code_"), [], NoItinerary, + FrmI, opstr>; + +class TEQI_FT<string opstr, RegisterOperand RO> : + InstSE<(outs), (ins RO:$rs, uimm16:$imm16), + !strconcat(opstr, "\t$rs, $imm16"), [], NoItinerary, FrmOther, opstr>; +// Mul, Div +class Mult<string opstr, InstrItinClass itin, RegisterOperand RO, + list<Register> DefRegs> : + InstSE<(outs), (ins RO:$rs, RO:$rt), !strconcat(opstr, "\t$rs, $rt"), [], + itin, FrmR, opstr> { + let isCommutable = 1; + let Defs = DefRegs; + let neverHasSideEffects = 1; +} + +// Pseudo multiply/divide instruction with explicit accumulator register +// operands. +class MultDivPseudo<Instruction RealInst, RegisterClass R0, RegisterOperand R1, + SDPatternOperator OpNode, InstrItinClass Itin, + bit IsComm = 1, bit HasSideEffects = 0, + bit UsesCustomInserter = 0> : + PseudoSE<(outs R0:$ac), (ins R1:$rs, R1:$rt), + [(set R0:$ac, (OpNode R1:$rs, R1:$rt))], Itin>, + PseudoInstExpansion<(RealInst R1:$rs, R1:$rt)> { + let isCommutable = IsComm; + let hasSideEffects = HasSideEffects; + let usesCustomInserter = UsesCustomInserter; +} + +// Pseudo multiply add/sub instruction with explicit accumulator register +// operands. +class MAddSubPseudo<Instruction RealInst, SDPatternOperator OpNode> + : PseudoSE<(outs ACC64:$ac), + (ins GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64:$acin), + [(set ACC64:$ac, + (OpNode GPR32Opnd:$rs, GPR32Opnd:$rt, ACC64:$acin))], + IIImult>, + PseudoInstExpansion<(RealInst GPR32Opnd:$rs, GPR32Opnd:$rt)> { + string Constraints = "$acin = $ac"; +} + +class Div<string opstr, InstrItinClass itin, RegisterOperand RO, + list<Register> DefRegs> : + InstSE<(outs), (ins RO:$rs, RO:$rt), !strconcat(opstr, "\t$$zero, $rs, $rt"), + [], itin, FrmR, opstr> { + let Defs = DefRegs; +} + +// Move from Hi/Lo +class PseudoMFLOHI<RegisterClass DstRC, RegisterClass SrcRC, SDNode OpNode> + : PseudoSE<(outs DstRC:$rd), (ins SrcRC:$hilo), + [(set DstRC:$rd, (OpNode SrcRC:$hilo))], IIHiLo>; + +class MoveFromLOHI<string opstr, RegisterOperand RO, Register UseReg>: + InstSE<(outs RO:$rd), (ins), !strconcat(opstr, "\t$rd"), [], IIHiLo, FrmR, + opstr> { + let Uses = [UseReg]; + let neverHasSideEffects = 1; +} + +class PseudoMTLOHI<RegisterClass DstRC, RegisterClass SrcRC> + : PseudoSE<(outs DstRC:$lohi), (ins SrcRC:$lo, SrcRC:$hi), + [(set DstRC:$lohi, (MipsMTLOHI SrcRC:$lo, SrcRC:$hi))], IIHiLo>; + +class MoveToLOHI<string opstr, RegisterOperand RO, list<Register> DefRegs>: + InstSE<(outs), (ins RO:$rs), !strconcat(opstr, "\t$rs"), [], IIHiLo, + FrmR, opstr> { + let Defs = DefRegs; + let neverHasSideEffects = 1; +} + +class EffectiveAddress<string opstr, RegisterOperand RO> : + InstSE<(outs RO:$rt), (ins mem_ea:$addr), !strconcat(opstr, "\t$rt, $addr"), + [(set RO:$rt, addr:$addr)], NoItinerary, FrmI> { + let isCodeGenOnly = 1; + let DecoderMethod = "DecodeMem"; +} + +// Count Leading Ones/Zeros in Word +class CountLeading0<string opstr, RegisterOperand RO>: + InstSE<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"), + [(set RO:$rd, (ctlz RO:$rs))], IIArith, FrmR, opstr>, + Requires<[HasBitCount, HasStdEnc]>; + +class CountLeading1<string opstr, RegisterOperand RO>: + InstSE<(outs RO:$rd), (ins RO:$rs), !strconcat(opstr, "\t$rd, $rs"), + [(set RO:$rd, (ctlz (not RO:$rs)))], IIArith, FrmR, opstr>, + Requires<[HasBitCount, HasStdEnc]>; + + +// Sign Extend in Register. +class SignExtInReg<string opstr, ValueType vt, RegisterOperand RO> : + InstSE<(outs RO:$rd), (ins RO:$rt), !strconcat(opstr, "\t$rd, $rt"), + [(set RO:$rd, (sext_inreg RO:$rt, vt))], IIseb, FrmR, opstr> { + let Predicates = [HasSEInReg, HasStdEnc]; +} + +// Subword Swap +class SubwordSwap<string opstr, RegisterOperand RO>: + InstSE<(outs RO:$rd), (ins RO:$rt), !strconcat(opstr, "\t$rd, $rt"), [], + NoItinerary, FrmR, opstr> { + let Predicates = [HasSwap, HasStdEnc]; + let neverHasSideEffects = 1; +} + +// Read Hardware +class ReadHardware<RegisterOperand CPURegOperand, RegisterOperand RO> : + InstSE<(outs CPURegOperand:$rt), (ins RO:$rd), "rdhwr\t$rt, $rd", [], + IIArith, FrmR>; + +// Ext and Ins +class ExtBase<string opstr, RegisterOperand RO, Operand PosOpnd, + SDPatternOperator Op = null_frag>: + InstSE<(outs RO:$rt), (ins RO:$rs, PosOpnd:$pos, size_ext:$size), + !strconcat(opstr, " $rt, $rs, $pos, $size"), + [(set RO:$rt, (Op RO:$rs, imm:$pos, imm:$size))], NoItinerary, + FrmR, opstr> { + let Predicates = [HasMips32r2, HasStdEnc]; +} + +class InsBase<string opstr, RegisterOperand RO, Operand PosOpnd, + SDPatternOperator Op = null_frag>: + InstSE<(outs RO:$rt), (ins RO:$rs, PosOpnd:$pos, size_ins:$size, RO:$src), + !strconcat(opstr, " $rt, $rs, $pos, $size"), + [(set RO:$rt, (Op RO:$rs, imm:$pos, imm:$size, RO:$src))], + NoItinerary, FrmR, opstr> { + let Predicates = [HasMips32r2, HasStdEnc]; + let Constraints = "$src = $rt"; +} + +// Atomic instructions with 2 source operands (ATOMIC_SWAP & ATOMIC_LOAD_*). +class Atomic2Ops<PatFrag Op, RegisterClass DRC> : + PseudoSE<(outs DRC:$dst), (ins PtrRC:$ptr, DRC:$incr), + [(set DRC:$dst, (Op iPTR:$ptr, DRC:$incr))]>; + +// Atomic Compare & Swap. +class AtomicCmpSwap<PatFrag Op, RegisterClass DRC> : + PseudoSE<(outs DRC:$dst), (ins PtrRC:$ptr, DRC:$cmp, DRC:$swap), + [(set DRC:$dst, (Op iPTR:$ptr, DRC:$cmp, DRC:$swap))]>; + +class LLBase<string opstr, RegisterOperand RO> : + InstSE<(outs RO:$rt), (ins mem:$addr), !strconcat(opstr, "\t$rt, $addr"), + [], NoItinerary, FrmI> { + let DecoderMethod = "DecodeMem"; + let mayLoad = 1; +} + +class SCBase<string opstr, RegisterOperand RO> : + InstSE<(outs RO:$dst), (ins RO:$rt, mem:$addr), + !strconcat(opstr, "\t$rt, $addr"), [], NoItinerary, FrmI> { + let DecoderMethod = "DecodeMem"; + let mayStore = 1; + let Constraints = "$rt = $dst"; +} + +class MFC3OP<string asmstr, RegisterOperand RO> : + InstSE<(outs RO:$rt, RO:$rd, uimm16:$sel), (ins), + !strconcat(asmstr, "\t$rt, $rd, $sel"), [], NoItinerary, FrmFR>; + +class TrapBase<Instruction RealInst> + : PseudoSE<(outs), (ins), [(trap)], NoItinerary>, + PseudoInstExpansion<(RealInst 0, 0)> { + let isBarrier = 1; + let isTerminator = 1; + let isCodeGenOnly = 1; +} + +//===----------------------------------------------------------------------===// +// Pseudo instructions +//===----------------------------------------------------------------------===// + +// Return RA. +let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, hasCtrlDep=1 in +def RetRA : PseudoSE<(outs), (ins), [(MipsRet)]>; + +let Defs = [SP], Uses = [SP], hasSideEffects = 1 in { +def ADJCALLSTACKDOWN : MipsPseudo<(outs), (ins i32imm:$amt), + [(callseq_start timm:$amt)]>; +def ADJCALLSTACKUP : MipsPseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), + [(callseq_end timm:$amt1, timm:$amt2)]>; +} + +let usesCustomInserter = 1 in { + def ATOMIC_LOAD_ADD_I8 : Atomic2Ops<atomic_load_add_8, GPR32>; + def ATOMIC_LOAD_ADD_I16 : Atomic2Ops<atomic_load_add_16, GPR32>; + def ATOMIC_LOAD_ADD_I32 : Atomic2Ops<atomic_load_add_32, GPR32>; + def ATOMIC_LOAD_SUB_I8 : Atomic2Ops<atomic_load_sub_8, GPR32>; + def ATOMIC_LOAD_SUB_I16 : Atomic2Ops<atomic_load_sub_16, GPR32>; + def ATOMIC_LOAD_SUB_I32 : Atomic2Ops<atomic_load_sub_32, GPR32>; + def ATOMIC_LOAD_AND_I8 : Atomic2Ops<atomic_load_and_8, GPR32>; + def ATOMIC_LOAD_AND_I16 : Atomic2Ops<atomic_load_and_16, GPR32>; + def ATOMIC_LOAD_AND_I32 : Atomic2Ops<atomic_load_and_32, GPR32>; + def ATOMIC_LOAD_OR_I8 : Atomic2Ops<atomic_load_or_8, GPR32>; + def ATOMIC_LOAD_OR_I16 : Atomic2Ops<atomic_load_or_16, GPR32>; + def ATOMIC_LOAD_OR_I32 : Atomic2Ops<atomic_load_or_32, GPR32>; + def ATOMIC_LOAD_XOR_I8 : Atomic2Ops<atomic_load_xor_8, GPR32>; + def ATOMIC_LOAD_XOR_I16 : Atomic2Ops<atomic_load_xor_16, GPR32>; + def ATOMIC_LOAD_XOR_I32 : Atomic2Ops<atomic_load_xor_32, GPR32>; + def ATOMIC_LOAD_NAND_I8 : Atomic2Ops<atomic_load_nand_8, GPR32>; + def ATOMIC_LOAD_NAND_I16 : Atomic2Ops<atomic_load_nand_16, GPR32>; + def ATOMIC_LOAD_NAND_I32 : Atomic2Ops<atomic_load_nand_32, GPR32>; + + def ATOMIC_SWAP_I8 : Atomic2Ops<atomic_swap_8, GPR32>; + def ATOMIC_SWAP_I16 : Atomic2Ops<atomic_swap_16, GPR32>; + def ATOMIC_SWAP_I32 : Atomic2Ops<atomic_swap_32, GPR32>; + + def ATOMIC_CMP_SWAP_I8 : AtomicCmpSwap<atomic_cmp_swap_8, GPR32>; + def ATOMIC_CMP_SWAP_I16 : AtomicCmpSwap<atomic_cmp_swap_16, GPR32>; + def ATOMIC_CMP_SWAP_I32 : AtomicCmpSwap<atomic_cmp_swap_32, GPR32>; +} + +/// Pseudo instructions for loading and storing accumulator registers. +let isPseudo = 1, isCodeGenOnly = 1 in { + def LOAD_ACC64 : Load<"", ACC64>; + def STORE_ACC64 : Store<"", ACC64>; +} + +//===----------------------------------------------------------------------===// +// Instruction definition +//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// +// MipsI Instructions +//===----------------------------------------------------------------------===// + +/// Arithmetic Instructions (ALU Immediate) +def ADDiu : MMRel, ArithLogicI<"addiu", simm16, GPR32Opnd, IIArith, immSExt16, + add>, + ADDI_FM<0x9>, IsAsCheapAsAMove; +def ADDi : MMRel, ArithLogicI<"addi", simm16, GPR32Opnd>, ADDI_FM<0x8>; +def SLTi : MMRel, SetCC_I<"slti", setlt, simm16, immSExt16, GPR32Opnd>, + SLTI_FM<0xa>; +def SLTiu : MMRel, SetCC_I<"sltiu", setult, simm16, immSExt16, GPR32Opnd>, + SLTI_FM<0xb>; +def ANDi : MMRel, ArithLogicI<"andi", uimm16, GPR32Opnd, IILogic, immZExt16, + and>, + ADDI_FM<0xc>; +def ORi : MMRel, ArithLogicI<"ori", uimm16, GPR32Opnd, IILogic, immZExt16, + or>, + ADDI_FM<0xd>; +def XORi : MMRel, ArithLogicI<"xori", uimm16, GPR32Opnd, IILogic, immZExt16, + xor>, + ADDI_FM<0xe>; +def LUi : MMRel, LoadUpper<"lui", GPR32Opnd, uimm16>, LUI_FM; + +/// Arithmetic Instructions (3-Operand, R-Type) +def ADDu : MMRel, ArithLogicR<"addu", GPR32Opnd, 1, IIArith, add>, + ADD_FM<0, 0x21>; +def SUBu : MMRel, ArithLogicR<"subu", GPR32Opnd, 0, IIArith, sub>, + ADD_FM<0, 0x23>; +let Defs = [HI0, LO0] in +def MUL : MMRel, ArithLogicR<"mul", GPR32Opnd, 1, IIImul, mul>, + ADD_FM<0x1c, 2>; +def ADD : MMRel, ArithLogicR<"add", GPR32Opnd>, ADD_FM<0, 0x20>; +def SUB : MMRel, ArithLogicR<"sub", GPR32Opnd>, ADD_FM<0, 0x22>; +def SLT : MMRel, SetCC_R<"slt", setlt, GPR32Opnd>, ADD_FM<0, 0x2a>; +def SLTu : MMRel, SetCC_R<"sltu", setult, GPR32Opnd>, ADD_FM<0, 0x2b>; +def AND : MMRel, ArithLogicR<"and", GPR32Opnd, 1, IILogic, and>, + ADD_FM<0, 0x24>; +def OR : MMRel, ArithLogicR<"or", GPR32Opnd, 1, IILogic, or>, + ADD_FM<0, 0x25>; +def XOR : MMRel, ArithLogicR<"xor", GPR32Opnd, 1, IILogic, xor>, + ADD_FM<0, 0x26>; +def NOR : MMRel, LogicNOR<"nor", GPR32Opnd>, ADD_FM<0, 0x27>; + +/// Shift Instructions +def SLL : MMRel, shift_rotate_imm<"sll", uimm5, GPR32Opnd, shl, immZExt5>, + SRA_FM<0, 0>; +def SRL : MMRel, shift_rotate_imm<"srl", uimm5, GPR32Opnd, srl, immZExt5>, + SRA_FM<2, 0>; +def SRA : MMRel, shift_rotate_imm<"sra", uimm5, GPR32Opnd, sra, immZExt5>, + SRA_FM<3, 0>; +def SLLV : MMRel, shift_rotate_reg<"sllv", GPR32Opnd, shl>, SRLV_FM<4, 0>; +def SRLV : MMRel, shift_rotate_reg<"srlv", GPR32Opnd, srl>, SRLV_FM<6, 0>; +def SRAV : MMRel, shift_rotate_reg<"srav", GPR32Opnd, sra>, SRLV_FM<7, 0>; + +// Rotate Instructions +let Predicates = [HasMips32r2, HasStdEnc] in { + def ROTR : MMRel, shift_rotate_imm<"rotr", uimm5, GPR32Opnd, rotr, + immZExt5>, + SRA_FM<2, 1>; + def ROTRV : MMRel, shift_rotate_reg<"rotrv", GPR32Opnd, rotr>, + SRLV_FM<6, 1>; +} + +/// Load and Store Instructions +/// aligned +def LB : Load<"lb", GPR32Opnd, sextloadi8, IILoad>, MMRel, LW_FM<0x20>; +def LBu : Load<"lbu", GPR32Opnd, zextloadi8, IILoad, addrDefault>, MMRel, + LW_FM<0x24>; +def LH : Load<"lh", GPR32Opnd, sextloadi16, IILoad, addrDefault>, MMRel, + LW_FM<0x21>; +def LHu : Load<"lhu", GPR32Opnd, zextloadi16, IILoad>, MMRel, LW_FM<0x25>; +def LW : Load<"lw", GPR32Opnd, load, IILoad, addrDefault>, MMRel, + LW_FM<0x23>; +def SB : Store<"sb", GPR32Opnd, truncstorei8, IIStore>, MMRel, LW_FM<0x28>; +def SH : Store<"sh", GPR32Opnd, truncstorei16, IIStore>, MMRel, LW_FM<0x29>; +def SW : Store<"sw", GPR32Opnd, store, IIStore>, MMRel, LW_FM<0x2b>; + +/// load/store left/right +let Predicates = [NotInMicroMips] in { +def LWL : LoadLeftRight<"lwl", MipsLWL, GPR32Opnd, IILoad>, LW_FM<0x22>; +def LWR : LoadLeftRight<"lwr", MipsLWR, GPR32Opnd, IILoad>, LW_FM<0x26>; +def SWL : StoreLeftRight<"swl", MipsSWL, GPR32Opnd, IIStore>, LW_FM<0x2a>; +def SWR : StoreLeftRight<"swr", MipsSWR, GPR32Opnd, IIStore>, LW_FM<0x2e>; +} + +def SYNC : SYNC_FT, SYNC_FM; +def TEQ : MMRel, TEQ_FT<"teq", GPR32Opnd>, TEQ_FM<0x34>; +def TGE : MMRel, TEQ_FT<"tge", GPR32Opnd>, TEQ_FM<0x30>; +def TGEU : MMRel, TEQ_FT<"tgeu", GPR32Opnd>, TEQ_FM<0x31>; +def TLT : MMRel, TEQ_FT<"tlt", GPR32Opnd>, TEQ_FM<0x32>; +def TLTU : MMRel, TEQ_FT<"tltu", GPR32Opnd>, TEQ_FM<0x33>; +def TNE : MMRel, TEQ_FT<"tne", GPR32Opnd>, TEQ_FM<0x36>; + +def TEQI : MMRel, TEQI_FT<"teqi", GPR32Opnd>, TEQI_FM<0xc>; +def TGEI : MMRel, TEQI_FT<"tgei", GPR32Opnd>, TEQI_FM<0x8>; +def TGEIU : MMRel, TEQI_FT<"tgeiu", GPR32Opnd>, TEQI_FM<0x9>; +def TLTI : MMRel, TEQI_FT<"tlti", GPR32Opnd>, TEQI_FM<0xa>; +def TTLTIU : MMRel, TEQI_FT<"tltiu", GPR32Opnd>, TEQI_FM<0xb>; +def TNEI : MMRel, TEQI_FT<"tnei", GPR32Opnd>, TEQI_FM<0xe>; + +def BREAK : BRK_FT<"break">, BRK_FM<0xd>; +def SYSCALL : SYS_FT<"syscall">, SYS_FM<0xc>; +def TRAP : TrapBase<BREAK>; + +def ERET : ER_FT<"eret">, ER_FM<0x18>; +def DERET : ER_FT<"deret">, ER_FM<0x1f>; + +def EI : DEI_FT<"ei", GPR32Opnd>, EI_FM<1>; +def DI : DEI_FT<"di", GPR32Opnd>, EI_FM<0>; + +def WAIT : WAIT_FT<"wait">; + +/// Load-linked, Store-conditional +def LL : LLBase<"ll", GPR32Opnd>, LW_FM<0x30>; +def SC : SCBase<"sc", GPR32Opnd>, LW_FM<0x38>; + +/// Jump and Branch Instructions +def J : MMRel, JumpFJ<jmptarget, "j", br, bb, "j">, FJ<2>, + Requires<[RelocStatic, HasStdEnc]>, IsBranch; +def JR : MMRel, IndirectBranch<"jr", GPR32Opnd>, MTLO_FM<8>; +def BEQ : MMRel, CBranch<"beq", brtarget, seteq, GPR32Opnd>, BEQ_FM<4>; +def BNE : MMRel, CBranch<"bne", brtarget, setne, GPR32Opnd>, BEQ_FM<5>; +def BGEZ : MMRel, CBranchZero<"bgez", brtarget, setge, GPR32Opnd>, + BGEZ_FM<1, 1>; +def BGTZ : MMRel, CBranchZero<"bgtz", brtarget, setgt, GPR32Opnd>, + BGEZ_FM<7, 0>; +def BLEZ : MMRel, CBranchZero<"blez", brtarget, setle, GPR32Opnd>, + BGEZ_FM<6, 0>; +def BLTZ : MMRel, CBranchZero<"bltz", brtarget, setlt, GPR32Opnd>, + BGEZ_FM<1, 0>; +def B : UncondBranch<BEQ>; + +def JAL : MMRel, JumpLink<"jal", calltarget>, FJ<3>; +def JALR : MMRel, JumpLinkReg<"jalr", GPR32Opnd>, JALR_FM; +def JALRPseudo : JumpLinkRegPseudo<GPR32Opnd, JALR, RA>; +def BGEZAL : MMRel, BGEZAL_FT<"bgezal", brtarget, GPR32Opnd>, BGEZAL_FM<0x11>; +def BLTZAL : MMRel, BGEZAL_FT<"bltzal", brtarget, GPR32Opnd>, BGEZAL_FM<0x10>; +def BAL_BR : BAL_BR_Pseudo<BGEZAL>; +def TAILCALL : MMRel, JumpFJ<calltarget, "j", MipsTailCall, imm, "tcall">, + FJ<2>, IsTailCall; +def TAILCALL_R : MMRel, JumpFR<"tcallr", GPR32Opnd, MipsTailCall>, MTLO_FM<8>, + IsTailCall; + +def RET : MMRel, RetBase<"ret", GPR32Opnd>, MTLO_FM<8>; + +// Exception handling related node and instructions. +// The conversion sequence is: +// ISD::EH_RETURN -> MipsISD::EH_RETURN -> +// MIPSeh_return -> (stack change + indirect branch) +// +// MIPSeh_return takes the place of regular return instruction +// but takes two arguments (V1, V0) which are used for storing +// the offset and return address respectively. +def SDT_MipsEHRET : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisPtrTy<1>]>; + +def MIPSehret : SDNode<"MipsISD::EH_RETURN", SDT_MipsEHRET, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + +let Uses = [V0, V1], isTerminator = 1, isReturn = 1, isBarrier = 1 in { + def MIPSeh_return32 : MipsPseudo<(outs), (ins GPR32:$spoff, GPR32:$dst), + [(MIPSehret GPR32:$spoff, GPR32:$dst)]>; + def MIPSeh_return64 : MipsPseudo<(outs), (ins GPR64:$spoff, + GPR64:$dst), + [(MIPSehret GPR64:$spoff, GPR64:$dst)]>; +} + +/// Multiply and Divide Instructions. +def MULT : MMRel, Mult<"mult", IIImult, GPR32Opnd, [HI0, LO0]>, + MULT_FM<0, 0x18>; +def MULTu : MMRel, Mult<"multu", IIImult, GPR32Opnd, [HI0, LO0]>, + MULT_FM<0, 0x19>; +def SDIV : MMRel, Div<"div", IIIdiv, GPR32Opnd, [HI0, LO0]>, + MULT_FM<0, 0x1a>; +def UDIV : MMRel, Div<"divu", IIIdiv, GPR32Opnd, [HI0, LO0]>, + MULT_FM<0, 0x1b>; + +def MTHI : MMRel, MoveToLOHI<"mthi", GPR32Opnd, [HI0]>, MTLO_FM<0x11>; +def MTLO : MMRel, MoveToLOHI<"mtlo", GPR32Opnd, [LO0]>, MTLO_FM<0x13>; +def MFHI : MMRel, MoveFromLOHI<"mfhi", GPR32Opnd, AC0>, MFLO_FM<0x10>; +def MFLO : MMRel, MoveFromLOHI<"mflo", GPR32Opnd, AC0>, MFLO_FM<0x12>; + +/// Sign Ext In Register Instructions. +def SEB : MMRel, SignExtInReg<"seb", i8, GPR32Opnd>, SEB_FM<0x10, 0x20>; +def SEH : MMRel, SignExtInReg<"seh", i16, GPR32Opnd>, SEB_FM<0x18, 0x20>; + +/// Count Leading +def CLZ : MMRel, CountLeading0<"clz", GPR32Opnd>, CLO_FM<0x20>; +def CLO : MMRel, CountLeading1<"clo", GPR32Opnd>, CLO_FM<0x21>; + +/// Word Swap Bytes Within Halfwords +def WSBH : MMRel, SubwordSwap<"wsbh", GPR32Opnd>, SEB_FM<2, 0x20>; + +/// No operation. +def NOP : PseudoSE<(outs), (ins), []>, PseudoInstExpansion<(SLL ZERO, ZERO, 0)>; + +// FrameIndexes are legalized when they are operands from load/store +// instructions. The same not happens for stack address copies, so an +// add op with mem ComplexPattern is used and the stack address copy +// can be matched. It's similar to Sparc LEA_ADDRi +def LEA_ADDiu : EffectiveAddress<"addiu", GPR32Opnd>, LW_FM<9>; + +// MADD*/MSUB* +def MADD : MMRel, MArithR<"madd", 1>, MULT_FM<0x1c, 0>; +def MADDU : MMRel, MArithR<"maddu", 1>, MULT_FM<0x1c, 1>; +def MSUB : MMRel, MArithR<"msub">, MULT_FM<0x1c, 4>; +def MSUBU : MMRel, MArithR<"msubu">, MULT_FM<0x1c, 5>; + +let Predicates = [HasStdEnc, NotDSP] in { +def PseudoMULT : MultDivPseudo<MULT, ACC64, GPR32Opnd, MipsMult, IIImult>; +def PseudoMULTu : MultDivPseudo<MULTu, ACC64, GPR32Opnd, MipsMultu, IIImult>; +def PseudoMFHI : PseudoMFLOHI<GPR32, ACC64, MipsMFHI>; +def PseudoMFLO : PseudoMFLOHI<GPR32, ACC64, MipsMFLO>; +def PseudoMTLOHI : PseudoMTLOHI<ACC64, GPR32>; +def PseudoMADD : MAddSubPseudo<MADD, MipsMAdd>; +def PseudoMADDU : MAddSubPseudo<MADDU, MipsMAddu>; +def PseudoMSUB : MAddSubPseudo<MSUB, MipsMSub>; +def PseudoMSUBU : MAddSubPseudo<MSUBU, MipsMSubu>; +} + +def PseudoSDIV : MultDivPseudo<SDIV, ACC64, GPR32Opnd, MipsDivRem, IIIdiv, + 0, 1, 1>; +def PseudoUDIV : MultDivPseudo<UDIV, ACC64, GPR32Opnd, MipsDivRemU, IIIdiv, + 0, 1, 1>; + +def RDHWR : ReadHardware<GPR32Opnd, HWRegsOpnd>, RDHWR_FM; + +def EXT : MMRel, ExtBase<"ext", GPR32Opnd, uimm5, MipsExt>, EXT_FM<0>; +def INS : MMRel, InsBase<"ins", GPR32Opnd, uimm5, MipsIns>, EXT_FM<4>; + +/// Move Control Registers From/To CPU Registers +def MFC0 : MFC3OP<"mfc0", GPR32Opnd>, MFC3OP_FM<0x10, 0>; +def MTC0 : MFC3OP<"mtc0", GPR32Opnd>, MFC3OP_FM<0x10, 4>; +def MFC2 : MFC3OP<"mfc2", GPR32Opnd>, MFC3OP_FM<0x12, 0>; +def MTC2 : MFC3OP<"mtc2", GPR32Opnd>, MFC3OP_FM<0x12, 4>; + +//===----------------------------------------------------------------------===// +// Instruction aliases +//===----------------------------------------------------------------------===// +def : InstAlias<"move $dst, $src", + (ADDu GPR32Opnd:$dst, GPR32Opnd:$src,ZERO), 1>, + Requires<[NotMips64]>; +def : InstAlias<"bal $offset", (BGEZAL ZERO, brtarget:$offset), 0>; +def : InstAlias<"addu $rs, $rt, $imm", + (ADDiu GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; +def : InstAlias<"add $rs, $rt, $imm", + (ADDi GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; +def : InstAlias<"and $rs, $rt, $imm", + (ANDi GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; +def : InstAlias<"j $rs", (JR GPR32Opnd:$rs), 0>; +def : InstAlias<"jalr $rs", (JALR RA, GPR32Opnd:$rs), 0>; +def : InstAlias<"jal $rs", (JALR RA, GPR32Opnd:$rs), 0>; +def : InstAlias<"jal $rd,$rs", (JALR GPR32Opnd:$rd, GPR32Opnd:$rs), 0>; +def : InstAlias<"not $rt, $rs", + (NOR GPR32Opnd:$rt, GPR32Opnd:$rs, ZERO), 0>; +def : InstAlias<"neg $rt, $rs", + (SUB GPR32Opnd:$rt, ZERO, GPR32Opnd:$rs), 1>; +def : InstAlias<"negu $rt, $rs", + (SUBu GPR32Opnd:$rt, ZERO, GPR32Opnd:$rs), 1>; +def : InstAlias<"slt $rs, $rt, $imm", + (SLTi GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm), 0>; +def : InstAlias<"xor $rs, $rt, $imm", + (XORi GPR32Opnd:$rs, GPR32Opnd:$rt, uimm16:$imm), 0>; +def : InstAlias<"or $rs, $rt, $imm", + (ORi GPR32Opnd:$rs, GPR32Opnd:$rt, uimm16:$imm), 0>; +def : InstAlias<"nop", (SLL ZERO, ZERO, 0), 1>; +def : InstAlias<"mfc0 $rt, $rd", (MFC0 GPR32Opnd:$rt, GPR32Opnd:$rd, 0), 0>; +def : InstAlias<"mtc0 $rt, $rd", (MTC0 GPR32Opnd:$rt, GPR32Opnd:$rd, 0), 0>; +def : InstAlias<"mfc2 $rt, $rd", (MFC2 GPR32Opnd:$rt, GPR32Opnd:$rd, 0), 0>; +def : InstAlias<"mtc2 $rt, $rd", (MTC2 GPR32Opnd:$rt, GPR32Opnd:$rd, 0), 0>; +def : InstAlias<"b $offset", (BEQ ZERO, ZERO, brtarget:$offset), 0>; +def : InstAlias<"bnez $rs,$offset", + (BNE GPR32Opnd:$rs, ZERO, brtarget:$offset), 0>; +def : InstAlias<"beqz $rs,$offset", + (BEQ GPR32Opnd:$rs, ZERO, brtarget:$offset), 0>; +def : InstAlias<"syscall", (SYSCALL 0), 1>; + +def : InstAlias<"break $imm", (BREAK uimm10:$imm, 0), 1>; +def : InstAlias<"break", (BREAK 0, 0), 1>; +def : InstAlias<"ei", (EI ZERO), 1>; +def : InstAlias<"di", (DI ZERO), 1>; + +def : InstAlias<"teq $rs, $rt", (TEQ GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : InstAlias<"tge $rs, $rt", (TGE GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : InstAlias<"tgeu $rs, $rt", (TGEU GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : InstAlias<"tlt $rs, $rt", (TLT GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : InstAlias<"tltu $rs, $rt", (TLTU GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : InstAlias<"tne $rs, $rt", (TNE GPR32Opnd:$rs, GPR32Opnd:$rt, 0), 1>; +def : InstAlias<"sub, $rd, $rs, $imm", + (ADDi GPR32Opnd:$rd, GPR32Opnd:$rs, InvertedImOperand:$imm)>; +def : InstAlias<"subu, $rd, $rs, $imm", + (ADDiu GPR32Opnd:$rd, GPR32Opnd:$rs, InvertedImOperand:$imm)>; + +//===----------------------------------------------------------------------===// +// Assembler Pseudo Instructions +//===----------------------------------------------------------------------===// + +class LoadImm32< string instr_asm, Operand Od, RegisterOperand RO> : + MipsAsmPseudoInst<(outs RO:$rt), (ins Od:$imm32), + !strconcat(instr_asm, "\t$rt, $imm32")> ; +def LoadImm32Reg : LoadImm32<"li", uimm5, GPR32Opnd>; + +class LoadAddress<string instr_asm, Operand MemOpnd, RegisterOperand RO> : + MipsAsmPseudoInst<(outs RO:$rt), (ins MemOpnd:$addr), + !strconcat(instr_asm, "\t$rt, $addr")> ; +def LoadAddr32Reg : LoadAddress<"la", mem, GPR32Opnd>; + +class LoadAddressImm<string instr_asm, Operand Od, RegisterOperand RO> : + MipsAsmPseudoInst<(outs RO:$rt), (ins Od:$imm32), + !strconcat(instr_asm, "\t$rt, $imm32")> ; +def LoadAddr32Imm : LoadAddressImm<"la", uimm5, GPR32Opnd>; + +//===----------------------------------------------------------------------===// +// Arbitrary patterns that map to one or more instructions +//===----------------------------------------------------------------------===// + +// Load/store pattern templates. +class LoadRegImmPat<Instruction LoadInst, ValueType ValTy, PatFrag Node> : + MipsPat<(ValTy (Node addrRegImm:$a)), (LoadInst addrRegImm:$a)>; + +class StoreRegImmPat<Instruction StoreInst, ValueType ValTy> : + MipsPat<(store ValTy:$v, addrRegImm:$a), (StoreInst ValTy:$v, addrRegImm:$a)>; + +// Small immediates +def : MipsPat<(i32 immSExt16:$in), + (ADDiu ZERO, imm:$in)>; +def : MipsPat<(i32 immZExt16:$in), + (ORi ZERO, imm:$in)>; +def : MipsPat<(i32 immLow16Zero:$in), + (LUi (HI16 imm:$in))>; + +// Arbitrary immediates +def : MipsPat<(i32 imm:$imm), + (ORi (LUi (HI16 imm:$imm)), (LO16 imm:$imm))>; + +// Carry MipsPatterns +def : MipsPat<(subc GPR32:$lhs, GPR32:$rhs), + (SUBu GPR32:$lhs, GPR32:$rhs)>; +let Predicates = [HasStdEnc, NotDSP] in { + def : MipsPat<(addc GPR32:$lhs, GPR32:$rhs), + (ADDu GPR32:$lhs, GPR32:$rhs)>; + def : MipsPat<(addc GPR32:$src, immSExt16:$imm), + (ADDiu GPR32:$src, imm:$imm)>; +} + +// Call +def : MipsPat<(MipsJmpLink (i32 tglobaladdr:$dst)), + (JAL tglobaladdr:$dst)>; +def : MipsPat<(MipsJmpLink (i32 texternalsym:$dst)), + (JAL texternalsym:$dst)>; +//def : MipsPat<(MipsJmpLink GPR32:$dst), +// (JALR GPR32:$dst)>; + +// Tail call +def : MipsPat<(MipsTailCall (iPTR tglobaladdr:$dst)), + (TAILCALL tglobaladdr:$dst)>; +def : MipsPat<(MipsTailCall (iPTR texternalsym:$dst)), + (TAILCALL texternalsym:$dst)>; +// hi/lo relocs +def : MipsPat<(MipsHi tglobaladdr:$in), (LUi tglobaladdr:$in)>; +def : MipsPat<(MipsHi tblockaddress:$in), (LUi tblockaddress:$in)>; +def : MipsPat<(MipsHi tjumptable:$in), (LUi tjumptable:$in)>; +def : MipsPat<(MipsHi tconstpool:$in), (LUi tconstpool:$in)>; +def : MipsPat<(MipsHi tglobaltlsaddr:$in), (LUi tglobaltlsaddr:$in)>; +def : MipsPat<(MipsHi texternalsym:$in), (LUi texternalsym:$in)>; + +def : MipsPat<(MipsLo tglobaladdr:$in), (ADDiu ZERO, tglobaladdr:$in)>; +def : MipsPat<(MipsLo tblockaddress:$in), (ADDiu ZERO, tblockaddress:$in)>; +def : MipsPat<(MipsLo tjumptable:$in), (ADDiu ZERO, tjumptable:$in)>; +def : MipsPat<(MipsLo tconstpool:$in), (ADDiu ZERO, tconstpool:$in)>; +def : MipsPat<(MipsLo tglobaltlsaddr:$in), (ADDiu ZERO, tglobaltlsaddr:$in)>; +def : MipsPat<(MipsLo texternalsym:$in), (ADDiu ZERO, texternalsym:$in)>; + +def : MipsPat<(add GPR32:$hi, (MipsLo tglobaladdr:$lo)), + (ADDiu GPR32:$hi, tglobaladdr:$lo)>; +def : MipsPat<(add GPR32:$hi, (MipsLo tblockaddress:$lo)), + (ADDiu GPR32:$hi, tblockaddress:$lo)>; +def : MipsPat<(add GPR32:$hi, (MipsLo tjumptable:$lo)), + (ADDiu GPR32:$hi, tjumptable:$lo)>; +def : MipsPat<(add GPR32:$hi, (MipsLo tconstpool:$lo)), + (ADDiu GPR32:$hi, tconstpool:$lo)>; +def : MipsPat<(add GPR32:$hi, (MipsLo tglobaltlsaddr:$lo)), + (ADDiu GPR32:$hi, tglobaltlsaddr:$lo)>; + +// gp_rel relocs +def : MipsPat<(add GPR32:$gp, (MipsGPRel tglobaladdr:$in)), + (ADDiu GPR32:$gp, tglobaladdr:$in)>; +def : MipsPat<(add GPR32:$gp, (MipsGPRel tconstpool:$in)), + (ADDiu GPR32:$gp, tconstpool:$in)>; + +// wrapper_pic +class WrapperPat<SDNode node, Instruction ADDiuOp, RegisterClass RC>: + MipsPat<(MipsWrapper RC:$gp, node:$in), + (ADDiuOp RC:$gp, node:$in)>; + +def : WrapperPat<tglobaladdr, ADDiu, GPR32>; +def : WrapperPat<tconstpool, ADDiu, GPR32>; +def : WrapperPat<texternalsym, ADDiu, GPR32>; +def : WrapperPat<tblockaddress, ADDiu, GPR32>; +def : WrapperPat<tjumptable, ADDiu, GPR32>; +def : WrapperPat<tglobaltlsaddr, ADDiu, GPR32>; + +// Mips does not have "not", so we expand our way +def : MipsPat<(not GPR32:$in), + (NOR GPR32Opnd:$in, ZERO)>; + +// extended loads +let Predicates = [HasStdEnc] in { + def : MipsPat<(i32 (extloadi1 addr:$src)), (LBu addr:$src)>; + def : MipsPat<(i32 (extloadi8 addr:$src)), (LBu addr:$src)>; + def : MipsPat<(i32 (extloadi16 addr:$src)), (LHu addr:$src)>; +} + +// peepholes +let Predicates = [HasStdEnc] in +def : MipsPat<(store (i32 0), addr:$dst), (SW ZERO, addr:$dst)>; + +// brcond patterns +multiclass BrcondPats<RegisterClass RC, Instruction BEQOp, Instruction BNEOp, + Instruction SLTOp, Instruction SLTuOp, Instruction SLTiOp, + Instruction SLTiuOp, Register ZEROReg> { +def : MipsPat<(brcond (i32 (setne RC:$lhs, 0)), bb:$dst), + (BNEOp RC:$lhs, ZEROReg, bb:$dst)>; +def : MipsPat<(brcond (i32 (seteq RC:$lhs, 0)), bb:$dst), + (BEQOp RC:$lhs, ZEROReg, bb:$dst)>; + +def : MipsPat<(brcond (i32 (setge RC:$lhs, RC:$rhs)), bb:$dst), + (BEQ (SLTOp RC:$lhs, RC:$rhs), ZERO, bb:$dst)>; +def : MipsPat<(brcond (i32 (setuge RC:$lhs, RC:$rhs)), bb:$dst), + (BEQ (SLTuOp RC:$lhs, RC:$rhs), ZERO, bb:$dst)>; +def : MipsPat<(brcond (i32 (setge RC:$lhs, immSExt16:$rhs)), bb:$dst), + (BEQ (SLTiOp RC:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>; +def : MipsPat<(brcond (i32 (setuge RC:$lhs, immSExt16:$rhs)), bb:$dst), + (BEQ (SLTiuOp RC:$lhs, immSExt16:$rhs), ZERO, bb:$dst)>; +def : MipsPat<(brcond (i32 (setgt RC:$lhs, immSExt16Plus1:$rhs)), bb:$dst), + (BEQ (SLTiOp RC:$lhs, (Plus1 imm:$rhs)), ZERO, bb:$dst)>; +def : MipsPat<(brcond (i32 (setugt RC:$lhs, immSExt16Plus1:$rhs)), bb:$dst), + (BEQ (SLTiuOp RC:$lhs, (Plus1 imm:$rhs)), ZERO, bb:$dst)>; + +def : MipsPat<(brcond (i32 (setle RC:$lhs, RC:$rhs)), bb:$dst), + (BEQ (SLTOp RC:$rhs, RC:$lhs), ZERO, bb:$dst)>; +def : MipsPat<(brcond (i32 (setule RC:$lhs, RC:$rhs)), bb:$dst), + (BEQ (SLTuOp RC:$rhs, RC:$lhs), ZERO, bb:$dst)>; + +def : MipsPat<(brcond RC:$cond, bb:$dst), + (BNEOp RC:$cond, ZEROReg, bb:$dst)>; +} + +defm : BrcondPats<GPR32, BEQ, BNE, SLT, SLTu, SLTi, SLTiu, ZERO>; + +def : MipsPat<(brcond (i32 (setlt i32:$lhs, 1)), bb:$dst), + (BLEZ i32:$lhs, bb:$dst)>; +def : MipsPat<(brcond (i32 (setgt i32:$lhs, -1)), bb:$dst), + (BGEZ i32:$lhs, bb:$dst)>; + +// setcc patterns +multiclass SeteqPats<RegisterClass RC, Instruction SLTiuOp, Instruction XOROp, + Instruction SLTuOp, Register ZEROReg> { + def : MipsPat<(seteq RC:$lhs, 0), + (SLTiuOp RC:$lhs, 1)>; + def : MipsPat<(setne RC:$lhs, 0), + (SLTuOp ZEROReg, RC:$lhs)>; + def : MipsPat<(seteq RC:$lhs, RC:$rhs), + (SLTiuOp (XOROp RC:$lhs, RC:$rhs), 1)>; + def : MipsPat<(setne RC:$lhs, RC:$rhs), + (SLTuOp ZEROReg, (XOROp RC:$lhs, RC:$rhs))>; +} + +multiclass SetlePats<RegisterClass RC, Instruction SLTOp, Instruction SLTuOp> { + def : MipsPat<(setle RC:$lhs, RC:$rhs), + (XORi (SLTOp RC:$rhs, RC:$lhs), 1)>; + def : MipsPat<(setule RC:$lhs, RC:$rhs), + (XORi (SLTuOp RC:$rhs, RC:$lhs), 1)>; +} + +multiclass SetgtPats<RegisterClass RC, Instruction SLTOp, Instruction SLTuOp> { + def : MipsPat<(setgt RC:$lhs, RC:$rhs), + (SLTOp RC:$rhs, RC:$lhs)>; + def : MipsPat<(setugt RC:$lhs, RC:$rhs), + (SLTuOp RC:$rhs, RC:$lhs)>; +} + +multiclass SetgePats<RegisterClass RC, Instruction SLTOp, Instruction SLTuOp> { + def : MipsPat<(setge RC:$lhs, RC:$rhs), + (XORi (SLTOp RC:$lhs, RC:$rhs), 1)>; + def : MipsPat<(setuge RC:$lhs, RC:$rhs), + (XORi (SLTuOp RC:$lhs, RC:$rhs), 1)>; +} + +multiclass SetgeImmPats<RegisterClass RC, Instruction SLTiOp, + Instruction SLTiuOp> { + def : MipsPat<(setge RC:$lhs, immSExt16:$rhs), + (XORi (SLTiOp RC:$lhs, immSExt16:$rhs), 1)>; + def : MipsPat<(setuge RC:$lhs, immSExt16:$rhs), + (XORi (SLTiuOp RC:$lhs, immSExt16:$rhs), 1)>; +} + +defm : SeteqPats<GPR32, SLTiu, XOR, SLTu, ZERO>; +defm : SetlePats<GPR32, SLT, SLTu>; +defm : SetgtPats<GPR32, SLT, SLTu>; +defm : SetgePats<GPR32, SLT, SLTu>; +defm : SetgeImmPats<GPR32, SLTi, SLTiu>; + +// bswap pattern +def : MipsPat<(bswap GPR32:$rt), (ROTR (WSBH GPR32:$rt), 16)>; + +// Load halfword/word patterns. +let AddedComplexity = 40 in { + let Predicates = [HasStdEnc] in { + def : LoadRegImmPat<LBu, i32, zextloadi8>; + def : LoadRegImmPat<LH, i32, sextloadi16>; + def : LoadRegImmPat<LW, i32, load>; + } +} + +//===----------------------------------------------------------------------===// +// Floating Point Support +//===----------------------------------------------------------------------===// + +include "MipsInstrFPU.td" +include "Mips64InstrInfo.td" +include "MipsCondMov.td" + +// +// Mips16 + +include "Mips16InstrFormats.td" +include "Mips16InstrInfo.td" + +// DSP +include "MipsDSPInstrFormats.td" +include "MipsDSPInstrInfo.td" + +// MSA +include "MipsMSAInstrFormats.td" +include "MipsMSAInstrInfo.td" + +// Micromips +include "MicroMipsInstrFormats.td" +include "MicroMipsInstrInfo.td" diff --git a/contrib/llvm/lib/Target/Mips/MipsJITInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsJITInfo.cpp new file mode 100644 index 000000000000..d76cb1da2ddc --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsJITInfo.cpp @@ -0,0 +1,285 @@ +//===-- MipsJITInfo.cpp - Implement the Mips JIT Interface ----------------===// +// +// 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 JIT interfaces for the Mips target. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "jit" +#include "MipsJITInfo.h" +#include "MipsInstrInfo.h" +#include "MipsRelocations.h" +#include "MipsSubtarget.h" +#include "llvm/CodeGen/JITCodeEmitter.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Memory.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdlib> +using namespace llvm; + + +void MipsJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { + unsigned NewAddr = (intptr_t)New; + unsigned OldAddr = (intptr_t)Old; + const unsigned NopInstr = 0x0; + + // If the functions are in the same memory segment, insert PC-region branch. + if ((NewAddr & 0xF0000000) == ((OldAddr + 4) & 0xF0000000)) { + unsigned *OldInstruction = (unsigned *)Old; + *OldInstruction = 0x08000000; + unsigned JTargetAddr = NewAddr & 0x0FFFFFFC; + + JTargetAddr >>= 2; + *OldInstruction |= JTargetAddr; + + // Insert a NOP. + OldInstruction++; + *OldInstruction = NopInstr; + + sys::Memory::InvalidateInstructionCache(Old, 2 * 4); + } else { + // We need to clear hint bits from the instruction, in case it is 'jr ra'. + const unsigned HintMask = 0xFFFFF83F, ReturnSequence = 0x03e00008; + unsigned* CurrentInstr = (unsigned*)Old; + unsigned CurrInstrHintClear = (*CurrentInstr) & HintMask; + unsigned* NextInstr = CurrentInstr + 1; + unsigned NextInstrHintClear = (*NextInstr) & HintMask; + + // Do absolute jump if there are 2 or more instructions before return from + // the old function. + if ((CurrInstrHintClear != ReturnSequence) && + (NextInstrHintClear != ReturnSequence)) { + const unsigned LuiT0Instr = 0x3c080000, AddiuT0Instr = 0x25080000; + const unsigned JrT0Instr = 0x01000008; + // lui t0, high 16 bit of the NewAddr + (*(CurrentInstr++)) = LuiT0Instr | ((NewAddr & 0xffff0000) >> 16); + // addiu t0, t0, low 16 bit of the NewAddr + (*(CurrentInstr++)) = AddiuT0Instr | (NewAddr & 0x0000ffff); + // jr t0 + (*(CurrentInstr++)) = JrT0Instr; + (*CurrentInstr) = NopInstr; + + sys::Memory::InvalidateInstructionCache(Old, 4 * 4); + } else { + // Unsupported case + report_fatal_error("MipsJITInfo::replaceMachineCodeForFunction"); + } + } +} + +/// JITCompilerFunction - This contains the address of the JIT function used to +/// compile a function lazily. +static TargetJITInfo::JITCompilerFn JITCompilerFunction; + +// Get the ASMPREFIX for the current host. This is often '_'. +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ +#endif +#define GETASMPREFIX2(X) #X +#define GETASMPREFIX(X) GETASMPREFIX2(X) +#define ASMPREFIX GETASMPREFIX(__USER_LABEL_PREFIX__) + +// CompilationCallback stub - We can't use a C function with inline assembly in +// it, because the prolog/epilog inserted by GCC won't work for us. Instead, +// write our own wrapper, which does things our way, so we have complete control +// over register saving and restoring. This code saves registers, calls +// MipsCompilationCallbackC and restores registers. +extern "C" { +#if defined (__mips__) +void MipsCompilationCallback(); + + asm( + ".text\n" + ".align 2\n" + ".globl " ASMPREFIX "MipsCompilationCallback\n" + ASMPREFIX "MipsCompilationCallback:\n" + ".ent " ASMPREFIX "MipsCompilationCallback\n" + ".frame $sp, 32, $ra\n" + ".set noreorder\n" + ".cpload $t9\n" + + "addiu $sp, $sp, -64\n" + ".cprestore 16\n" + + // Save argument registers a0, a1, a2, a3, f12, f14 since they may contain + // stuff for the real target function right now. We have to act as if this + // whole compilation callback doesn't exist as far as the caller is + // concerned. We also need to save the ra register since it contains the + // original return address, and t8 register since it contains the address + // of the end of function stub. + "sw $a0, 20($sp)\n" + "sw $a1, 24($sp)\n" + "sw $a2, 28($sp)\n" + "sw $a3, 32($sp)\n" + "sw $ra, 36($sp)\n" + "sw $t8, 40($sp)\n" + "sdc1 $f12, 48($sp)\n" + "sdc1 $f14, 56($sp)\n" + + // t8 points at the end of function stub. Pass the beginning of the stub + // to the MipsCompilationCallbackC. + "addiu $a0, $t8, -16\n" + "jal " ASMPREFIX "MipsCompilationCallbackC\n" + "nop\n" + + // Restore registers. + "lw $a0, 20($sp)\n" + "lw $a1, 24($sp)\n" + "lw $a2, 28($sp)\n" + "lw $a3, 32($sp)\n" + "lw $ra, 36($sp)\n" + "lw $t8, 40($sp)\n" + "ldc1 $f12, 48($sp)\n" + "ldc1 $f14, 56($sp)\n" + "addiu $sp, $sp, 64\n" + + // Jump to the (newly modified) stub to invoke the real function. + "addiu $t8, $t8, -16\n" + "jr $t8\n" + "nop\n" + + ".set reorder\n" + ".end " ASMPREFIX "MipsCompilationCallback\n" + ); +#else // host != Mips + void MipsCompilationCallback() { + llvm_unreachable( + "Cannot call MipsCompilationCallback() on a non-Mips arch!"); + } +#endif +} + +/// MipsCompilationCallbackC - This is the target-specific function invoked +/// by the function stub when we did not know the real target of a call. +/// This function must locate the start of the stub or call site and pass +/// it into the JIT compiler function. +extern "C" void MipsCompilationCallbackC(intptr_t StubAddr) { + // Get the address of the compiled code for this function. + intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr); + + // Rewrite the function stub so that we don't end up here every time we + // execute the call. We're replacing the first four instructions of the + // stub with code that jumps to the compiled function: + // lui $t9, %hi(NewVal) + // addiu $t9, $t9, %lo(NewVal) + // jr $t9 + // nop + + int Hi = ((unsigned)NewVal & 0xffff0000) >> 16; + if ((NewVal & 0x8000) != 0) + Hi++; + int Lo = (int)(NewVal & 0xffff); + + *(intptr_t *)(StubAddr) = 0xf << 26 | 25 << 16 | Hi; + *(intptr_t *)(StubAddr + 4) = 9 << 26 | 25 << 21 | 25 << 16 | Lo; + *(intptr_t *)(StubAddr + 8) = 25 << 21 | 8; + *(intptr_t *)(StubAddr + 12) = 0; + + sys::Memory::InvalidateInstructionCache((void*) StubAddr, 16); +} + +TargetJITInfo::LazyResolverFn MipsJITInfo::getLazyResolverFunction( + JITCompilerFn F) { + JITCompilerFunction = F; + return MipsCompilationCallback; +} + +TargetJITInfo::StubLayout MipsJITInfo::getStubLayout() { + // The stub contains 4 4-byte instructions, aligned at 4 bytes. See + // emitFunctionStub for details. + StubLayout Result = { 4*4, 4 }; + return Result; +} + +void *MipsJITInfo::emitFunctionStub(const Function *F, void *Fn, + JITCodeEmitter &JCE) { + JCE.emitAlignment(4); + void *Addr = (void*) (JCE.getCurrentPCValue()); + if (!sys::Memory::setRangeWritable(Addr, 16)) + llvm_unreachable("ERROR: Unable to mark stub writable."); + + intptr_t EmittedAddr; + if (Fn != (void*)(intptr_t)MipsCompilationCallback) + EmittedAddr = (intptr_t)Fn; + else + EmittedAddr = (intptr_t)MipsCompilationCallback; + + + int Hi = ((unsigned)EmittedAddr & 0xffff0000) >> 16; + if ((EmittedAddr & 0x8000) != 0) + Hi++; + int Lo = (int)(EmittedAddr & 0xffff); + + // lui $t9, %hi(EmittedAddr) + // addiu $t9, $t9, %lo(EmittedAddr) + // jalr $t8, $t9 + // nop + if (IsLittleEndian) { + JCE.emitWordLE(0xf << 26 | 25 << 16 | Hi); + JCE.emitWordLE(9 << 26 | 25 << 21 | 25 << 16 | Lo); + JCE.emitWordLE(25 << 21 | 24 << 11 | 9); + JCE.emitWordLE(0); + } else { + JCE.emitWordBE(0xf << 26 | 25 << 16 | Hi); + JCE.emitWordBE(9 << 26 | 25 << 21 | 25 << 16 | Lo); + JCE.emitWordBE(25 << 21 | 24 << 11 | 9); + JCE.emitWordBE(0); + } + + sys::Memory::InvalidateInstructionCache(Addr, 16); + if (!sys::Memory::setRangeExecutable(Addr, 16)) + llvm_unreachable("ERROR: Unable to mark stub executable."); + + return Addr; +} + +/// relocate - Before the JIT can run a block of code that has been emitted, +/// it must rewrite the code to contain the actual addresses of any +/// referenced global symbols. +void MipsJITInfo::relocate(void *Function, MachineRelocation *MR, + unsigned NumRelocs, unsigned char *GOTBase) { + for (unsigned i = 0; i != NumRelocs; ++i, ++MR) { + + void *RelocPos = (char*) Function + MR->getMachineCodeOffset(); + intptr_t ResultPtr = (intptr_t) MR->getResultPointer(); + + switch ((Mips::RelocationType) MR->getRelocationType()) { + case Mips::reloc_mips_pc16: + ResultPtr = (((ResultPtr - (intptr_t) RelocPos) - 4) >> 2) & 0xffff; + *((unsigned*) RelocPos) |= (unsigned) ResultPtr; + break; + + case Mips::reloc_mips_26: + ResultPtr = (ResultPtr & 0x0fffffff) >> 2; + *((unsigned*) RelocPos) |= (unsigned) ResultPtr; + break; + + case Mips::reloc_mips_hi: + ResultPtr = ResultPtr >> 16; + if ((((intptr_t) (MR->getResultPointer()) & 0xffff) >> 15) == 1) { + ResultPtr += 1; + } + *((unsigned*) RelocPos) |= (unsigned) ResultPtr; + break; + + case Mips::reloc_mips_lo: { + // Addend is needed for unaligned load/store instructions, where offset + // for the second load/store in the expanded instruction sequence must + // be modified by +1 or +3. Otherwise, Addend is 0. + int Addend = *((unsigned*) RelocPos) & 0xffff; + ResultPtr = (ResultPtr + Addend) & 0xffff; + *((unsigned*) RelocPos) &= 0xffff0000; + *((unsigned*) RelocPos) |= (unsigned) ResultPtr; + break; + } + } + } +} diff --git a/contrib/llvm/lib/Target/Mips/MipsJITInfo.h b/contrib/llvm/lib/Target/Mips/MipsJITInfo.h new file mode 100644 index 000000000000..ecda3101a003 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsJITInfo.h @@ -0,0 +1,71 @@ +//===- MipsJITInfo.h - Mips Implementation of the JIT 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 contains the declaration of the MipsJITInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSJITINFO_H +#define MIPSJITINFO_H + +#include "MipsMachineFunction.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/Target/TargetJITInfo.h" + +namespace llvm { +class MipsTargetMachine; + +class MipsJITInfo : public TargetJITInfo { + + bool IsPIC; + bool IsLittleEndian; + + public: + explicit MipsJITInfo() : + IsPIC(false), IsLittleEndian(true) {} + + /// replaceMachineCodeForFunction - Make it so that calling the function + /// whose machine code is at OLD turns into a call to NEW, perhaps by + /// overwriting OLD with a branch to NEW. This is used for self-modifying + /// code. + /// + virtual void replaceMachineCodeForFunction(void *Old, void *New); + + // getStubLayout - Returns the size and alignment of the largest call stub + // on Mips. + virtual StubLayout getStubLayout(); + + /// emitFunctionStub - Use the specified JITCodeEmitter object to emit a + /// small native function that simply calls the function at the specified + /// address. + virtual void *emitFunctionStub(const Function *F, void *Fn, + JITCodeEmitter &JCE); + + /// getLazyResolverFunction - Expose the lazy resolver to the JIT. + virtual LazyResolverFn getLazyResolverFunction(JITCompilerFn); + + /// relocate - Before the JIT can run a block of code that has been emitted, + /// it must rewrite the code to contain the actual addresses of any + /// referenced global symbols. + virtual void relocate(void *Function, MachineRelocation *MR, + unsigned NumRelocs, unsigned char *GOTBase); + + /// Initialize - Initialize internal stage for the function being JITted. + void Initialize(const MachineFunction &MF, bool isPIC, + bool isLittleEndian) { + IsPIC = isPIC; + IsLittleEndian = isLittleEndian; + } + +}; +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp b/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp new file mode 100644 index 000000000000..2efe57847add --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp @@ -0,0 +1,472 @@ +//===-- MipsLongBranch.cpp - Emit long branches ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass expands a branch or jump instruction into a long branch if its +// offset is too large to fit into its immediate field. +// +// FIXME: +// 1. Fix pc-region jump instructions which cross 256MB segment boundaries. +// 2. If program has inline assembly statements whose size cannot be +// determined accurately, load branch target addresses from the GOT. +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-long-branch" + +#include "Mips.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" + +using namespace llvm; + +STATISTIC(LongBranches, "Number of long branches."); + +static cl::opt<bool> SkipLongBranch( + "skip-mips-long-branch", + cl::init(false), + cl::desc("MIPS: Skip long branch pass."), + cl::Hidden); + +static cl::opt<bool> ForceLongBranch( + "force-mips-long-branch", + cl::init(false), + cl::desc("MIPS: Expand all branches to long format."), + cl::Hidden); + +namespace { + typedef MachineBasicBlock::iterator Iter; + typedef MachineBasicBlock::reverse_iterator ReverseIter; + + struct MBBInfo { + uint64_t Size, Address; + bool HasLongBranch; + MachineInstr *Br; + + MBBInfo() : Size(0), HasLongBranch(false), Br(0) {} + }; + + class MipsLongBranch : public MachineFunctionPass { + + public: + static char ID; + MipsLongBranch(TargetMachine &tm) + : MachineFunctionPass(ID), TM(tm), + IsPIC(TM.getRelocationModel() == Reloc::PIC_), + ABI(TM.getSubtarget<MipsSubtarget>().getTargetABI()), + LongBranchSeqSize(!IsPIC ? 2 : (ABI == MipsSubtarget::N64 ? 13 : 9)) {} + + virtual const char *getPassName() const { + return "Mips Long Branch"; + } + + bool runOnMachineFunction(MachineFunction &F); + + private: + void splitMBB(MachineBasicBlock *MBB); + void initMBBInfo(); + int64_t computeOffset(const MachineInstr *Br); + void replaceBranch(MachineBasicBlock &MBB, Iter Br, DebugLoc DL, + MachineBasicBlock *MBBOpnd); + void expandToLongBranch(MBBInfo &Info); + + const TargetMachine &TM; + MachineFunction *MF; + SmallVector<MBBInfo, 16> MBBInfos; + bool IsPIC; + unsigned ABI; + unsigned LongBranchSeqSize; + }; + + char MipsLongBranch::ID = 0; +} // end of anonymous namespace + +/// createMipsLongBranchPass - Returns a pass that converts branches to long +/// branches. +FunctionPass *llvm::createMipsLongBranchPass(MipsTargetMachine &tm) { + return new MipsLongBranch(tm); +} + +/// Iterate over list of Br's operands and search for a MachineBasicBlock +/// operand. +static MachineBasicBlock *getTargetMBB(const MachineInstr &Br) { + for (unsigned I = 0, E = Br.getDesc().getNumOperands(); I < E; ++I) { + const MachineOperand &MO = Br.getOperand(I); + + if (MO.isMBB()) + return MO.getMBB(); + } + + assert(false && "This instruction does not have an MBB operand."); + return 0; +} + +// Traverse the list of instructions backwards until a non-debug instruction is +// found or it reaches E. +static ReverseIter getNonDebugInstr(ReverseIter B, ReverseIter E) { + for (; B != E; ++B) + if (!B->isDebugValue()) + return B; + + return E; +} + +// Split MBB if it has two direct jumps/branches. +void MipsLongBranch::splitMBB(MachineBasicBlock *MBB) { + ReverseIter End = MBB->rend(); + ReverseIter LastBr = getNonDebugInstr(MBB->rbegin(), End); + + // Return if MBB has no branch instructions. + if ((LastBr == End) || + (!LastBr->isConditionalBranch() && !LastBr->isUnconditionalBranch())) + return; + + ReverseIter FirstBr = getNonDebugInstr(llvm::next(LastBr), End); + + // MBB has only one branch instruction if FirstBr is not a branch + // instruction. + if ((FirstBr == End) || + (!FirstBr->isConditionalBranch() && !FirstBr->isUnconditionalBranch())) + return; + + assert(!FirstBr->isIndirectBranch() && "Unexpected indirect branch found."); + + // Create a new MBB. Move instructions in MBB to the newly created MBB. + MachineBasicBlock *NewMBB = + MF->CreateMachineBasicBlock(MBB->getBasicBlock()); + + // Insert NewMBB and fix control flow. + MachineBasicBlock *Tgt = getTargetMBB(*FirstBr); + NewMBB->transferSuccessors(MBB); + NewMBB->removeSuccessor(Tgt); + MBB->addSuccessor(NewMBB); + MBB->addSuccessor(Tgt); + MF->insert(llvm::next(MachineFunction::iterator(MBB)), NewMBB); + + NewMBB->splice(NewMBB->end(), MBB, (++LastBr).base(), MBB->end()); +} + +// Fill MBBInfos. +void MipsLongBranch::initMBBInfo() { + // Split the MBBs if they have two branches. Each basic block should have at + // most one branch after this loop is executed. + for (MachineFunction::iterator I = MF->begin(), E = MF->end(); I != E;) + splitMBB(I++); + + MF->RenumberBlocks(); + MBBInfos.clear(); + MBBInfos.resize(MF->size()); + + const MipsInstrInfo *TII = + static_cast<const MipsInstrInfo*>(TM.getInstrInfo()); + for (unsigned I = 0, E = MBBInfos.size(); I < E; ++I) { + MachineBasicBlock *MBB = MF->getBlockNumbered(I); + + // Compute size of MBB. + for (MachineBasicBlock::instr_iterator MI = MBB->instr_begin(); + MI != MBB->instr_end(); ++MI) + MBBInfos[I].Size += TII->GetInstSizeInBytes(&*MI); + + // Search for MBB's branch instruction. + ReverseIter End = MBB->rend(); + ReverseIter Br = getNonDebugInstr(MBB->rbegin(), End); + + if ((Br != End) && !Br->isIndirectBranch() && + (Br->isConditionalBranch() || + (Br->isUnconditionalBranch() && + TM.getRelocationModel() == Reloc::PIC_))) + MBBInfos[I].Br = (++Br).base(); + } +} + +// Compute offset of branch in number of bytes. +int64_t MipsLongBranch::computeOffset(const MachineInstr *Br) { + int64_t Offset = 0; + int ThisMBB = Br->getParent()->getNumber(); + int TargetMBB = getTargetMBB(*Br)->getNumber(); + + // Compute offset of a forward branch. + if (ThisMBB < TargetMBB) { + for (int N = ThisMBB + 1; N < TargetMBB; ++N) + Offset += MBBInfos[N].Size; + + return Offset + 4; + } + + // Compute offset of a backward branch. + for (int N = ThisMBB; N >= TargetMBB; --N) + Offset += MBBInfos[N].Size; + + return -Offset + 4; +} + +// Replace Br with a branch which has the opposite condition code and a +// MachineBasicBlock operand MBBOpnd. +void MipsLongBranch::replaceBranch(MachineBasicBlock &MBB, Iter Br, + DebugLoc DL, MachineBasicBlock *MBBOpnd) { + const MipsInstrInfo *TII = + static_cast<const MipsInstrInfo*>(TM.getInstrInfo()); + unsigned NewOpc = TII->getOppositeBranchOpc(Br->getOpcode()); + const MCInstrDesc &NewDesc = TII->get(NewOpc); + + MachineInstrBuilder MIB = BuildMI(MBB, Br, DL, NewDesc); + + for (unsigned I = 0, E = Br->getDesc().getNumOperands(); I < E; ++I) { + MachineOperand &MO = Br->getOperand(I); + + if (!MO.isReg()) { + assert(MO.isMBB() && "MBB operand expected."); + break; + } + + MIB.addReg(MO.getReg()); + } + + MIB.addMBB(MBBOpnd); + + // Bundle the instruction in the delay slot to the newly created branch + // and erase the original branch. + assert(Br->isBundledWithSucc()); + MachineBasicBlock::instr_iterator II(Br); + MIBundleBuilder(&*MIB).append((++II)->removeFromBundle()); + Br->eraseFromParent(); +} + +// Expand branch instructions to long branches. +void MipsLongBranch::expandToLongBranch(MBBInfo &I) { + MachineBasicBlock::iterator Pos; + MachineBasicBlock *MBB = I.Br->getParent(), *TgtMBB = getTargetMBB(*I.Br); + DebugLoc DL = I.Br->getDebugLoc(); + const BasicBlock *BB = MBB->getBasicBlock(); + MachineFunction::iterator FallThroughMBB = ++MachineFunction::iterator(MBB); + MachineBasicBlock *LongBrMBB = MF->CreateMachineBasicBlock(BB); + + const MipsInstrInfo *TII = + static_cast<const MipsInstrInfo*>(TM.getInstrInfo()); + + MF->insert(FallThroughMBB, LongBrMBB); + MBB->removeSuccessor(TgtMBB); + MBB->addSuccessor(LongBrMBB); + + if (IsPIC) { + MachineBasicBlock *BalTgtMBB = MF->CreateMachineBasicBlock(BB); + MF->insert(FallThroughMBB, BalTgtMBB); + LongBrMBB->addSuccessor(BalTgtMBB); + BalTgtMBB->addSuccessor(TgtMBB); + + int64_t TgtAddress = MBBInfos[TgtMBB->getNumber()].Address; + unsigned BalTgtMBBSize = 5; + int64_t Offset = TgtAddress - (I.Address + I.Size - BalTgtMBBSize * 4); + int64_t Lo = SignExtend64<16>(Offset & 0xffff); + int64_t Hi = SignExtend64<16>(((Offset + 0x8000) >> 16) & 0xffff); + + if (ABI != MipsSubtarget::N64) { + // $longbr: + // addiu $sp, $sp, -8 + // sw $ra, 0($sp) + // bal $baltgt + // lui $at, %hi($tgt - $baltgt) + // $baltgt: + // addiu $at, $at, %lo($tgt - $baltgt) + // addu $at, $ra, $at + // lw $ra, 0($sp) + // jr $at + // addiu $sp, $sp, 8 + // $fallthrough: + // + + Pos = LongBrMBB->begin(); + + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP) + .addReg(Mips::SP).addImm(-8); + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SW)).addReg(Mips::RA) + .addReg(Mips::SP).addImm(0); + + MIBundleBuilder(*LongBrMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::BAL_BR)).addMBB(BalTgtMBB)) + .append(BuildMI(*MF, DL, TII->get(Mips::LUi), Mips::AT).addImm(Hi)); + + Pos = BalTgtMBB->begin(); + + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::AT) + .addReg(Mips::AT).addImm(Lo); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDu), Mips::AT) + .addReg(Mips::RA).addReg(Mips::AT); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LW), Mips::RA) + .addReg(Mips::SP).addImm(0); + + MIBundleBuilder(*BalTgtMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::JR)).addReg(Mips::AT)) + .append(BuildMI(*MF, DL, TII->get(Mips::ADDiu), Mips::SP) + .addReg(Mips::SP).addImm(8)); + } else { + // $longbr: + // daddiu $sp, $sp, -16 + // sd $ra, 0($sp) + // lui64 $at, %highest($tgt - $baltgt) + // daddiu $at, $at, %higher($tgt - $baltgt) + // dsll $at, $at, 16 + // daddiu $at, $at, %hi($tgt - $baltgt) + // bal $baltgt + // dsll $at, $at, 16 + // $baltgt: + // daddiu $at, $at, %lo($tgt - $baltgt) + // daddu $at, $ra, $at + // ld $ra, 0($sp) + // jr64 $at + // daddiu $sp, $sp, 16 + // $fallthrough: + // + + int64_t Higher = SignExtend64<16>(((Offset + 0x80008000) >> 32) & 0xffff); + int64_t Highest = + SignExtend64<16>(((Offset + 0x800080008000LL) >> 48) & 0xffff); + + Pos = LongBrMBB->begin(); + + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::SP_64) + .addReg(Mips::SP_64).addImm(-16); + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SD)).addReg(Mips::RA_64) + .addReg(Mips::SP_64).addImm(0); + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LUi64), Mips::AT_64) + .addImm(Highest); + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::AT_64) + .addReg(Mips::AT_64).addImm(Higher); + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DSLL), Mips::AT_64) + .addReg(Mips::AT_64).addImm(16); + BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::AT_64) + .addReg(Mips::AT_64).addImm(Hi); + + MIBundleBuilder(*LongBrMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::BAL_BR)).addMBB(BalTgtMBB)) + .append(BuildMI(*MF, DL, TII->get(Mips::DSLL), Mips::AT_64) + .addReg(Mips::AT_64).addImm(16)); + + Pos = BalTgtMBB->begin(); + + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::AT_64) + .addReg(Mips::AT_64).addImm(Lo); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDu), Mips::AT_64) + .addReg(Mips::RA_64).addReg(Mips::AT_64); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LD), Mips::RA_64) + .addReg(Mips::SP_64).addImm(0); + + MIBundleBuilder(*BalTgtMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::JR64)).addReg(Mips::AT_64)) + .append(BuildMI(*MF, DL, TII->get(Mips::DADDiu), Mips::SP_64) + .addReg(Mips::SP_64).addImm(16)); + } + + assert(BalTgtMBBSize == BalTgtMBB->size()); + assert(LongBrMBB->size() + BalTgtMBBSize == LongBranchSeqSize); + } else { + // $longbr: + // j $tgt + // nop + // $fallthrough: + // + Pos = LongBrMBB->begin(); + LongBrMBB->addSuccessor(TgtMBB); + MIBundleBuilder(*LongBrMBB, Pos) + .append(BuildMI(*MF, DL, TII->get(Mips::J)).addMBB(TgtMBB)) + .append(BuildMI(*MF, DL, TII->get(Mips::NOP))); + + assert(LongBrMBB->size() == LongBranchSeqSize); + } + + if (I.Br->isUnconditionalBranch()) { + // Change branch destination. + assert(I.Br->getDesc().getNumOperands() == 1); + I.Br->RemoveOperand(0); + I.Br->addOperand(MachineOperand::CreateMBB(LongBrMBB)); + } else + // Change branch destination and reverse condition. + replaceBranch(*MBB, I.Br, DL, FallThroughMBB); +} + +static void emitGPDisp(MachineFunction &F, const MipsInstrInfo *TII) { + MachineBasicBlock &MBB = F.front(); + MachineBasicBlock::iterator I = MBB.begin(); + DebugLoc DL = MBB.findDebugLoc(MBB.begin()); + BuildMI(MBB, I, DL, TII->get(Mips::LUi), Mips::V0) + .addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI); + BuildMI(MBB, I, DL, TII->get(Mips::ADDiu), Mips::V0) + .addReg(Mips::V0).addExternalSymbol("_gp_disp", MipsII::MO_ABS_LO); + MBB.removeLiveIn(Mips::V0); +} + +bool MipsLongBranch::runOnMachineFunction(MachineFunction &F) { + const MipsInstrInfo *TII = + static_cast<const MipsInstrInfo*>(TM.getInstrInfo()); + + if (TM.getSubtarget<MipsSubtarget>().inMips16Mode()) + return false; + if ((TM.getRelocationModel() == Reloc::PIC_) && + TM.getSubtarget<MipsSubtarget>().isABI_O32() && + F.getInfo<MipsFunctionInfo>()->globalBaseRegSet()) + emitGPDisp(F, TII); + + if (SkipLongBranch) + return true; + + MF = &F; + initMBBInfo(); + + SmallVectorImpl<MBBInfo>::iterator I, E = MBBInfos.end(); + bool EverMadeChange = false, MadeChange = true; + + while (MadeChange) { + MadeChange = false; + + for (I = MBBInfos.begin(); I != E; ++I) { + // Skip if this MBB doesn't have a branch or the branch has already been + // converted to a long branch. + if (!I->Br || I->HasLongBranch) + continue; + + int ShVal = TM.getSubtarget<MipsSubtarget>().inMicroMipsMode() ? 2 : 4; + + // Check if offset fits into 16-bit immediate field of branches. + if (!ForceLongBranch && isInt<16>(computeOffset(I->Br) / ShVal)) + continue; + + I->HasLongBranch = true; + I->Size += LongBranchSeqSize * 4; + ++LongBranches; + EverMadeChange = MadeChange = true; + } + } + + if (!EverMadeChange) + return true; + + // Compute basic block addresses. + if (TM.getRelocationModel() == Reloc::PIC_) { + uint64_t Address = 0; + + for (I = MBBInfos.begin(); I != E; Address += I->Size, ++I) + I->Address = Address; + } + + // Do the expansion. + for (I = MBBInfos.begin(); I != E; ++I) + if (I->HasLongBranch) + expandToLongBranch(*I); + + MF->RenumberBlocks(); + + return true; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsMCInstLower.cpp b/contrib/llvm/lib/Target/Mips/MipsMCInstLower.cpp new file mode 100644 index 000000000000..b6dfadce14e9 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMCInstLower.cpp @@ -0,0 +1,165 @@ +//===-- MipsMCInstLower.cpp - Convert Mips MachineInstr to 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 Mips MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// +#include "MipsMCInstLower.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsAsmPrinter.h" +#include "MipsInstrInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Target/Mangler.h" + +using namespace llvm; + +MipsMCInstLower::MipsMCInstLower(MipsAsmPrinter &asmprinter) + : AsmPrinter(asmprinter) {} + +void MipsMCInstLower::Initialize(MCContext *C) { + Ctx = C; +} + +MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO, + MachineOperandType MOTy, + unsigned Offset) const { + MCSymbolRefExpr::VariantKind Kind; + const MCSymbol *Symbol; + + switch(MO.getTargetFlags()) { + default: llvm_unreachable("Invalid target flag!"); + case MipsII::MO_NO_FLAG: Kind = MCSymbolRefExpr::VK_None; break; + case MipsII::MO_GPREL: Kind = MCSymbolRefExpr::VK_Mips_GPREL; break; + case MipsII::MO_GOT_CALL: Kind = MCSymbolRefExpr::VK_Mips_GOT_CALL; break; + case MipsII::MO_GOT16: Kind = MCSymbolRefExpr::VK_Mips_GOT16; break; + case MipsII::MO_GOT: Kind = MCSymbolRefExpr::VK_Mips_GOT; break; + case MipsII::MO_ABS_HI: Kind = MCSymbolRefExpr::VK_Mips_ABS_HI; break; + case MipsII::MO_ABS_LO: Kind = MCSymbolRefExpr::VK_Mips_ABS_LO; break; + case MipsII::MO_TLSGD: Kind = MCSymbolRefExpr::VK_Mips_TLSGD; break; + case MipsII::MO_TLSLDM: Kind = MCSymbolRefExpr::VK_Mips_TLSLDM; break; + case MipsII::MO_DTPREL_HI: Kind = MCSymbolRefExpr::VK_Mips_DTPREL_HI; break; + case MipsII::MO_DTPREL_LO: Kind = MCSymbolRefExpr::VK_Mips_DTPREL_LO; break; + case MipsII::MO_GOTTPREL: Kind = MCSymbolRefExpr::VK_Mips_GOTTPREL; break; + case MipsII::MO_TPREL_HI: Kind = MCSymbolRefExpr::VK_Mips_TPREL_HI; break; + case MipsII::MO_TPREL_LO: Kind = MCSymbolRefExpr::VK_Mips_TPREL_LO; break; + case MipsII::MO_GPOFF_HI: Kind = MCSymbolRefExpr::VK_Mips_GPOFF_HI; break; + case MipsII::MO_GPOFF_LO: Kind = MCSymbolRefExpr::VK_Mips_GPOFF_LO; break; + case MipsII::MO_GOT_DISP: Kind = MCSymbolRefExpr::VK_Mips_GOT_DISP; break; + case MipsII::MO_GOT_PAGE: Kind = MCSymbolRefExpr::VK_Mips_GOT_PAGE; break; + case MipsII::MO_GOT_OFST: Kind = MCSymbolRefExpr::VK_Mips_GOT_OFST; break; + case MipsII::MO_HIGHER: Kind = MCSymbolRefExpr::VK_Mips_HIGHER; break; + case MipsII::MO_HIGHEST: Kind = MCSymbolRefExpr::VK_Mips_HIGHEST; break; + case MipsII::MO_GOT_HI16: Kind = MCSymbolRefExpr::VK_Mips_GOT_HI16; break; + case MipsII::MO_GOT_LO16: Kind = MCSymbolRefExpr::VK_Mips_GOT_LO16; break; + case MipsII::MO_CALL_HI16: Kind = MCSymbolRefExpr::VK_Mips_CALL_HI16; break; + case MipsII::MO_CALL_LO16: Kind = MCSymbolRefExpr::VK_Mips_CALL_LO16; break; + } + + switch (MOTy) { + case MachineOperand::MO_MachineBasicBlock: + Symbol = MO.getMBB()->getSymbol(); + break; + + case MachineOperand::MO_GlobalAddress: + Symbol = AsmPrinter.getSymbol(MO.getGlobal()); + Offset += MO.getOffset(); + break; + + case MachineOperand::MO_BlockAddress: + Symbol = AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress()); + Offset += MO.getOffset(); + break; + + case MachineOperand::MO_ExternalSymbol: + Symbol = AsmPrinter.GetExternalSymbolSymbol(MO.getSymbolName()); + Offset += MO.getOffset(); + break; + + case MachineOperand::MO_JumpTableIndex: + Symbol = AsmPrinter.GetJTISymbol(MO.getIndex()); + break; + + case MachineOperand::MO_ConstantPoolIndex: + Symbol = AsmPrinter.GetCPISymbol(MO.getIndex()); + Offset += MO.getOffset(); + break; + + default: + llvm_unreachable("<unknown operand type>"); + } + + const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Symbol, Kind, *Ctx); + + if (!Offset) + return MCOperand::CreateExpr(MCSym); + + // Assume offset is never negative. + assert(Offset > 0); + + const MCConstantExpr *OffsetExpr = MCConstantExpr::Create(Offset, *Ctx); + const MCBinaryExpr *Add = MCBinaryExpr::CreateAdd(MCSym, OffsetExpr, *Ctx); + return MCOperand::CreateExpr(Add); +} + +/* +static void CreateMCInst(MCInst& Inst, unsigned Opc, const MCOperand &Opnd0, + const MCOperand &Opnd1, + const MCOperand &Opnd2 = MCOperand()) { + Inst.setOpcode(Opc); + Inst.addOperand(Opnd0); + Inst.addOperand(Opnd1); + if (Opnd2.isValid()) + Inst.addOperand(Opnd2); +} +*/ + +MCOperand MipsMCInstLower::LowerOperand(const MachineOperand &MO, + unsigned offset) const { + MachineOperandType MOTy = MO.getType(); + + switch (MOTy) { + default: llvm_unreachable("unknown operand type"); + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) break; + return MCOperand::CreateReg(MO.getReg()); + case MachineOperand::MO_Immediate: + return MCOperand::CreateImm(MO.getImm() + offset); + case MachineOperand::MO_MachineBasicBlock: + case MachineOperand::MO_GlobalAddress: + case MachineOperand::MO_ExternalSymbol: + case MachineOperand::MO_JumpTableIndex: + case MachineOperand::MO_ConstantPoolIndex: + case MachineOperand::MO_BlockAddress: + return LowerSymbolOperand(MO, MOTy, offset); + case MachineOperand::MO_RegisterMask: + break; + } + + return MCOperand(); +} + +void MipsMCInstLower::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 = LowerOperand(MO); + + if (MCOp.isValid()) + OutMI.addOperand(MCOp); + } +} + diff --git a/contrib/llvm/lib/Target/Mips/MipsMCInstLower.h b/contrib/llvm/lib/Target/Mips/MipsMCInstLower.h new file mode 100644 index 000000000000..4570bd90997f --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMCInstLower.h @@ -0,0 +1,42 @@ +//===-- MipsMCInstLower.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 MIPSMCINSTLOWER_H +#define MIPSMCINSTLOWER_H +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { + class MCContext; + class MCInst; + class MCOperand; + class MachineInstr; + class MachineFunction; + class MipsAsmPrinter; + +/// MipsMCInstLower - This class is used to lower an MachineInstr into an +// MCInst. +class LLVM_LIBRARY_VISIBILITY MipsMCInstLower { + typedef MachineOperand::MachineOperandType MachineOperandType; + MCContext *Ctx; + MipsAsmPrinter &AsmPrinter; +public: + MipsMCInstLower(MipsAsmPrinter &asmprinter); + void Initialize(MCContext *C); + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + MCOperand LowerOperand(const MachineOperand& MO, unsigned offset = 0) const; + +private: + MCOperand LowerSymbolOperand(const MachineOperand &MO, + MachineOperandType MOTy, unsigned Offset) const; +}; +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsMSAInstrFormats.td b/contrib/llvm/lib/Target/Mips/MipsMSAInstrFormats.td new file mode 100644 index 000000000000..875dc0b4034d --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMSAInstrFormats.td @@ -0,0 +1,406 @@ +//===- MipsMSAInstrFormats.td - Mips Instruction Formats ---*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +def HasMSA : Predicate<"Subtarget.hasMSA()">, + AssemblerPredicate<"FeatureMSA">; + +class MSAInst : MipsInst<(outs), (ins), "", [], NoItinerary, FrmOther> { + let Predicates = [HasMSA]; + let Inst{31-26} = 0b011110; +} + +class MSACBranch : MSAInst { + let Inst{31-26} = 0b010001; +} + +class MSASpecial : MSAInst { + let Inst{31-26} = 0b000000; +} + +class PseudoMSA<dag outs, dag ins, list<dag> pattern, + InstrItinClass itin = IIPseudo>: + MipsPseudo<outs, ins, pattern, itin> { + let Predicates = [HasMSA]; +} + +class MSA_BIT_B_FMT<bits<3> major, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + bits<3> m; + + let Inst{25-23} = major; + let Inst{22-19} = 0b1110; + let Inst{18-16} = m; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_BIT_H_FMT<bits<3> major, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + bits<4> m; + + let Inst{25-23} = major; + let Inst{22-20} = 0b110; + let Inst{19-16} = m; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_BIT_W_FMT<bits<3> major, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + bits<5> m; + + let Inst{25-23} = major; + let Inst{22-21} = 0b10; + let Inst{20-16} = m; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_BIT_D_FMT<bits<3> major, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + bits<6> m; + + let Inst{25-23} = major; + let Inst{22} = 0b0; + let Inst{21-16} = m; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_2R_FILL_FMT<bits<8> major, bits<2> df, bits<6> minor>: MSAInst { + bits<5> rs; + bits<5> wd; + + let Inst{25-18} = major; + let Inst{17-16} = df; + let Inst{15-11} = rs; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_2R_FMT<bits<8> major, bits<2> df, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + + let Inst{25-18} = major; + let Inst{17-16} = df; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_2RF_FMT<bits<9> major, bits<1> df, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + + let Inst{25-17} = major; + let Inst{16} = df; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_3R_FMT<bits<3> major, bits<2> df, bits<6> minor>: MSAInst { + bits<5> wt; + bits<5> ws; + bits<5> wd; + + let Inst{25-23} = major; + let Inst{22-21} = df; + let Inst{20-16} = wt; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_3RF_FMT<bits<4> major, bits<1> df, bits<6> minor>: MSAInst { + bits<5> wt; + bits<5> ws; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21} = df; + let Inst{20-16} = wt; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_3R_INDEX_FMT<bits<3> major, bits<2> df, bits<6> minor>: MSAInst { + bits<5> rt; + bits<5> ws; + bits<5> wd; + + let Inst{25-23} = major; + let Inst{22-21} = df; + let Inst{20-16} = rt; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_FMT<bits<10> major, bits<6> minor>: MSAInst { + bits<5> ws; + bits<5> wd; + + let Inst{25-16} = major; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_CFCMSA_FMT<bits<10> major, bits<6> minor>: MSAInst { + bits<5> rd; + bits<5> cs; + + let Inst{25-16} = major; + let Inst{15-11} = cs; + let Inst{10-6} = rd; + let Inst{5-0} = minor; +} + +class MSA_ELM_CTCMSA_FMT<bits<10> major, bits<6> minor>: MSAInst { + bits<5> rs; + bits<5> cd; + + let Inst{25-16} = major; + let Inst{15-11} = rs; + let Inst{10-6} = cd; + let Inst{5-0} = minor; +} + +class MSA_ELM_B_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-20} = 0b00; + let Inst{19-16} = n{3-0}; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_H_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-19} = 0b100; + let Inst{18-16} = n{2-0}; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_W_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-18} = 0b1100; + let Inst{17-16} = n{1-0}; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_D_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-17} = 0b11100; + let Inst{16} = n{0}; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_COPY_B_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> rd; + + let Inst{25-22} = major; + let Inst{21-20} = 0b00; + let Inst{19-16} = n{3-0}; + let Inst{15-11} = ws; + let Inst{10-6} = rd; + let Inst{5-0} = minor; +} + +class MSA_ELM_COPY_H_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> rd; + + let Inst{25-22} = major; + let Inst{21-19} = 0b100; + let Inst{18-16} = n{2-0}; + let Inst{15-11} = ws; + let Inst{10-6} = rd; + let Inst{5-0} = minor; +} + +class MSA_ELM_COPY_W_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<4> n; + bits<5> ws; + bits<5> rd; + + let Inst{25-22} = major; + let Inst{21-18} = 0b1100; + let Inst{17-16} = n{1-0}; + let Inst{15-11} = ws; + let Inst{10-6} = rd; + let Inst{5-0} = minor; +} + +class MSA_ELM_INSERT_B_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<6> n; + bits<5> rs; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-20} = 0b00; + let Inst{19-16} = n{3-0}; + let Inst{15-11} = rs; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_INSERT_H_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<6> n; + bits<5> rs; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-19} = 0b100; + let Inst{18-16} = n{2-0}; + let Inst{15-11} = rs; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_ELM_INSERT_W_FMT<bits<4> major, bits<6> minor>: MSAInst { + bits<6> n; + bits<5> rs; + bits<5> wd; + + let Inst{25-22} = major; + let Inst{21-18} = 0b1100; + let Inst{17-16} = n{1-0}; + let Inst{15-11} = rs; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_I5_FMT<bits<3> major, bits<2> df, bits<6> minor>: MSAInst { + bits<5> imm; + bits<5> ws; + bits<5> wd; + + let Inst{25-23} = major; + let Inst{22-21} = df; + let Inst{20-16} = imm; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_I8_FMT<bits<2> major, bits<6> minor>: MSAInst { + bits<8> u8; + bits<5> ws; + bits<5> wd; + + let Inst{25-24} = major; + let Inst{23-16} = u8; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_I10_FMT<bits<3> major, bits<2> df, bits<6> minor>: MSAInst { + bits<10> s10; + bits<5> wd; + + let Inst{25-23} = major; + let Inst{22-21} = df; + let Inst{20-11} = s10; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_MI10_FMT<bits<2> df, bits<4> minor>: MSAInst { + bits<21> addr; + bits<5> wd; + + let Inst{25-16} = addr{9-0}; + let Inst{15-11} = addr{20-16}; + let Inst{10-6} = wd; + let Inst{5-2} = minor; + let Inst{1-0} = df; +} + +class MSA_VEC_FMT<bits<5> major, bits<6> minor>: MSAInst { + bits<5> wt; + bits<5> ws; + bits<5> wd; + + let Inst{25-21} = major; + let Inst{20-16} = wt; + let Inst{15-11} = ws; + let Inst{10-6} = wd; + let Inst{5-0} = minor; +} + +class MSA_CBRANCH_FMT<bits<3> major, bits<2> df>: MSACBranch { + bits<16> offset; + bits<5> wt; + + let Inst{25-23} = major; + let Inst{22-21} = df; + let Inst{20-16} = wt; + let Inst{15-0} = offset; +} + +class MSA_CBRANCH_V_FMT<bits<5> major>: MSACBranch { + bits<16> offset; + bits<5> wt; + + let Inst{25-21} = major; + let Inst{20-16} = wt; + let Inst{15-0} = offset; +} + +class SPECIAL_LSA_FMT<bits<6> minor>: MSASpecial { + bits<5> rs; + bits<5> rt; + bits<5> rd; + bits<2> sa; + + let Inst{25-21} = rs; + let Inst{20-16} = rt; + let Inst{15-11} = rd; + let Inst{10-8} = 0b000; + let Inst{7-6} = sa; + let Inst{5-0} = minor; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsMSAInstrInfo.td b/contrib/llvm/lib/Target/Mips/MipsMSAInstrInfo.td new file mode 100644 index 000000000000..82c51a6473da --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMSAInstrInfo.td @@ -0,0 +1,3694 @@ +//===- MipsMSAInstrInfo.td - MSA ASE instructions -*- tablegen ------------*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Mips MSA ASE instructions. +// +//===----------------------------------------------------------------------===// + +def SDT_MipsVecCond : SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisVec<1>]>; +def SDT_VSetCC : SDTypeProfile<1, 3, [SDTCisInt<0>, + SDTCisInt<1>, + SDTCisSameAs<1, 2>, + SDTCisVT<3, OtherVT>]>; +def SDT_VFSetCC : SDTypeProfile<1, 3, [SDTCisInt<0>, + SDTCisFP<1>, + SDTCisSameAs<1, 2>, + SDTCisVT<3, OtherVT>]>; +def SDT_VSHF : SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisVec<0>, + SDTCisInt<1>, SDTCisVec<1>, + SDTCisSameAs<0, 2>, SDTCisSameAs<2, 3>]>; +def SDT_SHF : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisVec<0>, + SDTCisVT<1, i32>, SDTCisSameAs<0, 2>]>; +def SDT_ILV : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisVec<0>, + SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>]>; + +def MipsVAllNonZero : SDNode<"MipsISD::VALL_NONZERO", SDT_MipsVecCond>; +def MipsVAnyNonZero : SDNode<"MipsISD::VANY_NONZERO", SDT_MipsVecCond>; +def MipsVAllZero : SDNode<"MipsISD::VALL_ZERO", SDT_MipsVecCond>; +def MipsVAnyZero : SDNode<"MipsISD::VANY_ZERO", SDT_MipsVecCond>; +def MipsVSMax : SDNode<"MipsISD::VSMAX", SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; +def MipsVSMin : SDNode<"MipsISD::VSMIN", SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; +def MipsVUMax : SDNode<"MipsISD::VUMAX", SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; +def MipsVUMin : SDNode<"MipsISD::VUMIN", SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; +def MipsVNOR : SDNode<"MipsISD::VNOR", SDTIntBinOp, + [SDNPCommutative, SDNPAssociative]>; +def MipsVSHF : SDNode<"MipsISD::VSHF", SDT_VSHF>; +def MipsSHF : SDNode<"MipsISD::SHF", SDT_SHF>; +def MipsILVEV : SDNode<"MipsISD::ILVEV", SDT_ILV>; +def MipsILVOD : SDNode<"MipsISD::ILVOD", SDT_ILV>; +def MipsILVL : SDNode<"MipsISD::ILVL", SDT_ILV>; +def MipsILVR : SDNode<"MipsISD::ILVR", SDT_ILV>; +def MipsPCKEV : SDNode<"MipsISD::PCKEV", SDT_ILV>; +def MipsPCKOD : SDNode<"MipsISD::PCKOD", SDT_ILV>; + +def vsetcc : SDNode<"ISD::SETCC", SDT_VSetCC>; +def vfsetcc : SDNode<"ISD::SETCC", SDT_VFSetCC>; + +def MipsVExtractSExt : SDNode<"MipsISD::VEXTRACT_SEXT_ELT", + SDTypeProfile<1, 3, [SDTCisPtrTy<2>]>, []>; +def MipsVExtractZExt : SDNode<"MipsISD::VEXTRACT_ZEXT_ELT", + SDTypeProfile<1, 3, [SDTCisPtrTy<2>]>, []>; + +// Operands + +def uimm2 : Operand<i32> { + let PrintMethod = "printUnsignedImm"; +} + +// The immediate of an LSA instruction needs special handling +// as the encoded value should be subtracted by one. +def uimm2LSAAsmOperand : AsmOperandClass { + let Name = "LSAImm"; + let ParserMethod = "parseLSAImm"; + let RenderMethod = "addImmOperands"; +} + +def LSAImm : Operand<i32> { + let PrintMethod = "printUnsignedImm"; + let EncoderMethod = "getLSAImmEncoding"; + let DecoderMethod = "DecodeLSAImm"; + let ParserMatchClass = uimm2LSAAsmOperand; +} + +def uimm3 : Operand<i32> { + let PrintMethod = "printUnsignedImm8"; +} + +def uimm4 : Operand<i32> { + let PrintMethod = "printUnsignedImm8"; +} + +def uimm8 : Operand<i32> { + let PrintMethod = "printUnsignedImm8"; +} + +def simm5 : Operand<i32>; + +def simm10 : Operand<i32>; + +def vsplat_uimm1 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_uimm2 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_uimm3 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_uimm4 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_uimm5 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_uimm6 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_uimm8 : Operand<vAny> { + let PrintMethod = "printUnsignedImm8"; +} + +def vsplat_simm5 : Operand<vAny>; + +def vsplat_simm10 : Operand<vAny>; + +def immZExt2Lsa : ImmLeaf<i32, [{return isUInt<2>(Imm - 1);}]>; + +// Pattern fragments +def vextract_sext_i8 : PatFrag<(ops node:$vec, node:$idx), + (MipsVExtractSExt node:$vec, node:$idx, i8)>; +def vextract_sext_i16 : PatFrag<(ops node:$vec, node:$idx), + (MipsVExtractSExt node:$vec, node:$idx, i16)>; +def vextract_sext_i32 : PatFrag<(ops node:$vec, node:$idx), + (MipsVExtractSExt node:$vec, node:$idx, i32)>; + +def vextract_zext_i8 : PatFrag<(ops node:$vec, node:$idx), + (MipsVExtractZExt node:$vec, node:$idx, i8)>; +def vextract_zext_i16 : PatFrag<(ops node:$vec, node:$idx), + (MipsVExtractZExt node:$vec, node:$idx, i16)>; +def vextract_zext_i32 : PatFrag<(ops node:$vec, node:$idx), + (MipsVExtractZExt node:$vec, node:$idx, i32)>; + +def vinsert_v16i8 : PatFrag<(ops node:$vec, node:$val, node:$idx), + (v16i8 (vector_insert node:$vec, node:$val, node:$idx))>; +def vinsert_v8i16 : PatFrag<(ops node:$vec, node:$val, node:$idx), + (v8i16 (vector_insert node:$vec, node:$val, node:$idx))>; +def vinsert_v4i32 : PatFrag<(ops node:$vec, node:$val, node:$idx), + (v4i32 (vector_insert node:$vec, node:$val, node:$idx))>; + +class vfsetcc_type<ValueType ResTy, ValueType OpTy, CondCode CC> : + PatFrag<(ops node:$lhs, node:$rhs), + (ResTy (vfsetcc (OpTy node:$lhs), (OpTy node:$rhs), CC))>; + +// ISD::SETFALSE cannot occur +def vfsetoeq_v4f32 : vfsetcc_type<v4i32, v4f32, SETOEQ>; +def vfsetoeq_v2f64 : vfsetcc_type<v2i64, v2f64, SETOEQ>; +def vfsetoge_v4f32 : vfsetcc_type<v4i32, v4f32, SETOGE>; +def vfsetoge_v2f64 : vfsetcc_type<v2i64, v2f64, SETOGE>; +def vfsetogt_v4f32 : vfsetcc_type<v4i32, v4f32, SETOGT>; +def vfsetogt_v2f64 : vfsetcc_type<v2i64, v2f64, SETOGT>; +def vfsetole_v4f32 : vfsetcc_type<v4i32, v4f32, SETOLE>; +def vfsetole_v2f64 : vfsetcc_type<v2i64, v2f64, SETOLE>; +def vfsetolt_v4f32 : vfsetcc_type<v4i32, v4f32, SETOLT>; +def vfsetolt_v2f64 : vfsetcc_type<v2i64, v2f64, SETOLT>; +def vfsetone_v4f32 : vfsetcc_type<v4i32, v4f32, SETONE>; +def vfsetone_v2f64 : vfsetcc_type<v2i64, v2f64, SETONE>; +def vfsetord_v4f32 : vfsetcc_type<v4i32, v4f32, SETO>; +def vfsetord_v2f64 : vfsetcc_type<v2i64, v2f64, SETO>; +def vfsetun_v4f32 : vfsetcc_type<v4i32, v4f32, SETUO>; +def vfsetun_v2f64 : vfsetcc_type<v2i64, v2f64, SETUO>; +def vfsetueq_v4f32 : vfsetcc_type<v4i32, v4f32, SETUEQ>; +def vfsetueq_v2f64 : vfsetcc_type<v2i64, v2f64, SETUEQ>; +def vfsetuge_v4f32 : vfsetcc_type<v4i32, v4f32, SETUGE>; +def vfsetuge_v2f64 : vfsetcc_type<v2i64, v2f64, SETUGE>; +def vfsetugt_v4f32 : vfsetcc_type<v4i32, v4f32, SETUGT>; +def vfsetugt_v2f64 : vfsetcc_type<v2i64, v2f64, SETUGT>; +def vfsetule_v4f32 : vfsetcc_type<v4i32, v4f32, SETULE>; +def vfsetule_v2f64 : vfsetcc_type<v2i64, v2f64, SETULE>; +def vfsetult_v4f32 : vfsetcc_type<v4i32, v4f32, SETULT>; +def vfsetult_v2f64 : vfsetcc_type<v2i64, v2f64, SETULT>; +def vfsetune_v4f32 : vfsetcc_type<v4i32, v4f32, SETUNE>; +def vfsetune_v2f64 : vfsetcc_type<v2i64, v2f64, SETUNE>; +// ISD::SETTRUE cannot occur +// ISD::SETFALSE2 cannot occur +// ISD::SETTRUE2 cannot occur + +class vsetcc_type<ValueType ResTy, CondCode CC> : + PatFrag<(ops node:$lhs, node:$rhs), + (ResTy (vsetcc node:$lhs, node:$rhs, CC))>; + +def vseteq_v16i8 : vsetcc_type<v16i8, SETEQ>; +def vseteq_v8i16 : vsetcc_type<v8i16, SETEQ>; +def vseteq_v4i32 : vsetcc_type<v4i32, SETEQ>; +def vseteq_v2i64 : vsetcc_type<v2i64, SETEQ>; +def vsetle_v16i8 : vsetcc_type<v16i8, SETLE>; +def vsetle_v8i16 : vsetcc_type<v8i16, SETLE>; +def vsetle_v4i32 : vsetcc_type<v4i32, SETLE>; +def vsetle_v2i64 : vsetcc_type<v2i64, SETLE>; +def vsetlt_v16i8 : vsetcc_type<v16i8, SETLT>; +def vsetlt_v8i16 : vsetcc_type<v8i16, SETLT>; +def vsetlt_v4i32 : vsetcc_type<v4i32, SETLT>; +def vsetlt_v2i64 : vsetcc_type<v2i64, SETLT>; +def vsetule_v16i8 : vsetcc_type<v16i8, SETULE>; +def vsetule_v8i16 : vsetcc_type<v8i16, SETULE>; +def vsetule_v4i32 : vsetcc_type<v4i32, SETULE>; +def vsetule_v2i64 : vsetcc_type<v2i64, SETULE>; +def vsetult_v16i8 : vsetcc_type<v16i8, SETULT>; +def vsetult_v8i16 : vsetcc_type<v8i16, SETULT>; +def vsetult_v4i32 : vsetcc_type<v4i32, SETULT>; +def vsetult_v2i64 : vsetcc_type<v2i64, SETULT>; + +def vsplati8 : PatFrag<(ops node:$e0), + (v16i8 (build_vector node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0))>; +def vsplati16 : PatFrag<(ops node:$e0), + (v8i16 (build_vector node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0, + node:$e0, node:$e0))>; +def vsplati32 : PatFrag<(ops node:$e0), + (v4i32 (build_vector node:$e0, node:$e0, + node:$e0, node:$e0))>; +def vsplati64 : PatFrag<(ops node:$e0), + (v2i64 (build_vector:$v0 node:$e0, node:$e0))>; +def vsplatf32 : PatFrag<(ops node:$e0), + (v4f32 (build_vector node:$e0, node:$e0, + node:$e0, node:$e0))>; +def vsplatf64 : PatFrag<(ops node:$e0), + (v2f64 (build_vector node:$e0, node:$e0))>; + +def vsplati8_elt : PatFrag<(ops node:$v, node:$i), + (MipsVSHF (vsplati8 node:$i), node:$v, node:$v)>; +def vsplati16_elt : PatFrag<(ops node:$v, node:$i), + (MipsVSHF (vsplati16 node:$i), node:$v, node:$v)>; +def vsplati32_elt : PatFrag<(ops node:$v, node:$i), + (MipsVSHF (vsplati32 node:$i), node:$v, node:$v)>; +def vsplati64_elt : PatFrag<(ops node:$v, node:$i), + (MipsVSHF (vsplati64 node:$i), node:$v, node:$v)>; + +class SplatPatLeaf<Operand opclass, dag frag, code pred = [{}], + SDNodeXForm xform = NOOP_SDNodeXForm> + : PatLeaf<frag, pred, xform> { + Operand OpClass = opclass; +} + +class SplatComplexPattern<Operand opclass, ValueType ty, int numops, string fn, + list<SDNode> roots = [], + list<SDNodeProperty> props = []> : + ComplexPattern<ty, numops, fn, roots, props> { + Operand OpClass = opclass; +} + +def vsplati8_uimm3 : SplatComplexPattern<vsplat_uimm3, v16i8, 1, + "selectVSplatUimm3", + [build_vector, bitconvert]>; + +def vsplati8_uimm4 : SplatComplexPattern<vsplat_uimm4, v16i8, 1, + "selectVSplatUimm4", + [build_vector, bitconvert]>; + +def vsplati8_uimm5 : SplatComplexPattern<vsplat_uimm5, v16i8, 1, + "selectVSplatUimm5", + [build_vector, bitconvert]>; + +def vsplati8_uimm8 : SplatComplexPattern<vsplat_uimm8, v16i8, 1, + "selectVSplatUimm8", + [build_vector, bitconvert]>; + +def vsplati8_simm5 : SplatComplexPattern<vsplat_simm5, v16i8, 1, + "selectVSplatSimm5", + [build_vector, bitconvert]>; + +def vsplati16_uimm3 : SplatComplexPattern<vsplat_uimm3, v8i16, 1, + "selectVSplatUimm3", + [build_vector, bitconvert]>; + +def vsplati16_uimm4 : SplatComplexPattern<vsplat_uimm4, v8i16, 1, + "selectVSplatUimm4", + [build_vector, bitconvert]>; + +def vsplati16_uimm5 : SplatComplexPattern<vsplat_uimm5, v8i16, 1, + "selectVSplatUimm5", + [build_vector, bitconvert]>; + +def vsplati16_simm5 : SplatComplexPattern<vsplat_simm5, v8i16, 1, + "selectVSplatSimm5", + [build_vector, bitconvert]>; + +def vsplati32_uimm2 : SplatComplexPattern<vsplat_uimm2, v4i32, 1, + "selectVSplatUimm2", + [build_vector, bitconvert]>; + +def vsplati32_uimm5 : SplatComplexPattern<vsplat_uimm5, v4i32, 1, + "selectVSplatUimm5", + [build_vector, bitconvert]>; + +def vsplati32_simm5 : SplatComplexPattern<vsplat_simm5, v4i32, 1, + "selectVSplatSimm5", + [build_vector, bitconvert]>; + +def vsplati64_uimm1 : SplatComplexPattern<vsplat_uimm1, v2i64, 1, + "selectVSplatUimm1", + [build_vector, bitconvert]>; + +def vsplati64_uimm5 : SplatComplexPattern<vsplat_uimm5, v2i64, 1, + "selectVSplatUimm5", + [build_vector, bitconvert]>; + +def vsplati64_uimm6 : SplatComplexPattern<vsplat_uimm6, v2i64, 1, + "selectVSplatUimm6", + [build_vector, bitconvert]>; + +def vsplati64_simm5 : SplatComplexPattern<vsplat_simm5, v2i64, 1, + "selectVSplatSimm5", + [build_vector, bitconvert]>; + +// Any build_vector that is a constant splat with a value that is an exact +// power of 2 +def vsplat_uimm_pow2 : ComplexPattern<vAny, 1, "selectVSplatUimmPow2", + [build_vector, bitconvert]>; + +// Any build_vector that is a constant splat with a value that is the bitwise +// inverse of an exact power of 2 +def vsplat_uimm_inv_pow2 : ComplexPattern<vAny, 1, "selectVSplatUimmInvPow2", + [build_vector, bitconvert]>; + +// Any build_vector that is a constant splat with only a consecutive sequence +// of left-most bits set. +def vsplat_maskl_bits : SplatComplexPattern<vsplat_uimm8, vAny, 1, + "selectVSplatMaskL", + [build_vector, bitconvert]>; + +// Any build_vector that is a constant splat with only a consecutive sequence +// of right-most bits set. +def vsplat_maskr_bits : SplatComplexPattern<vsplat_uimm8, vAny, 1, + "selectVSplatMaskR", + [build_vector, bitconvert]>; + +// Any build_vector that is a constant splat with a value that equals 1 +// FIXME: These should be a ComplexPattern but we can't use them because the +// ISel generator requires the uses to have a name, but providing a name +// causes other errors ("used in pattern but not operand list") +def vsplat_imm_eq_1 : PatLeaf<(build_vector), [{ + APInt Imm; + EVT EltTy = N->getValueType(0).getVectorElementType(); + + return selectVSplat (N, Imm) && + Imm.getBitWidth() == EltTy.getSizeInBits() && Imm == 1; +}]>; + +def vsplati64_imm_eq_1 : PatLeaf<(bitconvert (v4i32 (build_vector))), [{ + APInt Imm; + SDNode *BV = N->getOperand(0).getNode(); + EVT EltTy = N->getValueType(0).getVectorElementType(); + + return selectVSplat (BV, Imm) && + Imm.getBitWidth() == EltTy.getSizeInBits() && Imm == 1; +}]>; + +def vbclr_b : PatFrag<(ops node:$ws, node:$wt), + (and node:$ws, (xor (shl vsplat_imm_eq_1, node:$wt), + immAllOnesV))>; +def vbclr_h : PatFrag<(ops node:$ws, node:$wt), + (and node:$ws, (xor (shl vsplat_imm_eq_1, node:$wt), + immAllOnesV))>; +def vbclr_w : PatFrag<(ops node:$ws, node:$wt), + (and node:$ws, (xor (shl vsplat_imm_eq_1, node:$wt), + immAllOnesV))>; +def vbclr_d : PatFrag<(ops node:$ws, node:$wt), + (and node:$ws, (xor (shl (v2i64 vsplati64_imm_eq_1), + node:$wt), + (bitconvert (v4i32 immAllOnesV))))>; + +def vbneg_b : PatFrag<(ops node:$ws, node:$wt), + (xor node:$ws, (shl vsplat_imm_eq_1, node:$wt))>; +def vbneg_h : PatFrag<(ops node:$ws, node:$wt), + (xor node:$ws, (shl vsplat_imm_eq_1, node:$wt))>; +def vbneg_w : PatFrag<(ops node:$ws, node:$wt), + (xor node:$ws, (shl vsplat_imm_eq_1, node:$wt))>; +def vbneg_d : PatFrag<(ops node:$ws, node:$wt), + (xor node:$ws, (shl (v2i64 vsplati64_imm_eq_1), + node:$wt))>; + +def vbset_b : PatFrag<(ops node:$ws, node:$wt), + (or node:$ws, (shl vsplat_imm_eq_1, node:$wt))>; +def vbset_h : PatFrag<(ops node:$ws, node:$wt), + (or node:$ws, (shl vsplat_imm_eq_1, node:$wt))>; +def vbset_w : PatFrag<(ops node:$ws, node:$wt), + (or node:$ws, (shl vsplat_imm_eq_1, node:$wt))>; +def vbset_d : PatFrag<(ops node:$ws, node:$wt), + (or node:$ws, (shl (v2i64 vsplati64_imm_eq_1), + node:$wt))>; + +def fms : PatFrag<(ops node:$wd, node:$ws, node:$wt), + (fsub node:$wd, (fmul node:$ws, node:$wt))>; + +def muladd : PatFrag<(ops node:$wd, node:$ws, node:$wt), + (add node:$wd, (mul node:$ws, node:$wt))>; + +def mulsub : PatFrag<(ops node:$wd, node:$ws, node:$wt), + (sub node:$wd, (mul node:$ws, node:$wt))>; + +def mul_fexp2 : PatFrag<(ops node:$ws, node:$wt), + (fmul node:$ws, (fexp2 node:$wt))>; + +// Immediates +def immSExt5 : ImmLeaf<i32, [{return isInt<5>(Imm);}]>; +def immSExt10: ImmLeaf<i32, [{return isInt<10>(Imm);}]>; + +// Instruction encoding. +class ADD_A_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b010000>; +class ADD_A_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b010000>; +class ADD_A_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b010000>; +class ADD_A_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b010000>; + +class ADDS_A_B_ENC : MSA_3R_FMT<0b001, 0b00, 0b010000>; +class ADDS_A_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b010000>; +class ADDS_A_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b010000>; +class ADDS_A_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b010000>; + +class ADDS_S_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b010000>; +class ADDS_S_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b010000>; +class ADDS_S_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b010000>; +class ADDS_S_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b010000>; + +class ADDS_U_B_ENC : MSA_3R_FMT<0b011, 0b00, 0b010000>; +class ADDS_U_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b010000>; +class ADDS_U_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b010000>; +class ADDS_U_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b010000>; + +class ADDV_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b001110>; +class ADDV_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b001110>; +class ADDV_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b001110>; +class ADDV_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b001110>; + +class ADDVI_B_ENC : MSA_I5_FMT<0b000, 0b00, 0b000110>; +class ADDVI_H_ENC : MSA_I5_FMT<0b000, 0b01, 0b000110>; +class ADDVI_W_ENC : MSA_I5_FMT<0b000, 0b10, 0b000110>; +class ADDVI_D_ENC : MSA_I5_FMT<0b000, 0b11, 0b000110>; + +class AND_V_ENC : MSA_VEC_FMT<0b00000, 0b011110>; + +class ANDI_B_ENC : MSA_I8_FMT<0b00, 0b000000>; + +class ASUB_S_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b010001>; +class ASUB_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b010001>; +class ASUB_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b010001>; +class ASUB_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b010001>; + +class ASUB_U_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b010001>; +class ASUB_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b010001>; +class ASUB_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b010001>; +class ASUB_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b010001>; + +class AVE_S_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b010000>; +class AVE_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b010000>; +class AVE_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b010000>; +class AVE_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b010000>; + +class AVE_U_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b010000>; +class AVE_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b010000>; +class AVE_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b010000>; +class AVE_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b010000>; + +class AVER_S_B_ENC : MSA_3R_FMT<0b110, 0b00, 0b010000>; +class AVER_S_H_ENC : MSA_3R_FMT<0b110, 0b01, 0b010000>; +class AVER_S_W_ENC : MSA_3R_FMT<0b110, 0b10, 0b010000>; +class AVER_S_D_ENC : MSA_3R_FMT<0b110, 0b11, 0b010000>; + +class AVER_U_B_ENC : MSA_3R_FMT<0b111, 0b00, 0b010000>; +class AVER_U_H_ENC : MSA_3R_FMT<0b111, 0b01, 0b010000>; +class AVER_U_W_ENC : MSA_3R_FMT<0b111, 0b10, 0b010000>; +class AVER_U_D_ENC : MSA_3R_FMT<0b111, 0b11, 0b010000>; + +class BCLR_B_ENC : MSA_3R_FMT<0b011, 0b00, 0b001101>; +class BCLR_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b001101>; +class BCLR_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b001101>; +class BCLR_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b001101>; + +class BCLRI_B_ENC : MSA_BIT_B_FMT<0b011, 0b001001>; +class BCLRI_H_ENC : MSA_BIT_H_FMT<0b011, 0b001001>; +class BCLRI_W_ENC : MSA_BIT_W_FMT<0b011, 0b001001>; +class BCLRI_D_ENC : MSA_BIT_D_FMT<0b011, 0b001001>; + +class BINSL_B_ENC : MSA_3R_FMT<0b110, 0b00, 0b001101>; +class BINSL_H_ENC : MSA_3R_FMT<0b110, 0b01, 0b001101>; +class BINSL_W_ENC : MSA_3R_FMT<0b110, 0b10, 0b001101>; +class BINSL_D_ENC : MSA_3R_FMT<0b110, 0b11, 0b001101>; + +class BINSLI_B_ENC : MSA_BIT_B_FMT<0b110, 0b001001>; +class BINSLI_H_ENC : MSA_BIT_H_FMT<0b110, 0b001001>; +class BINSLI_W_ENC : MSA_BIT_W_FMT<0b110, 0b001001>; +class BINSLI_D_ENC : MSA_BIT_D_FMT<0b110, 0b001001>; + +class BINSR_B_ENC : MSA_3R_FMT<0b111, 0b00, 0b001101>; +class BINSR_H_ENC : MSA_3R_FMT<0b111, 0b01, 0b001101>; +class BINSR_W_ENC : MSA_3R_FMT<0b111, 0b10, 0b001101>; +class BINSR_D_ENC : MSA_3R_FMT<0b111, 0b11, 0b001101>; + +class BINSRI_B_ENC : MSA_BIT_B_FMT<0b111, 0b001001>; +class BINSRI_H_ENC : MSA_BIT_H_FMT<0b111, 0b001001>; +class BINSRI_W_ENC : MSA_BIT_W_FMT<0b111, 0b001001>; +class BINSRI_D_ENC : MSA_BIT_D_FMT<0b111, 0b001001>; + +class BMNZ_V_ENC : MSA_VEC_FMT<0b00100, 0b011110>; + +class BMNZI_B_ENC : MSA_I8_FMT<0b00, 0b000001>; + +class BMZ_V_ENC : MSA_VEC_FMT<0b00101, 0b011110>; + +class BMZI_B_ENC : MSA_I8_FMT<0b01, 0b000001>; + +class BNEG_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b001101>; +class BNEG_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b001101>; +class BNEG_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b001101>; +class BNEG_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b001101>; + +class BNEGI_B_ENC : MSA_BIT_B_FMT<0b101, 0b001001>; +class BNEGI_H_ENC : MSA_BIT_H_FMT<0b101, 0b001001>; +class BNEGI_W_ENC : MSA_BIT_W_FMT<0b101, 0b001001>; +class BNEGI_D_ENC : MSA_BIT_D_FMT<0b101, 0b001001>; + +class BNZ_B_ENC : MSA_CBRANCH_FMT<0b111, 0b00>; +class BNZ_H_ENC : MSA_CBRANCH_FMT<0b111, 0b01>; +class BNZ_W_ENC : MSA_CBRANCH_FMT<0b111, 0b10>; +class BNZ_D_ENC : MSA_CBRANCH_FMT<0b111, 0b11>; + +class BNZ_V_ENC : MSA_CBRANCH_V_FMT<0b01111>; + +class BSEL_V_ENC : MSA_VEC_FMT<0b00110, 0b011110>; + +class BSELI_B_ENC : MSA_I8_FMT<0b10, 0b000001>; + +class BSET_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b001101>; +class BSET_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b001101>; +class BSET_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b001101>; +class BSET_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b001101>; + +class BSETI_B_ENC : MSA_BIT_B_FMT<0b100, 0b001001>; +class BSETI_H_ENC : MSA_BIT_H_FMT<0b100, 0b001001>; +class BSETI_W_ENC : MSA_BIT_W_FMT<0b100, 0b001001>; +class BSETI_D_ENC : MSA_BIT_D_FMT<0b100, 0b001001>; + +class BZ_B_ENC : MSA_CBRANCH_FMT<0b110, 0b00>; +class BZ_H_ENC : MSA_CBRANCH_FMT<0b110, 0b01>; +class BZ_W_ENC : MSA_CBRANCH_FMT<0b110, 0b10>; +class BZ_D_ENC : MSA_CBRANCH_FMT<0b110, 0b11>; + +class BZ_V_ENC : MSA_CBRANCH_V_FMT<0b01011>; + +class CEQ_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b001111>; +class CEQ_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b001111>; +class CEQ_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b001111>; +class CEQ_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b001111>; + +class CEQI_B_ENC : MSA_I5_FMT<0b000, 0b00, 0b000111>; +class CEQI_H_ENC : MSA_I5_FMT<0b000, 0b01, 0b000111>; +class CEQI_W_ENC : MSA_I5_FMT<0b000, 0b10, 0b000111>; +class CEQI_D_ENC : MSA_I5_FMT<0b000, 0b11, 0b000111>; + +class CFCMSA_ENC : MSA_ELM_CFCMSA_FMT<0b0001111110, 0b011001>; + +class CLE_S_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b001111>; +class CLE_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b001111>; +class CLE_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b001111>; +class CLE_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b001111>; + +class CLE_U_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b001111>; +class CLE_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b001111>; +class CLE_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b001111>; +class CLE_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b001111>; + +class CLEI_S_B_ENC : MSA_I5_FMT<0b100, 0b00, 0b000111>; +class CLEI_S_H_ENC : MSA_I5_FMT<0b100, 0b01, 0b000111>; +class CLEI_S_W_ENC : MSA_I5_FMT<0b100, 0b10, 0b000111>; +class CLEI_S_D_ENC : MSA_I5_FMT<0b100, 0b11, 0b000111>; + +class CLEI_U_B_ENC : MSA_I5_FMT<0b101, 0b00, 0b000111>; +class CLEI_U_H_ENC : MSA_I5_FMT<0b101, 0b01, 0b000111>; +class CLEI_U_W_ENC : MSA_I5_FMT<0b101, 0b10, 0b000111>; +class CLEI_U_D_ENC : MSA_I5_FMT<0b101, 0b11, 0b000111>; + +class CLT_S_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b001111>; +class CLT_S_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b001111>; +class CLT_S_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b001111>; +class CLT_S_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b001111>; + +class CLT_U_B_ENC : MSA_3R_FMT<0b011, 0b00, 0b001111>; +class CLT_U_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b001111>; +class CLT_U_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b001111>; +class CLT_U_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b001111>; + +class CLTI_S_B_ENC : MSA_I5_FMT<0b010, 0b00, 0b000111>; +class CLTI_S_H_ENC : MSA_I5_FMT<0b010, 0b01, 0b000111>; +class CLTI_S_W_ENC : MSA_I5_FMT<0b010, 0b10, 0b000111>; +class CLTI_S_D_ENC : MSA_I5_FMT<0b010, 0b11, 0b000111>; + +class CLTI_U_B_ENC : MSA_I5_FMT<0b011, 0b00, 0b000111>; +class CLTI_U_H_ENC : MSA_I5_FMT<0b011, 0b01, 0b000111>; +class CLTI_U_W_ENC : MSA_I5_FMT<0b011, 0b10, 0b000111>; +class CLTI_U_D_ENC : MSA_I5_FMT<0b011, 0b11, 0b000111>; + +class COPY_S_B_ENC : MSA_ELM_COPY_B_FMT<0b0010, 0b011001>; +class COPY_S_H_ENC : MSA_ELM_COPY_H_FMT<0b0010, 0b011001>; +class COPY_S_W_ENC : MSA_ELM_COPY_W_FMT<0b0010, 0b011001>; + +class COPY_U_B_ENC : MSA_ELM_COPY_B_FMT<0b0011, 0b011001>; +class COPY_U_H_ENC : MSA_ELM_COPY_H_FMT<0b0011, 0b011001>; +class COPY_U_W_ENC : MSA_ELM_COPY_W_FMT<0b0011, 0b011001>; + +class CTCMSA_ENC : MSA_ELM_CTCMSA_FMT<0b0000111110, 0b011001>; + +class DIV_S_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b010010>; +class DIV_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b010010>; +class DIV_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b010010>; +class DIV_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b010010>; + +class DIV_U_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b010010>; +class DIV_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b010010>; +class DIV_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b010010>; +class DIV_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b010010>; + +class DOTP_S_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b010011>; +class DOTP_S_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b010011>; +class DOTP_S_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b010011>; + +class DOTP_U_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b010011>; +class DOTP_U_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b010011>; +class DOTP_U_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b010011>; + +class DPADD_S_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b010011>; +class DPADD_S_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b010011>; +class DPADD_S_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b010011>; + +class DPADD_U_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b010011>; +class DPADD_U_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b010011>; +class DPADD_U_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b010011>; + +class DPSUB_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b010011>; +class DPSUB_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b010011>; +class DPSUB_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b010011>; + +class DPSUB_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b010011>; +class DPSUB_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b010011>; +class DPSUB_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b010011>; + +class FADD_W_ENC : MSA_3RF_FMT<0b0000, 0b0, 0b011011>; +class FADD_D_ENC : MSA_3RF_FMT<0b0000, 0b1, 0b011011>; + +class FCAF_W_ENC : MSA_3RF_FMT<0b0000, 0b0, 0b011010>; +class FCAF_D_ENC : MSA_3RF_FMT<0b0000, 0b1, 0b011010>; + +class FCEQ_W_ENC : MSA_3RF_FMT<0b0010, 0b0, 0b011010>; +class FCEQ_D_ENC : MSA_3RF_FMT<0b0010, 0b1, 0b011010>; + +class FCLASS_W_ENC : MSA_2RF_FMT<0b110010000, 0b0, 0b011110>; +class FCLASS_D_ENC : MSA_2RF_FMT<0b110010000, 0b1, 0b011110>; + +class FCLE_W_ENC : MSA_3RF_FMT<0b0110, 0b0, 0b011010>; +class FCLE_D_ENC : MSA_3RF_FMT<0b0110, 0b1, 0b011010>; + +class FCLT_W_ENC : MSA_3RF_FMT<0b0100, 0b0, 0b011010>; +class FCLT_D_ENC : MSA_3RF_FMT<0b0100, 0b1, 0b011010>; + +class FCNE_W_ENC : MSA_3RF_FMT<0b0011, 0b0, 0b011100>; +class FCNE_D_ENC : MSA_3RF_FMT<0b0011, 0b1, 0b011100>; + +class FCOR_W_ENC : MSA_3RF_FMT<0b0001, 0b0, 0b011100>; +class FCOR_D_ENC : MSA_3RF_FMT<0b0001, 0b1, 0b011100>; + +class FCUEQ_W_ENC : MSA_3RF_FMT<0b0011, 0b0, 0b011010>; +class FCUEQ_D_ENC : MSA_3RF_FMT<0b0011, 0b1, 0b011010>; + +class FCULE_W_ENC : MSA_3RF_FMT<0b0111, 0b0, 0b011010>; +class FCULE_D_ENC : MSA_3RF_FMT<0b0111, 0b1, 0b011010>; + +class FCULT_W_ENC : MSA_3RF_FMT<0b0101, 0b0, 0b011010>; +class FCULT_D_ENC : MSA_3RF_FMT<0b0101, 0b1, 0b011010>; + +class FCUN_W_ENC : MSA_3RF_FMT<0b0001, 0b0, 0b011010>; +class FCUN_D_ENC : MSA_3RF_FMT<0b0001, 0b1, 0b011010>; + +class FCUNE_W_ENC : MSA_3RF_FMT<0b0010, 0b0, 0b011100>; +class FCUNE_D_ENC : MSA_3RF_FMT<0b0010, 0b1, 0b011100>; + +class FDIV_W_ENC : MSA_3RF_FMT<0b0011, 0b0, 0b011011>; +class FDIV_D_ENC : MSA_3RF_FMT<0b0011, 0b1, 0b011011>; + +class FEXDO_H_ENC : MSA_3RF_FMT<0b1000, 0b0, 0b011011>; +class FEXDO_W_ENC : MSA_3RF_FMT<0b1000, 0b1, 0b011011>; + +class FEXP2_W_ENC : MSA_3RF_FMT<0b0111, 0b0, 0b011011>; +class FEXP2_D_ENC : MSA_3RF_FMT<0b0111, 0b1, 0b011011>; + +class FEXUPL_W_ENC : MSA_2RF_FMT<0b110011000, 0b0, 0b011110>; +class FEXUPL_D_ENC : MSA_2RF_FMT<0b110011000, 0b1, 0b011110>; + +class FEXUPR_W_ENC : MSA_2RF_FMT<0b110011001, 0b0, 0b011110>; +class FEXUPR_D_ENC : MSA_2RF_FMT<0b110011001, 0b1, 0b011110>; + +class FFINT_S_W_ENC : MSA_2RF_FMT<0b110011110, 0b0, 0b011110>; +class FFINT_S_D_ENC : MSA_2RF_FMT<0b110011110, 0b1, 0b011110>; + +class FFINT_U_W_ENC : MSA_2RF_FMT<0b110011111, 0b0, 0b011110>; +class FFINT_U_D_ENC : MSA_2RF_FMT<0b110011111, 0b1, 0b011110>; + +class FFQL_W_ENC : MSA_2RF_FMT<0b110011010, 0b0, 0b011110>; +class FFQL_D_ENC : MSA_2RF_FMT<0b110011010, 0b1, 0b011110>; + +class FFQR_W_ENC : MSA_2RF_FMT<0b110011011, 0b0, 0b011110>; +class FFQR_D_ENC : MSA_2RF_FMT<0b110011011, 0b1, 0b011110>; + +class FILL_B_ENC : MSA_2R_FILL_FMT<0b11000000, 0b00, 0b011110>; +class FILL_H_ENC : MSA_2R_FILL_FMT<0b11000000, 0b01, 0b011110>; +class FILL_W_ENC : MSA_2R_FILL_FMT<0b11000000, 0b10, 0b011110>; + +class FLOG2_W_ENC : MSA_2RF_FMT<0b110010111, 0b0, 0b011110>; +class FLOG2_D_ENC : MSA_2RF_FMT<0b110010111, 0b1, 0b011110>; + +class FMADD_W_ENC : MSA_3RF_FMT<0b0100, 0b0, 0b011011>; +class FMADD_D_ENC : MSA_3RF_FMT<0b0100, 0b1, 0b011011>; + +class FMAX_W_ENC : MSA_3RF_FMT<0b1110, 0b0, 0b011011>; +class FMAX_D_ENC : MSA_3RF_FMT<0b1110, 0b1, 0b011011>; + +class FMAX_A_W_ENC : MSA_3RF_FMT<0b1111, 0b0, 0b011011>; +class FMAX_A_D_ENC : MSA_3RF_FMT<0b1111, 0b1, 0b011011>; + +class FMIN_W_ENC : MSA_3RF_FMT<0b1100, 0b0, 0b011011>; +class FMIN_D_ENC : MSA_3RF_FMT<0b1100, 0b1, 0b011011>; + +class FMIN_A_W_ENC : MSA_3RF_FMT<0b1101, 0b0, 0b011011>; +class FMIN_A_D_ENC : MSA_3RF_FMT<0b1101, 0b1, 0b011011>; + +class FMSUB_W_ENC : MSA_3RF_FMT<0b0101, 0b0, 0b011011>; +class FMSUB_D_ENC : MSA_3RF_FMT<0b0101, 0b1, 0b011011>; + +class FMUL_W_ENC : MSA_3RF_FMT<0b0010, 0b0, 0b011011>; +class FMUL_D_ENC : MSA_3RF_FMT<0b0010, 0b1, 0b011011>; + +class FRINT_W_ENC : MSA_2RF_FMT<0b110010110, 0b0, 0b011110>; +class FRINT_D_ENC : MSA_2RF_FMT<0b110010110, 0b1, 0b011110>; + +class FRCP_W_ENC : MSA_2RF_FMT<0b110010101, 0b0, 0b011110>; +class FRCP_D_ENC : MSA_2RF_FMT<0b110010101, 0b1, 0b011110>; + +class FRSQRT_W_ENC : MSA_2RF_FMT<0b110010100, 0b0, 0b011110>; +class FRSQRT_D_ENC : MSA_2RF_FMT<0b110010100, 0b1, 0b011110>; + +class FSAF_W_ENC : MSA_3RF_FMT<0b1000, 0b0, 0b011010>; +class FSAF_D_ENC : MSA_3RF_FMT<0b1000, 0b1, 0b011010>; + +class FSEQ_W_ENC : MSA_3RF_FMT<0b1010, 0b0, 0b011010>; +class FSEQ_D_ENC : MSA_3RF_FMT<0b1010, 0b1, 0b011010>; + +class FSLE_W_ENC : MSA_3RF_FMT<0b1110, 0b0, 0b011010>; +class FSLE_D_ENC : MSA_3RF_FMT<0b1110, 0b1, 0b011010>; + +class FSLT_W_ENC : MSA_3RF_FMT<0b1100, 0b0, 0b011010>; +class FSLT_D_ENC : MSA_3RF_FMT<0b1100, 0b1, 0b011010>; + +class FSNE_W_ENC : MSA_3RF_FMT<0b1011, 0b0, 0b011100>; +class FSNE_D_ENC : MSA_3RF_FMT<0b1011, 0b1, 0b011100>; + +class FSOR_W_ENC : MSA_3RF_FMT<0b1001, 0b0, 0b011100>; +class FSOR_D_ENC : MSA_3RF_FMT<0b1001, 0b1, 0b011100>; + +class FSQRT_W_ENC : MSA_2RF_FMT<0b110010011, 0b0, 0b011110>; +class FSQRT_D_ENC : MSA_2RF_FMT<0b110010011, 0b1, 0b011110>; + +class FSUB_W_ENC : MSA_3RF_FMT<0b0001, 0b0, 0b011011>; +class FSUB_D_ENC : MSA_3RF_FMT<0b0001, 0b1, 0b011011>; + +class FSUEQ_W_ENC : MSA_3RF_FMT<0b1011, 0b0, 0b011010>; +class FSUEQ_D_ENC : MSA_3RF_FMT<0b1011, 0b1, 0b011010>; + +class FSULE_W_ENC : MSA_3RF_FMT<0b1111, 0b0, 0b011010>; +class FSULE_D_ENC : MSA_3RF_FMT<0b1111, 0b1, 0b011010>; + +class FSULT_W_ENC : MSA_3RF_FMT<0b1101, 0b0, 0b011010>; +class FSULT_D_ENC : MSA_3RF_FMT<0b1101, 0b1, 0b011010>; + +class FSUN_W_ENC : MSA_3RF_FMT<0b1001, 0b0, 0b011010>; +class FSUN_D_ENC : MSA_3RF_FMT<0b1001, 0b1, 0b011010>; + +class FSUNE_W_ENC : MSA_3RF_FMT<0b1010, 0b0, 0b011100>; +class FSUNE_D_ENC : MSA_3RF_FMT<0b1010, 0b1, 0b011100>; + +class FTINT_S_W_ENC : MSA_2RF_FMT<0b110011100, 0b0, 0b011110>; +class FTINT_S_D_ENC : MSA_2RF_FMT<0b110011100, 0b1, 0b011110>; + +class FTINT_U_W_ENC : MSA_2RF_FMT<0b110011101, 0b0, 0b011110>; +class FTINT_U_D_ENC : MSA_2RF_FMT<0b110011101, 0b1, 0b011110>; + +class FTQ_H_ENC : MSA_3RF_FMT<0b1010, 0b0, 0b011011>; +class FTQ_W_ENC : MSA_3RF_FMT<0b1010, 0b1, 0b011011>; + +class FTRUNC_S_W_ENC : MSA_2RF_FMT<0b110010001, 0b0, 0b011110>; +class FTRUNC_S_D_ENC : MSA_2RF_FMT<0b110010001, 0b1, 0b011110>; + +class FTRUNC_U_W_ENC : MSA_2RF_FMT<0b110010010, 0b0, 0b011110>; +class FTRUNC_U_D_ENC : MSA_2RF_FMT<0b110010010, 0b1, 0b011110>; + +class HADD_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b010101>; +class HADD_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b010101>; +class HADD_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b010101>; + +class HADD_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b010101>; +class HADD_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b010101>; +class HADD_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b010101>; + +class HSUB_S_H_ENC : MSA_3R_FMT<0b110, 0b01, 0b010101>; +class HSUB_S_W_ENC : MSA_3R_FMT<0b110, 0b10, 0b010101>; +class HSUB_S_D_ENC : MSA_3R_FMT<0b110, 0b11, 0b010101>; + +class HSUB_U_H_ENC : MSA_3R_FMT<0b111, 0b01, 0b010101>; +class HSUB_U_W_ENC : MSA_3R_FMT<0b111, 0b10, 0b010101>; +class HSUB_U_D_ENC : MSA_3R_FMT<0b111, 0b11, 0b010101>; + +class ILVEV_B_ENC : MSA_3R_FMT<0b110, 0b00, 0b010100>; +class ILVEV_H_ENC : MSA_3R_FMT<0b110, 0b01, 0b010100>; +class ILVEV_W_ENC : MSA_3R_FMT<0b110, 0b10, 0b010100>; +class ILVEV_D_ENC : MSA_3R_FMT<0b110, 0b11, 0b010100>; + +class ILVL_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b010100>; +class ILVL_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b010100>; +class ILVL_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b010100>; +class ILVL_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b010100>; + +class ILVOD_B_ENC : MSA_3R_FMT<0b111, 0b00, 0b010100>; +class ILVOD_H_ENC : MSA_3R_FMT<0b111, 0b01, 0b010100>; +class ILVOD_W_ENC : MSA_3R_FMT<0b111, 0b10, 0b010100>; +class ILVOD_D_ENC : MSA_3R_FMT<0b111, 0b11, 0b010100>; + +class ILVR_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b010100>; +class ILVR_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b010100>; +class ILVR_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b010100>; +class ILVR_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b010100>; + +class INSERT_B_ENC : MSA_ELM_INSERT_B_FMT<0b0100, 0b011001>; +class INSERT_H_ENC : MSA_ELM_INSERT_H_FMT<0b0100, 0b011001>; +class INSERT_W_ENC : MSA_ELM_INSERT_W_FMT<0b0100, 0b011001>; + +class INSVE_B_ENC : MSA_ELM_B_FMT<0b0101, 0b011001>; +class INSVE_H_ENC : MSA_ELM_H_FMT<0b0101, 0b011001>; +class INSVE_W_ENC : MSA_ELM_W_FMT<0b0101, 0b011001>; +class INSVE_D_ENC : MSA_ELM_D_FMT<0b0101, 0b011001>; + +class LD_B_ENC : MSA_MI10_FMT<0b00, 0b1000>; +class LD_H_ENC : MSA_MI10_FMT<0b01, 0b1000>; +class LD_W_ENC : MSA_MI10_FMT<0b10, 0b1000>; +class LD_D_ENC : MSA_MI10_FMT<0b11, 0b1000>; + +class LDI_B_ENC : MSA_I10_FMT<0b110, 0b00, 0b000111>; +class LDI_H_ENC : MSA_I10_FMT<0b110, 0b01, 0b000111>; +class LDI_W_ENC : MSA_I10_FMT<0b110, 0b10, 0b000111>; +class LDI_D_ENC : MSA_I10_FMT<0b110, 0b11, 0b000111>; + +class LSA_ENC : SPECIAL_LSA_FMT<0b000101>; + +class MADD_Q_H_ENC : MSA_3RF_FMT<0b0101, 0b0, 0b011100>; +class MADD_Q_W_ENC : MSA_3RF_FMT<0b0101, 0b1, 0b011100>; + +class MADDR_Q_H_ENC : MSA_3RF_FMT<0b1101, 0b0, 0b011100>; +class MADDR_Q_W_ENC : MSA_3RF_FMT<0b1101, 0b1, 0b011100>; + +class MADDV_B_ENC : MSA_3R_FMT<0b001, 0b00, 0b010010>; +class MADDV_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b010010>; +class MADDV_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b010010>; +class MADDV_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b010010>; + +class MAX_A_B_ENC : MSA_3R_FMT<0b110, 0b00, 0b001110>; +class MAX_A_H_ENC : MSA_3R_FMT<0b110, 0b01, 0b001110>; +class MAX_A_W_ENC : MSA_3R_FMT<0b110, 0b10, 0b001110>; +class MAX_A_D_ENC : MSA_3R_FMT<0b110, 0b11, 0b001110>; + +class MAX_S_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b001110>; +class MAX_S_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b001110>; +class MAX_S_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b001110>; +class MAX_S_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b001110>; + +class MAX_U_B_ENC : MSA_3R_FMT<0b011, 0b00, 0b001110>; +class MAX_U_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b001110>; +class MAX_U_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b001110>; +class MAX_U_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b001110>; + +class MAXI_S_B_ENC : MSA_I5_FMT<0b010, 0b00, 0b000110>; +class MAXI_S_H_ENC : MSA_I5_FMT<0b010, 0b01, 0b000110>; +class MAXI_S_W_ENC : MSA_I5_FMT<0b010, 0b10, 0b000110>; +class MAXI_S_D_ENC : MSA_I5_FMT<0b010, 0b11, 0b000110>; + +class MAXI_U_B_ENC : MSA_I5_FMT<0b011, 0b00, 0b000110>; +class MAXI_U_H_ENC : MSA_I5_FMT<0b011, 0b01, 0b000110>; +class MAXI_U_W_ENC : MSA_I5_FMT<0b011, 0b10, 0b000110>; +class MAXI_U_D_ENC : MSA_I5_FMT<0b011, 0b11, 0b000110>; + +class MIN_A_B_ENC : MSA_3R_FMT<0b111, 0b00, 0b001110>; +class MIN_A_H_ENC : MSA_3R_FMT<0b111, 0b01, 0b001110>; +class MIN_A_W_ENC : MSA_3R_FMT<0b111, 0b10, 0b001110>; +class MIN_A_D_ENC : MSA_3R_FMT<0b111, 0b11, 0b001110>; + +class MIN_S_B_ENC : MSA_3R_FMT<0b100, 0b00, 0b001110>; +class MIN_S_H_ENC : MSA_3R_FMT<0b100, 0b01, 0b001110>; +class MIN_S_W_ENC : MSA_3R_FMT<0b100, 0b10, 0b001110>; +class MIN_S_D_ENC : MSA_3R_FMT<0b100, 0b11, 0b001110>; + +class MIN_U_B_ENC : MSA_3R_FMT<0b101, 0b00, 0b001110>; +class MIN_U_H_ENC : MSA_3R_FMT<0b101, 0b01, 0b001110>; +class MIN_U_W_ENC : MSA_3R_FMT<0b101, 0b10, 0b001110>; +class MIN_U_D_ENC : MSA_3R_FMT<0b101, 0b11, 0b001110>; + +class MINI_S_B_ENC : MSA_I5_FMT<0b100, 0b00, 0b000110>; +class MINI_S_H_ENC : MSA_I5_FMT<0b100, 0b01, 0b000110>; +class MINI_S_W_ENC : MSA_I5_FMT<0b100, 0b10, 0b000110>; +class MINI_S_D_ENC : MSA_I5_FMT<0b100, 0b11, 0b000110>; + +class MINI_U_B_ENC : MSA_I5_FMT<0b101, 0b00, 0b000110>; +class MINI_U_H_ENC : MSA_I5_FMT<0b101, 0b01, 0b000110>; +class MINI_U_W_ENC : MSA_I5_FMT<0b101, 0b10, 0b000110>; +class MINI_U_D_ENC : MSA_I5_FMT<0b101, 0b11, 0b000110>; + +class MOD_S_B_ENC : MSA_3R_FMT<0b110, 0b00, 0b010010>; +class MOD_S_H_ENC : MSA_3R_FMT<0b110, 0b01, 0b010010>; +class MOD_S_W_ENC : MSA_3R_FMT<0b110, 0b10, 0b010010>; +class MOD_S_D_ENC : MSA_3R_FMT<0b110, 0b11, 0b010010>; + +class MOD_U_B_ENC : MSA_3R_FMT<0b111, 0b00, 0b010010>; +class MOD_U_H_ENC : MSA_3R_FMT<0b111, 0b01, 0b010010>; +class MOD_U_W_ENC : MSA_3R_FMT<0b111, 0b10, 0b010010>; +class MOD_U_D_ENC : MSA_3R_FMT<0b111, 0b11, 0b010010>; + +class MOVE_V_ENC : MSA_ELM_FMT<0b0010111110, 0b011001>; + +class MSUB_Q_H_ENC : MSA_3RF_FMT<0b0110, 0b0, 0b011100>; +class MSUB_Q_W_ENC : MSA_3RF_FMT<0b0110, 0b1, 0b011100>; + +class MSUBR_Q_H_ENC : MSA_3RF_FMT<0b1110, 0b0, 0b011100>; +class MSUBR_Q_W_ENC : MSA_3RF_FMT<0b1110, 0b1, 0b011100>; + +class MSUBV_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b010010>; +class MSUBV_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b010010>; +class MSUBV_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b010010>; +class MSUBV_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b010010>; + +class MUL_Q_H_ENC : MSA_3RF_FMT<0b0100, 0b0, 0b011100>; +class MUL_Q_W_ENC : MSA_3RF_FMT<0b0100, 0b1, 0b011100>; + +class MULR_Q_H_ENC : MSA_3RF_FMT<0b1100, 0b0, 0b011100>; +class MULR_Q_W_ENC : MSA_3RF_FMT<0b1100, 0b1, 0b011100>; + +class MULV_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b010010>; +class MULV_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b010010>; +class MULV_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b010010>; +class MULV_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b010010>; + +class NLOC_B_ENC : MSA_2R_FMT<0b11000010, 0b00, 0b011110>; +class NLOC_H_ENC : MSA_2R_FMT<0b11000010, 0b01, 0b011110>; +class NLOC_W_ENC : MSA_2R_FMT<0b11000010, 0b10, 0b011110>; +class NLOC_D_ENC : MSA_2R_FMT<0b11000010, 0b11, 0b011110>; + +class NLZC_B_ENC : MSA_2R_FMT<0b11000011, 0b00, 0b011110>; +class NLZC_H_ENC : MSA_2R_FMT<0b11000011, 0b01, 0b011110>; +class NLZC_W_ENC : MSA_2R_FMT<0b11000011, 0b10, 0b011110>; +class NLZC_D_ENC : MSA_2R_FMT<0b11000011, 0b11, 0b011110>; + +class NOR_V_ENC : MSA_VEC_FMT<0b00010, 0b011110>; + +class NORI_B_ENC : MSA_I8_FMT<0b10, 0b000000>; + +class OR_V_ENC : MSA_VEC_FMT<0b00001, 0b011110>; + +class ORI_B_ENC : MSA_I8_FMT<0b01, 0b000000>; + +class PCKEV_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b010100>; +class PCKEV_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b010100>; +class PCKEV_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b010100>; +class PCKEV_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b010100>; + +class PCKOD_B_ENC : MSA_3R_FMT<0b011, 0b00, 0b010100>; +class PCKOD_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b010100>; +class PCKOD_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b010100>; +class PCKOD_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b010100>; + +class PCNT_B_ENC : MSA_2R_FMT<0b11000001, 0b00, 0b011110>; +class PCNT_H_ENC : MSA_2R_FMT<0b11000001, 0b01, 0b011110>; +class PCNT_W_ENC : MSA_2R_FMT<0b11000001, 0b10, 0b011110>; +class PCNT_D_ENC : MSA_2R_FMT<0b11000001, 0b11, 0b011110>; + +class SAT_S_B_ENC : MSA_BIT_B_FMT<0b000, 0b001010>; +class SAT_S_H_ENC : MSA_BIT_H_FMT<0b000, 0b001010>; +class SAT_S_W_ENC : MSA_BIT_W_FMT<0b000, 0b001010>; +class SAT_S_D_ENC : MSA_BIT_D_FMT<0b000, 0b001010>; + +class SAT_U_B_ENC : MSA_BIT_B_FMT<0b001, 0b001010>; +class SAT_U_H_ENC : MSA_BIT_H_FMT<0b001, 0b001010>; +class SAT_U_W_ENC : MSA_BIT_W_FMT<0b001, 0b001010>; +class SAT_U_D_ENC : MSA_BIT_D_FMT<0b001, 0b001010>; + +class SHF_B_ENC : MSA_I8_FMT<0b00, 0b000010>; +class SHF_H_ENC : MSA_I8_FMT<0b01, 0b000010>; +class SHF_W_ENC : MSA_I8_FMT<0b10, 0b000010>; + +class SLD_B_ENC : MSA_3R_INDEX_FMT<0b000, 0b00, 0b010100>; +class SLD_H_ENC : MSA_3R_INDEX_FMT<0b000, 0b01, 0b010100>; +class SLD_W_ENC : MSA_3R_INDEX_FMT<0b000, 0b10, 0b010100>; +class SLD_D_ENC : MSA_3R_INDEX_FMT<0b000, 0b11, 0b010100>; + +class SLDI_B_ENC : MSA_ELM_B_FMT<0b0000, 0b011001>; +class SLDI_H_ENC : MSA_ELM_H_FMT<0b0000, 0b011001>; +class SLDI_W_ENC : MSA_ELM_W_FMT<0b0000, 0b011001>; +class SLDI_D_ENC : MSA_ELM_D_FMT<0b0000, 0b011001>; + +class SLL_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b001101>; +class SLL_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b001101>; +class SLL_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b001101>; +class SLL_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b001101>; + +class SLLI_B_ENC : MSA_BIT_B_FMT<0b000, 0b001001>; +class SLLI_H_ENC : MSA_BIT_H_FMT<0b000, 0b001001>; +class SLLI_W_ENC : MSA_BIT_W_FMT<0b000, 0b001001>; +class SLLI_D_ENC : MSA_BIT_D_FMT<0b000, 0b001001>; + +class SPLAT_B_ENC : MSA_3R_INDEX_FMT<0b001, 0b00, 0b010100>; +class SPLAT_H_ENC : MSA_3R_INDEX_FMT<0b001, 0b01, 0b010100>; +class SPLAT_W_ENC : MSA_3R_INDEX_FMT<0b001, 0b10, 0b010100>; +class SPLAT_D_ENC : MSA_3R_INDEX_FMT<0b001, 0b11, 0b010100>; + +class SPLATI_B_ENC : MSA_ELM_B_FMT<0b0001, 0b011001>; +class SPLATI_H_ENC : MSA_ELM_H_FMT<0b0001, 0b011001>; +class SPLATI_W_ENC : MSA_ELM_W_FMT<0b0001, 0b011001>; +class SPLATI_D_ENC : MSA_ELM_D_FMT<0b0001, 0b011001>; + +class SRA_B_ENC : MSA_3R_FMT<0b001, 0b00, 0b001101>; +class SRA_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b001101>; +class SRA_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b001101>; +class SRA_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b001101>; + +class SRAI_B_ENC : MSA_BIT_B_FMT<0b001, 0b001001>; +class SRAI_H_ENC : MSA_BIT_H_FMT<0b001, 0b001001>; +class SRAI_W_ENC : MSA_BIT_W_FMT<0b001, 0b001001>; +class SRAI_D_ENC : MSA_BIT_D_FMT<0b001, 0b001001>; + +class SRAR_B_ENC : MSA_3R_FMT<0b001, 0b00, 0b010101>; +class SRAR_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b010101>; +class SRAR_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b010101>; +class SRAR_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b010101>; + +class SRARI_B_ENC : MSA_BIT_B_FMT<0b010, 0b001010>; +class SRARI_H_ENC : MSA_BIT_H_FMT<0b010, 0b001010>; +class SRARI_W_ENC : MSA_BIT_W_FMT<0b010, 0b001010>; +class SRARI_D_ENC : MSA_BIT_D_FMT<0b010, 0b001010>; + +class SRL_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b001101>; +class SRL_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b001101>; +class SRL_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b001101>; +class SRL_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b001101>; + +class SRLI_B_ENC : MSA_BIT_B_FMT<0b010, 0b001001>; +class SRLI_H_ENC : MSA_BIT_H_FMT<0b010, 0b001001>; +class SRLI_W_ENC : MSA_BIT_W_FMT<0b010, 0b001001>; +class SRLI_D_ENC : MSA_BIT_D_FMT<0b010, 0b001001>; + +class SRLR_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b010101>; +class SRLR_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b010101>; +class SRLR_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b010101>; +class SRLR_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b010101>; + +class SRLRI_B_ENC : MSA_BIT_B_FMT<0b011, 0b001010>; +class SRLRI_H_ENC : MSA_BIT_H_FMT<0b011, 0b001010>; +class SRLRI_W_ENC : MSA_BIT_W_FMT<0b011, 0b001010>; +class SRLRI_D_ENC : MSA_BIT_D_FMT<0b011, 0b001010>; + +class ST_B_ENC : MSA_MI10_FMT<0b00, 0b1001>; +class ST_H_ENC : MSA_MI10_FMT<0b01, 0b1001>; +class ST_W_ENC : MSA_MI10_FMT<0b10, 0b1001>; +class ST_D_ENC : MSA_MI10_FMT<0b11, 0b1001>; + +class SUBS_S_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b010001>; +class SUBS_S_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b010001>; +class SUBS_S_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b010001>; +class SUBS_S_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b010001>; + +class SUBS_U_B_ENC : MSA_3R_FMT<0b001, 0b00, 0b010001>; +class SUBS_U_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b010001>; +class SUBS_U_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b010001>; +class SUBS_U_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b010001>; + +class SUBSUS_U_B_ENC : MSA_3R_FMT<0b010, 0b00, 0b010001>; +class SUBSUS_U_H_ENC : MSA_3R_FMT<0b010, 0b01, 0b010001>; +class SUBSUS_U_W_ENC : MSA_3R_FMT<0b010, 0b10, 0b010001>; +class SUBSUS_U_D_ENC : MSA_3R_FMT<0b010, 0b11, 0b010001>; + +class SUBSUU_S_B_ENC : MSA_3R_FMT<0b011, 0b00, 0b010001>; +class SUBSUU_S_H_ENC : MSA_3R_FMT<0b011, 0b01, 0b010001>; +class SUBSUU_S_W_ENC : MSA_3R_FMT<0b011, 0b10, 0b010001>; +class SUBSUU_S_D_ENC : MSA_3R_FMT<0b011, 0b11, 0b010001>; + +class SUBV_B_ENC : MSA_3R_FMT<0b001, 0b00, 0b001110>; +class SUBV_H_ENC : MSA_3R_FMT<0b001, 0b01, 0b001110>; +class SUBV_W_ENC : MSA_3R_FMT<0b001, 0b10, 0b001110>; +class SUBV_D_ENC : MSA_3R_FMT<0b001, 0b11, 0b001110>; + +class SUBVI_B_ENC : MSA_I5_FMT<0b001, 0b00, 0b000110>; +class SUBVI_H_ENC : MSA_I5_FMT<0b001, 0b01, 0b000110>; +class SUBVI_W_ENC : MSA_I5_FMT<0b001, 0b10, 0b000110>; +class SUBVI_D_ENC : MSA_I5_FMT<0b001, 0b11, 0b000110>; + +class VSHF_B_ENC : MSA_3R_FMT<0b000, 0b00, 0b010101>; +class VSHF_H_ENC : MSA_3R_FMT<0b000, 0b01, 0b010101>; +class VSHF_W_ENC : MSA_3R_FMT<0b000, 0b10, 0b010101>; +class VSHF_D_ENC : MSA_3R_FMT<0b000, 0b11, 0b010101>; + +class XOR_V_ENC : MSA_VEC_FMT<0b00011, 0b011110>; + +class XORI_B_ENC : MSA_I8_FMT<0b11, 0b000000>; + +// Instruction desc. +class MSA_BIT_B_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ComplexPattern Imm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, vsplat_uimm3:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, Imm:$m))]; + InstrItinClass Itinerary = itin; +} + +class MSA_BIT_H_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ComplexPattern Imm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, vsplat_uimm4:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, Imm:$m))]; + InstrItinClass Itinerary = itin; +} + +class MSA_BIT_W_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ComplexPattern Imm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, vsplat_uimm5:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, Imm:$m))]; + InstrItinClass Itinerary = itin; +} + +class MSA_BIT_D_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ComplexPattern Imm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, vsplat_uimm6:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, Imm:$m))]; + InstrItinClass Itinerary = itin; +} + +// This class is deprecated and will be removed soon. +class MSA_BIT_B_X_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, uimm3:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, immZExt3:$m))]; + InstrItinClass Itinerary = itin; +} + +// This class is deprecated and will be removed soon. +class MSA_BIT_H_X_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, uimm4:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, immZExt4:$m))]; + InstrItinClass Itinerary = itin; +} + +// This class is deprecated and will be removed soon. +class MSA_BIT_W_X_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, uimm5:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, immZExt5:$m))]; + InstrItinClass Itinerary = itin; +} + +// This class is deprecated and will be removed soon. +class MSA_BIT_D_X_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, uimm6:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, immZExt6:$m))]; + InstrItinClass Itinerary = itin; +} + +class MSA_BIT_BINSXI_DESC_BASE<string instr_asm, ValueType Ty, + ComplexPattern Mask, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ROWS:$ws, vsplat_uimm8:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (vselect (Ty Mask:$m), (Ty ROWD:$wd_in), + ROWS:$ws))]; + InstrItinClass Itinerary = itin; + string Constraints = "$wd = $wd_in"; +} + +class MSA_BIT_BINSLI_DESC_BASE<string instr_asm, ValueType Ty, + RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> : + MSA_BIT_BINSXI_DESC_BASE<instr_asm, Ty, vsplat_maskl_bits, ROWD, ROWS, itin>; + +class MSA_BIT_BINSRI_DESC_BASE<string instr_asm, ValueType Ty, + RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> : + MSA_BIT_BINSXI_DESC_BASE<instr_asm, Ty, vsplat_maskr_bits, ROWD, ROWS, itin>; + +class MSA_BIT_SPLAT_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + SplatComplexPattern SplatImm, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, SplatImm.OpClass:$m); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $m"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, SplatImm:$m))]; + InstrItinClass Itinerary = itin; +} + +class MSA_COPY_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ValueType VecTy, RegisterOperand ROD, + RegisterOperand ROWS, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROD:$rd); + dag InOperandList = (ins ROWS:$ws, uimm4:$n); + string AsmString = !strconcat(instr_asm, "\t$rd, $ws[$n]"); + list<dag> Pattern = [(set ROD:$rd, (OpNode (VecTy ROWS:$ws), immZExt4:$n))]; + InstrItinClass Itinerary = itin; +} + +class MSA_ELM_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, uimm4:$n); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws[$n]"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, immZExt4:$n))]; + InstrItinClass Itinerary = itin; +} + +class MSA_COPY_PSEUDO_BASE<SDPatternOperator OpNode, ValueType VecTy, + RegisterClass RCD, RegisterClass RCWS> : + MipsPseudo<(outs RCD:$wd), (ins RCWS:$ws, uimm4:$n), + [(set RCD:$wd, (OpNode (VecTy RCWS:$ws), immZExt4:$n))]> { + bit usesCustomInserter = 1; +} + +class MSA_I5_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + SplatComplexPattern SplatImm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, SplatImm.OpClass:$imm); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $imm"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, SplatImm:$imm))]; + InstrItinClass Itinerary = itin; +} + +class MSA_I8_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + SplatComplexPattern SplatImm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, SplatImm.OpClass:$u8); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $u8"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, SplatImm:$u8))]; + InstrItinClass Itinerary = itin; +} + +// This class is deprecated and will be removed in the next few patches +class MSA_I8_X_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, uimm8:$u8); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $u8"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, immZExt8:$u8))]; + InstrItinClass Itinerary = itin; +} + +class MSA_I8_SHF_DESC_BASE<string instr_asm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, uimm8:$u8); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $u8"); + list<dag> Pattern = [(set ROWD:$wd, (MipsSHF immZExt8:$u8, ROWS:$ws))]; + InstrItinClass Itinerary = itin; +} + +class MSA_I10_LDI_DESC_BASE<string instr_asm, RegisterOperand ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins vsplat_simm10:$s10); + string AsmString = !strconcat(instr_asm, "\t$wd, $s10"); + // LDI is matched using custom matching code in MipsSEISelDAGToDAG.cpp + list<dag> Pattern = []; + bit hasSideEffects = 0; + InstrItinClass Itinerary = itin; +} + +class MSA_2R_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws))]; + InstrItinClass Itinerary = itin; +} + +class MSA_2R_FILL_DESC_BASE<string instr_asm, ValueType VT, + SDPatternOperator OpNode, RegisterOperand ROWD, + RegisterOperand ROS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROS:$rs); + string AsmString = !strconcat(instr_asm, "\t$wd, $rs"); + list<dag> Pattern = [(set ROWD:$wd, (VT (OpNode ROS:$rs)))]; + InstrItinClass Itinerary = itin; +} + +class MSA_2R_FILL_PSEUDO_BASE<ValueType VT, SDPatternOperator OpNode, + RegisterClass RCWD, RegisterClass RCWS = RCWD> : + MipsPseudo<(outs RCWD:$wd), (ins RCWS:$fs), + [(set RCWD:$wd, (OpNode RCWS:$fs))]> { + let usesCustomInserter = 1; +} + +class MSA_2RF_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws))]; + InstrItinClass Itinerary = itin; +} + +class MSA_3R_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWT:$wt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $wt"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, ROWT:$wt))]; + InstrItinClass Itinerary = itin; +} + +class MSA_3R_BINSX_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ROWS:$ws, ROWT:$wt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $wt"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWD:$wd_in, ROWS:$ws, + ROWT:$wt))]; + string Constraints = "$wd = $wd_in"; + InstrItinClass Itinerary = itin; +} + +class MSA_3R_SPLAT_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, GPR32:$rt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws[$rt]"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, GPR32:$rt))]; + InstrItinClass Itinerary = itin; +} + +class MSA_3R_VSHF_DESC_BASE<string instr_asm, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ROWS:$ws, ROWT:$wt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $wt"); + list<dag> Pattern = [(set ROWD:$wd, (MipsVSHF ROWD:$wd_in, ROWS:$ws, + ROWT:$wt))]; + string Constraints = "$wd = $wd_in"; + InstrItinClass Itinerary = itin; +} + +class MSA_3R_SLD_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, GPR32:$rt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws[$rt]"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, GPR32:$rt))]; + InstrItinClass Itinerary = itin; +} + +class MSA_3R_4R_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ROWS:$ws, ROWT:$wt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $wt"); + list<dag> Pattern = [(set ROWD:$wd, + (OpNode ROWD:$wd_in, ROWS:$ws, ROWT:$wt))]; + InstrItinClass Itinerary = itin; + string Constraints = "$wd = $wd_in"; +} + +class MSA_3RF_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> : + MSA_3R_DESC_BASE<instr_asm, OpNode, ROWD, ROWS, ROWT, itin>; + +class MSA_3RF_4RF_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> : + MSA_3R_4R_DESC_BASE<instr_asm, OpNode, ROWD, ROWS, ROWT, itin>; + +class MSA_CBRANCH_DESC_BASE<string instr_asm, RegisterOperand ROWD> { + dag OutOperandList = (outs); + dag InOperandList = (ins ROWD:$wt, brtarget:$offset); + string AsmString = !strconcat(instr_asm, "\t$wt, $offset"); + list<dag> Pattern = []; + InstrItinClass Itinerary = IIBranch; + bit isBranch = 1; + bit isTerminator = 1; + bit hasDelaySlot = 1; + list<Register> Defs = [AT]; +} + +class MSA_INSERT_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROS, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, ROS:$rs, uimm6:$n); + string AsmString = !strconcat(instr_asm, "\t$wd[$n], $rs"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWD:$wd_in, + ROS:$rs, + immZExt6:$n))]; + InstrItinClass Itinerary = itin; + string Constraints = "$wd = $wd_in"; +} + +class MSA_INSERT_PSEUDO_BASE<SDPatternOperator OpNode, ValueType Ty, + RegisterOperand ROWD, RegisterOperand ROFS> : + MipsPseudo<(outs ROWD:$wd), (ins ROWD:$wd_in, uimm6:$n, ROFS:$fs), + [(set ROWD:$wd, (OpNode (Ty ROWD:$wd_in), ROFS:$fs, + immZExt6:$n))]> { + bit usesCustomInserter = 1; + string Constraints = "$wd = $wd_in"; +} + +class MSA_INSVE_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWD:$wd_in, uimm6:$n, ROWS:$ws); + string AsmString = !strconcat(instr_asm, "\t$wd[$n], $ws[0]"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWD:$wd_in, + immZExt6:$n, + ROWS:$ws))]; + InstrItinClass Itinerary = itin; + string Constraints = "$wd = $wd_in"; +} + +class MSA_VEC_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + RegisterOperand ROWD, RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, ROWT:$wt); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws, $wt"); + list<dag> Pattern = [(set ROWD:$wd, (OpNode ROWS:$ws, ROWT:$wt))]; + InstrItinClass Itinerary = itin; +} + +class MSA_ELM_SPLAT_DESC_BASE<string instr_asm, SplatComplexPattern SplatImm, + RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins ROWS:$ws, SplatImm.OpClass:$n); + string AsmString = !strconcat(instr_asm, "\t$wd, $ws[$n]"); + list<dag> Pattern = [(set ROWD:$wd, (MipsVSHF SplatImm:$n, ROWS:$ws, + ROWS:$ws))]; + InstrItinClass Itinerary = itin; +} + +class MSA_VEC_PSEUDO_BASE<SDPatternOperator OpNode, RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + RegisterOperand ROWT = ROWD> : + MipsPseudo<(outs ROWD:$wd), (ins ROWS:$ws, ROWT:$wt), + [(set ROWD:$wd, (OpNode ROWS:$ws, ROWT:$wt))]>; + +class ADD_A_B_DESC : MSA_3R_DESC_BASE<"add_a.b", int_mips_add_a_b, MSA128BOpnd>, + IsCommutable; +class ADD_A_H_DESC : MSA_3R_DESC_BASE<"add_a.h", int_mips_add_a_h, MSA128HOpnd>, + IsCommutable; +class ADD_A_W_DESC : MSA_3R_DESC_BASE<"add_a.w", int_mips_add_a_w, MSA128WOpnd>, + IsCommutable; +class ADD_A_D_DESC : MSA_3R_DESC_BASE<"add_a.d", int_mips_add_a_d, MSA128DOpnd>, + IsCommutable; + +class ADDS_A_B_DESC : MSA_3R_DESC_BASE<"adds_a.b", int_mips_adds_a_b, + MSA128BOpnd>, IsCommutable; +class ADDS_A_H_DESC : MSA_3R_DESC_BASE<"adds_a.h", int_mips_adds_a_h, + MSA128HOpnd>, IsCommutable; +class ADDS_A_W_DESC : MSA_3R_DESC_BASE<"adds_a.w", int_mips_adds_a_w, + MSA128WOpnd>, IsCommutable; +class ADDS_A_D_DESC : MSA_3R_DESC_BASE<"adds_a.d", int_mips_adds_a_d, + MSA128DOpnd>, IsCommutable; + +class ADDS_S_B_DESC : MSA_3R_DESC_BASE<"adds_s.b", int_mips_adds_s_b, + MSA128BOpnd>, IsCommutable; +class ADDS_S_H_DESC : MSA_3R_DESC_BASE<"adds_s.h", int_mips_adds_s_h, + MSA128HOpnd>, IsCommutable; +class ADDS_S_W_DESC : MSA_3R_DESC_BASE<"adds_s.w", int_mips_adds_s_w, + MSA128WOpnd>, IsCommutable; +class ADDS_S_D_DESC : MSA_3R_DESC_BASE<"adds_s.d", int_mips_adds_s_d, + MSA128DOpnd>, IsCommutable; + +class ADDS_U_B_DESC : MSA_3R_DESC_BASE<"adds_u.b", int_mips_adds_u_b, + MSA128BOpnd>, IsCommutable; +class ADDS_U_H_DESC : MSA_3R_DESC_BASE<"adds_u.h", int_mips_adds_u_h, + MSA128HOpnd>, IsCommutable; +class ADDS_U_W_DESC : MSA_3R_DESC_BASE<"adds_u.w", int_mips_adds_u_w, + MSA128WOpnd>, IsCommutable; +class ADDS_U_D_DESC : MSA_3R_DESC_BASE<"adds_u.d", int_mips_adds_u_d, + MSA128DOpnd>, IsCommutable; + +class ADDV_B_DESC : MSA_3R_DESC_BASE<"addv.b", add, MSA128BOpnd>, IsCommutable; +class ADDV_H_DESC : MSA_3R_DESC_BASE<"addv.h", add, MSA128HOpnd>, IsCommutable; +class ADDV_W_DESC : MSA_3R_DESC_BASE<"addv.w", add, MSA128WOpnd>, IsCommutable; +class ADDV_D_DESC : MSA_3R_DESC_BASE<"addv.d", add, MSA128DOpnd>, IsCommutable; + +class ADDVI_B_DESC : MSA_I5_DESC_BASE<"addvi.b", add, vsplati8_uimm5, + MSA128BOpnd>; +class ADDVI_H_DESC : MSA_I5_DESC_BASE<"addvi.h", add, vsplati16_uimm5, + MSA128HOpnd>; +class ADDVI_W_DESC : MSA_I5_DESC_BASE<"addvi.w", add, vsplati32_uimm5, + MSA128WOpnd>; +class ADDVI_D_DESC : MSA_I5_DESC_BASE<"addvi.d", add, vsplati64_uimm5, + MSA128DOpnd>; + +class AND_V_DESC : MSA_VEC_DESC_BASE<"and.v", and, MSA128BOpnd>; +class AND_V_H_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<and, MSA128HOpnd>; +class AND_V_W_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<and, MSA128WOpnd>; +class AND_V_D_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<and, MSA128DOpnd>; + +class ANDI_B_DESC : MSA_I8_DESC_BASE<"andi.b", and, vsplati8_uimm8, + MSA128BOpnd>; + +class ASUB_S_B_DESC : MSA_3R_DESC_BASE<"asub_s.b", int_mips_asub_s_b, + MSA128BOpnd>; +class ASUB_S_H_DESC : MSA_3R_DESC_BASE<"asub_s.h", int_mips_asub_s_h, + MSA128HOpnd>; +class ASUB_S_W_DESC : MSA_3R_DESC_BASE<"asub_s.w", int_mips_asub_s_w, + MSA128WOpnd>; +class ASUB_S_D_DESC : MSA_3R_DESC_BASE<"asub_s.d", int_mips_asub_s_d, + MSA128DOpnd>; + +class ASUB_U_B_DESC : MSA_3R_DESC_BASE<"asub_u.b", int_mips_asub_u_b, + MSA128BOpnd>; +class ASUB_U_H_DESC : MSA_3R_DESC_BASE<"asub_u.h", int_mips_asub_u_h, + MSA128HOpnd>; +class ASUB_U_W_DESC : MSA_3R_DESC_BASE<"asub_u.w", int_mips_asub_u_w, + MSA128WOpnd>; +class ASUB_U_D_DESC : MSA_3R_DESC_BASE<"asub_u.d", int_mips_asub_u_d, + MSA128DOpnd>; + +class AVE_S_B_DESC : MSA_3R_DESC_BASE<"ave_s.b", int_mips_ave_s_b, MSA128BOpnd>, + IsCommutable; +class AVE_S_H_DESC : MSA_3R_DESC_BASE<"ave_s.h", int_mips_ave_s_h, MSA128HOpnd>, + IsCommutable; +class AVE_S_W_DESC : MSA_3R_DESC_BASE<"ave_s.w", int_mips_ave_s_w, MSA128WOpnd>, + IsCommutable; +class AVE_S_D_DESC : MSA_3R_DESC_BASE<"ave_s.d", int_mips_ave_s_d, MSA128DOpnd>, + IsCommutable; + +class AVE_U_B_DESC : MSA_3R_DESC_BASE<"ave_u.b", int_mips_ave_u_b, MSA128BOpnd>, + IsCommutable; +class AVE_U_H_DESC : MSA_3R_DESC_BASE<"ave_u.h", int_mips_ave_u_h, MSA128HOpnd>, + IsCommutable; +class AVE_U_W_DESC : MSA_3R_DESC_BASE<"ave_u.w", int_mips_ave_u_w, MSA128WOpnd>, + IsCommutable; +class AVE_U_D_DESC : MSA_3R_DESC_BASE<"ave_u.d", int_mips_ave_u_d, MSA128DOpnd>, + IsCommutable; + +class AVER_S_B_DESC : MSA_3R_DESC_BASE<"aver_s.b", int_mips_aver_s_b, + MSA128BOpnd>, IsCommutable; +class AVER_S_H_DESC : MSA_3R_DESC_BASE<"aver_s.h", int_mips_aver_s_h, + MSA128HOpnd>, IsCommutable; +class AVER_S_W_DESC : MSA_3R_DESC_BASE<"aver_s.w", int_mips_aver_s_w, + MSA128WOpnd>, IsCommutable; +class AVER_S_D_DESC : MSA_3R_DESC_BASE<"aver_s.d", int_mips_aver_s_d, + MSA128DOpnd>, IsCommutable; + +class AVER_U_B_DESC : MSA_3R_DESC_BASE<"aver_u.b", int_mips_aver_u_b, + MSA128BOpnd>, IsCommutable; +class AVER_U_H_DESC : MSA_3R_DESC_BASE<"aver_u.h", int_mips_aver_u_h, + MSA128HOpnd>, IsCommutable; +class AVER_U_W_DESC : MSA_3R_DESC_BASE<"aver_u.w", int_mips_aver_u_w, + MSA128WOpnd>, IsCommutable; +class AVER_U_D_DESC : MSA_3R_DESC_BASE<"aver_u.d", int_mips_aver_u_d, + MSA128DOpnd>, IsCommutable; + +class BCLR_B_DESC : MSA_3R_DESC_BASE<"bclr.b", vbclr_b, MSA128BOpnd>; +class BCLR_H_DESC : MSA_3R_DESC_BASE<"bclr.h", vbclr_h, MSA128HOpnd>; +class BCLR_W_DESC : MSA_3R_DESC_BASE<"bclr.w", vbclr_w, MSA128WOpnd>; +class BCLR_D_DESC : MSA_3R_DESC_BASE<"bclr.d", vbclr_d, MSA128DOpnd>; + +class BCLRI_B_DESC : MSA_BIT_B_DESC_BASE<"bclri.b", and, vsplat_uimm_inv_pow2, + MSA128BOpnd>; +class BCLRI_H_DESC : MSA_BIT_H_DESC_BASE<"bclri.h", and, vsplat_uimm_inv_pow2, + MSA128HOpnd>; +class BCLRI_W_DESC : MSA_BIT_W_DESC_BASE<"bclri.w", and, vsplat_uimm_inv_pow2, + MSA128WOpnd>; +class BCLRI_D_DESC : MSA_BIT_D_DESC_BASE<"bclri.d", and, vsplat_uimm_inv_pow2, + MSA128DOpnd>; + +class BINSL_B_DESC : MSA_3R_BINSX_DESC_BASE<"binsl.b", int_mips_binsl_b, + MSA128BOpnd>; +class BINSL_H_DESC : MSA_3R_BINSX_DESC_BASE<"binsl.h", int_mips_binsl_h, + MSA128HOpnd>; +class BINSL_W_DESC : MSA_3R_BINSX_DESC_BASE<"binsl.w", int_mips_binsl_w, + MSA128WOpnd>; +class BINSL_D_DESC : MSA_3R_BINSX_DESC_BASE<"binsl.d", int_mips_binsl_d, + MSA128DOpnd>; + +class BINSLI_B_DESC : MSA_BIT_BINSLI_DESC_BASE<"binsli.b", v16i8, MSA128BOpnd>; +class BINSLI_H_DESC : MSA_BIT_BINSLI_DESC_BASE<"binsli.h", v8i16, MSA128HOpnd>; +class BINSLI_W_DESC : MSA_BIT_BINSLI_DESC_BASE<"binsli.w", v4i32, MSA128WOpnd>; +class BINSLI_D_DESC : MSA_BIT_BINSLI_DESC_BASE<"binsli.d", v2i64, MSA128DOpnd>; + +class BINSR_B_DESC : MSA_3R_BINSX_DESC_BASE<"binsr.b", int_mips_binsr_b, + MSA128BOpnd>; +class BINSR_H_DESC : MSA_3R_BINSX_DESC_BASE<"binsr.h", int_mips_binsr_h, + MSA128HOpnd>; +class BINSR_W_DESC : MSA_3R_BINSX_DESC_BASE<"binsr.w", int_mips_binsr_w, + MSA128WOpnd>; +class BINSR_D_DESC : MSA_3R_BINSX_DESC_BASE<"binsr.d", int_mips_binsr_d, + MSA128DOpnd>; + +class BINSRI_B_DESC : MSA_BIT_BINSRI_DESC_BASE<"binsri.b", v16i8, MSA128BOpnd>; +class BINSRI_H_DESC : MSA_BIT_BINSRI_DESC_BASE<"binsri.h", v8i16, MSA128HOpnd>; +class BINSRI_W_DESC : MSA_BIT_BINSRI_DESC_BASE<"binsri.w", v4i32, MSA128WOpnd>; +class BINSRI_D_DESC : MSA_BIT_BINSRI_DESC_BASE<"binsri.d", v2i64, MSA128DOpnd>; + +class BMNZ_V_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, + MSA128BOpnd:$wt); + string AsmString = "bmnz.v\t$wd, $ws, $wt"; + list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect MSA128BOpnd:$wt, + MSA128BOpnd:$ws, + MSA128BOpnd:$wd_in))]; + InstrItinClass Itinerary = NoItinerary; + string Constraints = "$wd = $wd_in"; +} + +class BMNZI_B_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, + vsplat_uimm8:$u8); + string AsmString = "bmnzi.b\t$wd, $ws, $u8"; + list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect vsplati8_uimm8:$u8, + MSA128BOpnd:$ws, + MSA128BOpnd:$wd_in))]; + InstrItinClass Itinerary = NoItinerary; + string Constraints = "$wd = $wd_in"; +} + +class BMZ_V_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, + MSA128BOpnd:$wt); + string AsmString = "bmz.v\t$wd, $ws, $wt"; + list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect MSA128BOpnd:$wt, + MSA128BOpnd:$wd_in, + MSA128BOpnd:$ws))]; + InstrItinClass Itinerary = NoItinerary; + string Constraints = "$wd = $wd_in"; +} + +class BMZI_B_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, + vsplat_uimm8:$u8); + string AsmString = "bmzi.b\t$wd, $ws, $u8"; + list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect vsplati8_uimm8:$u8, + MSA128BOpnd:$wd_in, + MSA128BOpnd:$ws))]; + InstrItinClass Itinerary = NoItinerary; + string Constraints = "$wd = $wd_in"; +} + +class BNEG_B_DESC : MSA_3R_DESC_BASE<"bneg.b", vbneg_b, MSA128BOpnd>; +class BNEG_H_DESC : MSA_3R_DESC_BASE<"bneg.h", vbneg_h, MSA128HOpnd>; +class BNEG_W_DESC : MSA_3R_DESC_BASE<"bneg.w", vbneg_w, MSA128WOpnd>; +class BNEG_D_DESC : MSA_3R_DESC_BASE<"bneg.d", vbneg_d, MSA128DOpnd>; + +class BNEGI_B_DESC : MSA_BIT_B_DESC_BASE<"bnegi.b", xor, vsplat_uimm_pow2, MSA128BOpnd>; +class BNEGI_H_DESC : MSA_BIT_H_DESC_BASE<"bnegi.h", xor, vsplat_uimm_pow2, MSA128HOpnd>; +class BNEGI_W_DESC : MSA_BIT_W_DESC_BASE<"bnegi.w", xor, vsplat_uimm_pow2, MSA128WOpnd>; +class BNEGI_D_DESC : MSA_BIT_D_DESC_BASE<"bnegi.d", xor, vsplat_uimm_pow2, MSA128DOpnd>; + +class BNZ_B_DESC : MSA_CBRANCH_DESC_BASE<"bnz.b", MSA128BOpnd>; +class BNZ_H_DESC : MSA_CBRANCH_DESC_BASE<"bnz.h", MSA128HOpnd>; +class BNZ_W_DESC : MSA_CBRANCH_DESC_BASE<"bnz.w", MSA128WOpnd>; +class BNZ_D_DESC : MSA_CBRANCH_DESC_BASE<"bnz.d", MSA128DOpnd>; + +class BNZ_V_DESC : MSA_CBRANCH_DESC_BASE<"bnz.v", MSA128BOpnd>; + +class BSEL_V_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, + MSA128BOpnd:$wt); + string AsmString = "bsel.v\t$wd, $ws, $wt"; + list<dag> Pattern = [(set MSA128BOpnd:$wd, + (vselect MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, + MSA128BOpnd:$wt))]; + InstrItinClass Itinerary = NoItinerary; + string Constraints = "$wd = $wd_in"; +} + +class BSELI_B_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$wd_in, MSA128BOpnd:$ws, + vsplat_uimm8:$u8); + string AsmString = "bseli.b\t$wd, $ws, $u8"; + list<dag> Pattern = [(set MSA128BOpnd:$wd, (vselect MSA128BOpnd:$wd_in, + MSA128BOpnd:$ws, + vsplati8_uimm8:$u8))]; + InstrItinClass Itinerary = NoItinerary; + string Constraints = "$wd = $wd_in"; +} + +class BSET_B_DESC : MSA_3R_DESC_BASE<"bset.b", vbset_b, MSA128BOpnd>; +class BSET_H_DESC : MSA_3R_DESC_BASE<"bset.h", vbset_h, MSA128HOpnd>; +class BSET_W_DESC : MSA_3R_DESC_BASE<"bset.w", vbset_w, MSA128WOpnd>; +class BSET_D_DESC : MSA_3R_DESC_BASE<"bset.d", vbset_d, MSA128DOpnd>; + +class BSETI_B_DESC : MSA_BIT_B_DESC_BASE<"bseti.b", or, vsplat_uimm_pow2, + MSA128BOpnd>; +class BSETI_H_DESC : MSA_BIT_H_DESC_BASE<"bseti.h", or, vsplat_uimm_pow2, + MSA128HOpnd>; +class BSETI_W_DESC : MSA_BIT_W_DESC_BASE<"bseti.w", or, vsplat_uimm_pow2, + MSA128WOpnd>; +class BSETI_D_DESC : MSA_BIT_D_DESC_BASE<"bseti.d", or, vsplat_uimm_pow2, + MSA128DOpnd>; + +class BZ_B_DESC : MSA_CBRANCH_DESC_BASE<"bz.b", MSA128BOpnd>; +class BZ_H_DESC : MSA_CBRANCH_DESC_BASE<"bz.h", MSA128HOpnd>; +class BZ_W_DESC : MSA_CBRANCH_DESC_BASE<"bz.w", MSA128WOpnd>; +class BZ_D_DESC : MSA_CBRANCH_DESC_BASE<"bz.d", MSA128DOpnd>; + +class BZ_V_DESC : MSA_CBRANCH_DESC_BASE<"bz.v", MSA128BOpnd>; + +class CEQ_B_DESC : MSA_3R_DESC_BASE<"ceq.b", vseteq_v16i8, MSA128BOpnd>, + IsCommutable; +class CEQ_H_DESC : MSA_3R_DESC_BASE<"ceq.h", vseteq_v8i16, MSA128HOpnd>, + IsCommutable; +class CEQ_W_DESC : MSA_3R_DESC_BASE<"ceq.w", vseteq_v4i32, MSA128WOpnd>, + IsCommutable; +class CEQ_D_DESC : MSA_3R_DESC_BASE<"ceq.d", vseteq_v2i64, MSA128DOpnd>, + IsCommutable; + +class CEQI_B_DESC : MSA_I5_DESC_BASE<"ceqi.b", vseteq_v16i8, vsplati8_simm5, + MSA128BOpnd>; +class CEQI_H_DESC : MSA_I5_DESC_BASE<"ceqi.h", vseteq_v8i16, vsplati16_simm5, + MSA128HOpnd>; +class CEQI_W_DESC : MSA_I5_DESC_BASE<"ceqi.w", vseteq_v4i32, vsplati32_simm5, + MSA128WOpnd>; +class CEQI_D_DESC : MSA_I5_DESC_BASE<"ceqi.d", vseteq_v2i64, vsplati64_simm5, + MSA128DOpnd>; + +class CFCMSA_DESC { + dag OutOperandList = (outs GPR32Opnd:$rd); + dag InOperandList = (ins MSA128CROpnd:$cs); + string AsmString = "cfcmsa\t$rd, $cs"; + InstrItinClass Itinerary = NoItinerary; + bit hasSideEffects = 1; +} + +class CLE_S_B_DESC : MSA_3R_DESC_BASE<"cle_s.b", vsetle_v16i8, MSA128BOpnd>; +class CLE_S_H_DESC : MSA_3R_DESC_BASE<"cle_s.h", vsetle_v8i16, MSA128HOpnd>; +class CLE_S_W_DESC : MSA_3R_DESC_BASE<"cle_s.w", vsetle_v4i32, MSA128WOpnd>; +class CLE_S_D_DESC : MSA_3R_DESC_BASE<"cle_s.d", vsetle_v2i64, MSA128DOpnd>; + +class CLE_U_B_DESC : MSA_3R_DESC_BASE<"cle_u.b", vsetule_v16i8, MSA128BOpnd>; +class CLE_U_H_DESC : MSA_3R_DESC_BASE<"cle_u.h", vsetule_v8i16, MSA128HOpnd>; +class CLE_U_W_DESC : MSA_3R_DESC_BASE<"cle_u.w", vsetule_v4i32, MSA128WOpnd>; +class CLE_U_D_DESC : MSA_3R_DESC_BASE<"cle_u.d", vsetule_v2i64, MSA128DOpnd>; + +class CLEI_S_B_DESC : MSA_I5_DESC_BASE<"clei_s.b", vsetle_v16i8, + vsplati8_simm5, MSA128BOpnd>; +class CLEI_S_H_DESC : MSA_I5_DESC_BASE<"clei_s.h", vsetle_v8i16, + vsplati16_simm5, MSA128HOpnd>; +class CLEI_S_W_DESC : MSA_I5_DESC_BASE<"clei_s.w", vsetle_v4i32, + vsplati32_simm5, MSA128WOpnd>; +class CLEI_S_D_DESC : MSA_I5_DESC_BASE<"clei_s.d", vsetle_v2i64, + vsplati64_simm5, MSA128DOpnd>; + +class CLEI_U_B_DESC : MSA_I5_DESC_BASE<"clei_u.b", vsetule_v16i8, + vsplati8_uimm5, MSA128BOpnd>; +class CLEI_U_H_DESC : MSA_I5_DESC_BASE<"clei_u.h", vsetule_v8i16, + vsplati16_uimm5, MSA128HOpnd>; +class CLEI_U_W_DESC : MSA_I5_DESC_BASE<"clei_u.w", vsetule_v4i32, + vsplati32_uimm5, MSA128WOpnd>; +class CLEI_U_D_DESC : MSA_I5_DESC_BASE<"clei_u.d", vsetule_v2i64, + vsplati64_uimm5, MSA128DOpnd>; + +class CLT_S_B_DESC : MSA_3R_DESC_BASE<"clt_s.b", vsetlt_v16i8, MSA128BOpnd>; +class CLT_S_H_DESC : MSA_3R_DESC_BASE<"clt_s.h", vsetlt_v8i16, MSA128HOpnd>; +class CLT_S_W_DESC : MSA_3R_DESC_BASE<"clt_s.w", vsetlt_v4i32, MSA128WOpnd>; +class CLT_S_D_DESC : MSA_3R_DESC_BASE<"clt_s.d", vsetlt_v2i64, MSA128DOpnd>; + +class CLT_U_B_DESC : MSA_3R_DESC_BASE<"clt_u.b", vsetult_v16i8, MSA128BOpnd>; +class CLT_U_H_DESC : MSA_3R_DESC_BASE<"clt_u.h", vsetult_v8i16, MSA128HOpnd>; +class CLT_U_W_DESC : MSA_3R_DESC_BASE<"clt_u.w", vsetult_v4i32, MSA128WOpnd>; +class CLT_U_D_DESC : MSA_3R_DESC_BASE<"clt_u.d", vsetult_v2i64, MSA128DOpnd>; + +class CLTI_S_B_DESC : MSA_I5_DESC_BASE<"clti_s.b", vsetlt_v16i8, + vsplati8_simm5, MSA128BOpnd>; +class CLTI_S_H_DESC : MSA_I5_DESC_BASE<"clti_s.h", vsetlt_v8i16, + vsplati16_simm5, MSA128HOpnd>; +class CLTI_S_W_DESC : MSA_I5_DESC_BASE<"clti_s.w", vsetlt_v4i32, + vsplati32_simm5, MSA128WOpnd>; +class CLTI_S_D_DESC : MSA_I5_DESC_BASE<"clti_s.d", vsetlt_v2i64, + vsplati64_simm5, MSA128DOpnd>; + +class CLTI_U_B_DESC : MSA_I5_DESC_BASE<"clti_u.b", vsetult_v16i8, + vsplati8_uimm5, MSA128BOpnd>; +class CLTI_U_H_DESC : MSA_I5_DESC_BASE<"clti_u.h", vsetult_v8i16, + vsplati16_uimm5, MSA128HOpnd>; +class CLTI_U_W_DESC : MSA_I5_DESC_BASE<"clti_u.w", vsetult_v4i32, + vsplati32_uimm5, MSA128WOpnd>; +class CLTI_U_D_DESC : MSA_I5_DESC_BASE<"clti_u.d", vsetult_v2i64, + vsplati64_uimm5, MSA128DOpnd>; + +class COPY_S_B_DESC : MSA_COPY_DESC_BASE<"copy_s.b", vextract_sext_i8, v16i8, + GPR32Opnd, MSA128BOpnd>; +class COPY_S_H_DESC : MSA_COPY_DESC_BASE<"copy_s.h", vextract_sext_i16, v8i16, + GPR32Opnd, MSA128HOpnd>; +class COPY_S_W_DESC : MSA_COPY_DESC_BASE<"copy_s.w", vextract_sext_i32, v4i32, + GPR32Opnd, MSA128WOpnd>; + +class COPY_U_B_DESC : MSA_COPY_DESC_BASE<"copy_u.b", vextract_zext_i8, v16i8, + GPR32Opnd, MSA128BOpnd>; +class COPY_U_H_DESC : MSA_COPY_DESC_BASE<"copy_u.h", vextract_zext_i16, v8i16, + GPR32Opnd, MSA128HOpnd>; +class COPY_U_W_DESC : MSA_COPY_DESC_BASE<"copy_u.w", vextract_zext_i32, v4i32, + GPR32Opnd, MSA128WOpnd>; + +class COPY_FW_PSEUDO_DESC : MSA_COPY_PSEUDO_BASE<vector_extract, v4f32, FGR32, + MSA128W>; +class COPY_FD_PSEUDO_DESC : MSA_COPY_PSEUDO_BASE<vector_extract, v2f64, FGR64, + MSA128D>; + +class CTCMSA_DESC { + dag OutOperandList = (outs); + dag InOperandList = (ins MSA128CROpnd:$cd, GPR32Opnd:$rs); + string AsmString = "ctcmsa\t$cd, $rs"; + InstrItinClass Itinerary = NoItinerary; + bit hasSideEffects = 1; +} + +class DIV_S_B_DESC : MSA_3R_DESC_BASE<"div_s.b", sdiv, MSA128BOpnd>; +class DIV_S_H_DESC : MSA_3R_DESC_BASE<"div_s.h", sdiv, MSA128HOpnd>; +class DIV_S_W_DESC : MSA_3R_DESC_BASE<"div_s.w", sdiv, MSA128WOpnd>; +class DIV_S_D_DESC : MSA_3R_DESC_BASE<"div_s.d", sdiv, MSA128DOpnd>; + +class DIV_U_B_DESC : MSA_3R_DESC_BASE<"div_u.b", udiv, MSA128BOpnd>; +class DIV_U_H_DESC : MSA_3R_DESC_BASE<"div_u.h", udiv, MSA128HOpnd>; +class DIV_U_W_DESC : MSA_3R_DESC_BASE<"div_u.w", udiv, MSA128WOpnd>; +class DIV_U_D_DESC : MSA_3R_DESC_BASE<"div_u.d", udiv, MSA128DOpnd>; + +class DOTP_S_H_DESC : MSA_3R_DESC_BASE<"dotp_s.h", int_mips_dotp_s_h, + MSA128HOpnd, MSA128BOpnd, MSA128BOpnd>, + IsCommutable; +class DOTP_S_W_DESC : MSA_3R_DESC_BASE<"dotp_s.w", int_mips_dotp_s_w, + MSA128WOpnd, MSA128HOpnd, MSA128HOpnd>, + IsCommutable; +class DOTP_S_D_DESC : MSA_3R_DESC_BASE<"dotp_s.d", int_mips_dotp_s_d, + MSA128DOpnd, MSA128WOpnd, MSA128WOpnd>, + IsCommutable; + +class DOTP_U_H_DESC : MSA_3R_DESC_BASE<"dotp_u.h", int_mips_dotp_u_h, + MSA128HOpnd, MSA128BOpnd, MSA128BOpnd>, + IsCommutable; +class DOTP_U_W_DESC : MSA_3R_DESC_BASE<"dotp_u.w", int_mips_dotp_u_w, + MSA128WOpnd, MSA128HOpnd, MSA128HOpnd>, + IsCommutable; +class DOTP_U_D_DESC : MSA_3R_DESC_BASE<"dotp_u.d", int_mips_dotp_u_d, + MSA128DOpnd, MSA128WOpnd, MSA128WOpnd>, + IsCommutable; + +class DPADD_S_H_DESC : MSA_3R_4R_DESC_BASE<"dpadd_s.h", int_mips_dpadd_s_h, + MSA128HOpnd, MSA128BOpnd, + MSA128BOpnd>, IsCommutable; +class DPADD_S_W_DESC : MSA_3R_4R_DESC_BASE<"dpadd_s.w", int_mips_dpadd_s_w, + MSA128WOpnd, MSA128HOpnd, + MSA128HOpnd>, IsCommutable; +class DPADD_S_D_DESC : MSA_3R_4R_DESC_BASE<"dpadd_s.d", int_mips_dpadd_s_d, + MSA128DOpnd, MSA128WOpnd, + MSA128WOpnd>, IsCommutable; + +class DPADD_U_H_DESC : MSA_3R_4R_DESC_BASE<"dpadd_u.h", int_mips_dpadd_u_h, + MSA128HOpnd, MSA128BOpnd, + MSA128BOpnd>, IsCommutable; +class DPADD_U_W_DESC : MSA_3R_4R_DESC_BASE<"dpadd_u.w", int_mips_dpadd_u_w, + MSA128WOpnd, MSA128HOpnd, + MSA128HOpnd>, IsCommutable; +class DPADD_U_D_DESC : MSA_3R_4R_DESC_BASE<"dpadd_u.d", int_mips_dpadd_u_d, + MSA128DOpnd, MSA128WOpnd, + MSA128WOpnd>, IsCommutable; + +class DPSUB_S_H_DESC : MSA_3R_4R_DESC_BASE<"dpsub_s.h", int_mips_dpsub_s_h, + MSA128HOpnd, MSA128BOpnd, + MSA128BOpnd>; +class DPSUB_S_W_DESC : MSA_3R_4R_DESC_BASE<"dpsub_s.w", int_mips_dpsub_s_w, + MSA128WOpnd, MSA128HOpnd, + MSA128HOpnd>; +class DPSUB_S_D_DESC : MSA_3R_4R_DESC_BASE<"dpsub_s.d", int_mips_dpsub_s_d, + MSA128DOpnd, MSA128WOpnd, + MSA128WOpnd>; + +class DPSUB_U_H_DESC : MSA_3R_4R_DESC_BASE<"dpsub_u.h", int_mips_dpsub_u_h, + MSA128HOpnd, MSA128BOpnd, + MSA128BOpnd>; +class DPSUB_U_W_DESC : MSA_3R_4R_DESC_BASE<"dpsub_u.w", int_mips_dpsub_u_w, + MSA128WOpnd, MSA128HOpnd, + MSA128HOpnd>; +class DPSUB_U_D_DESC : MSA_3R_4R_DESC_BASE<"dpsub_u.d", int_mips_dpsub_u_d, + MSA128DOpnd, MSA128WOpnd, + MSA128WOpnd>; + +class FADD_W_DESC : MSA_3RF_DESC_BASE<"fadd.w", fadd, MSA128WOpnd>, + IsCommutable; +class FADD_D_DESC : MSA_3RF_DESC_BASE<"fadd.d", fadd, MSA128DOpnd>, + IsCommutable; + +class FCAF_W_DESC : MSA_3RF_DESC_BASE<"fcaf.w", int_mips_fcaf_w, MSA128WOpnd>, + IsCommutable; +class FCAF_D_DESC : MSA_3RF_DESC_BASE<"fcaf.d", int_mips_fcaf_d, MSA128DOpnd>, + IsCommutable; + +class FCEQ_W_DESC : MSA_3RF_DESC_BASE<"fceq.w", vfsetoeq_v4f32, MSA128WOpnd>, + IsCommutable; +class FCEQ_D_DESC : MSA_3RF_DESC_BASE<"fceq.d", vfsetoeq_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCLASS_W_DESC : MSA_2RF_DESC_BASE<"fclass.w", int_mips_fclass_w, + MSA128WOpnd>; +class FCLASS_D_DESC : MSA_2RF_DESC_BASE<"fclass.d", int_mips_fclass_d, + MSA128DOpnd>; + +class FCLE_W_DESC : MSA_3RF_DESC_BASE<"fcle.w", vfsetole_v4f32, MSA128WOpnd>; +class FCLE_D_DESC : MSA_3RF_DESC_BASE<"fcle.d", vfsetole_v2f64, MSA128DOpnd>; + +class FCLT_W_DESC : MSA_3RF_DESC_BASE<"fclt.w", vfsetolt_v4f32, MSA128WOpnd>; +class FCLT_D_DESC : MSA_3RF_DESC_BASE<"fclt.d", vfsetolt_v2f64, MSA128DOpnd>; + +class FCNE_W_DESC : MSA_3RF_DESC_BASE<"fcne.w", vfsetone_v4f32, MSA128WOpnd>, + IsCommutable; +class FCNE_D_DESC : MSA_3RF_DESC_BASE<"fcne.d", vfsetone_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCOR_W_DESC : MSA_3RF_DESC_BASE<"fcor.w", vfsetord_v4f32, MSA128WOpnd>, + IsCommutable; +class FCOR_D_DESC : MSA_3RF_DESC_BASE<"fcor.d", vfsetord_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCUEQ_W_DESC : MSA_3RF_DESC_BASE<"fcueq.w", vfsetueq_v4f32, MSA128WOpnd>, + IsCommutable; +class FCUEQ_D_DESC : MSA_3RF_DESC_BASE<"fcueq.d", vfsetueq_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCULE_W_DESC : MSA_3RF_DESC_BASE<"fcule.w", vfsetule_v4f32, MSA128WOpnd>, + IsCommutable; +class FCULE_D_DESC : MSA_3RF_DESC_BASE<"fcule.d", vfsetule_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCULT_W_DESC : MSA_3RF_DESC_BASE<"fcult.w", vfsetult_v4f32, MSA128WOpnd>, + IsCommutable; +class FCULT_D_DESC : MSA_3RF_DESC_BASE<"fcult.d", vfsetult_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCUN_W_DESC : MSA_3RF_DESC_BASE<"fcun.w", vfsetun_v4f32, MSA128WOpnd>, + IsCommutable; +class FCUN_D_DESC : MSA_3RF_DESC_BASE<"fcun.d", vfsetun_v2f64, MSA128DOpnd>, + IsCommutable; + +class FCUNE_W_DESC : MSA_3RF_DESC_BASE<"fcune.w", vfsetune_v4f32, MSA128WOpnd>, + IsCommutable; +class FCUNE_D_DESC : MSA_3RF_DESC_BASE<"fcune.d", vfsetune_v2f64, MSA128DOpnd>, + IsCommutable; + +class FDIV_W_DESC : MSA_3RF_DESC_BASE<"fdiv.w", fdiv, MSA128WOpnd>; +class FDIV_D_DESC : MSA_3RF_DESC_BASE<"fdiv.d", fdiv, MSA128DOpnd>; + +class FEXDO_H_DESC : MSA_3RF_DESC_BASE<"fexdo.h", int_mips_fexdo_h, + MSA128HOpnd, MSA128WOpnd, MSA128WOpnd>; +class FEXDO_W_DESC : MSA_3RF_DESC_BASE<"fexdo.w", int_mips_fexdo_w, + MSA128WOpnd, MSA128DOpnd, MSA128DOpnd>; + +// The fexp2.df instruction multiplies the first operand by 2 to the power of +// the second operand. We therefore need a pseudo-insn in order to invent the +// 1.0 when we only need to match ISD::FEXP2. +class FEXP2_W_DESC : MSA_3RF_DESC_BASE<"fexp2.w", mul_fexp2, MSA128WOpnd>; +class FEXP2_D_DESC : MSA_3RF_DESC_BASE<"fexp2.d", mul_fexp2, MSA128DOpnd>; +let usesCustomInserter = 1 in { + class FEXP2_W_1_PSEUDO_DESC : + MipsPseudo<(outs MSA128W:$wd), (ins MSA128W:$ws), + [(set MSA128W:$wd, (fexp2 MSA128W:$ws))]>; + class FEXP2_D_1_PSEUDO_DESC : + MipsPseudo<(outs MSA128D:$wd), (ins MSA128D:$ws), + [(set MSA128D:$wd, (fexp2 MSA128D:$ws))]>; +} + +class FEXUPL_W_DESC : MSA_2RF_DESC_BASE<"fexupl.w", int_mips_fexupl_w, + MSA128WOpnd, MSA128HOpnd>; +class FEXUPL_D_DESC : MSA_2RF_DESC_BASE<"fexupl.d", int_mips_fexupl_d, + MSA128DOpnd, MSA128WOpnd>; + +class FEXUPR_W_DESC : MSA_2RF_DESC_BASE<"fexupr.w", int_mips_fexupr_w, + MSA128WOpnd, MSA128HOpnd>; +class FEXUPR_D_DESC : MSA_2RF_DESC_BASE<"fexupr.d", int_mips_fexupr_d, + MSA128DOpnd, MSA128WOpnd>; + +class FFINT_S_W_DESC : MSA_2RF_DESC_BASE<"ffint_s.w", sint_to_fp, MSA128WOpnd>; +class FFINT_S_D_DESC : MSA_2RF_DESC_BASE<"ffint_s.d", sint_to_fp, MSA128DOpnd>; + +class FFINT_U_W_DESC : MSA_2RF_DESC_BASE<"ffint_u.w", uint_to_fp, MSA128WOpnd>; +class FFINT_U_D_DESC : MSA_2RF_DESC_BASE<"ffint_u.d", uint_to_fp, MSA128DOpnd>; + +class FFQL_W_DESC : MSA_2RF_DESC_BASE<"ffql.w", int_mips_ffql_w, + MSA128WOpnd, MSA128HOpnd>; +class FFQL_D_DESC : MSA_2RF_DESC_BASE<"ffql.d", int_mips_ffql_d, + MSA128DOpnd, MSA128WOpnd>; + +class FFQR_W_DESC : MSA_2RF_DESC_BASE<"ffqr.w", int_mips_ffqr_w, + MSA128WOpnd, MSA128HOpnd>; +class FFQR_D_DESC : MSA_2RF_DESC_BASE<"ffqr.d", int_mips_ffqr_d, + MSA128DOpnd, MSA128WOpnd>; + +class FILL_B_DESC : MSA_2R_FILL_DESC_BASE<"fill.b", v16i8, vsplati8, + MSA128BOpnd, GPR32Opnd>; +class FILL_H_DESC : MSA_2R_FILL_DESC_BASE<"fill.h", v8i16, vsplati16, + MSA128HOpnd, GPR32Opnd>; +class FILL_W_DESC : MSA_2R_FILL_DESC_BASE<"fill.w", v4i32, vsplati32, + MSA128WOpnd, GPR32Opnd>; + +class FILL_FW_PSEUDO_DESC : MSA_2R_FILL_PSEUDO_BASE<v4f32, vsplatf32, MSA128W, + FGR32>; +class FILL_FD_PSEUDO_DESC : MSA_2R_FILL_PSEUDO_BASE<v2f64, vsplatf64, MSA128D, + FGR64>; + +class FLOG2_W_DESC : MSA_2RF_DESC_BASE<"flog2.w", flog2, MSA128WOpnd>; +class FLOG2_D_DESC : MSA_2RF_DESC_BASE<"flog2.d", flog2, MSA128DOpnd>; + +class FMADD_W_DESC : MSA_3RF_4RF_DESC_BASE<"fmadd.w", fma, MSA128WOpnd>; +class FMADD_D_DESC : MSA_3RF_4RF_DESC_BASE<"fmadd.d", fma, MSA128DOpnd>; + +class FMAX_W_DESC : MSA_3RF_DESC_BASE<"fmax.w", int_mips_fmax_w, MSA128WOpnd>; +class FMAX_D_DESC : MSA_3RF_DESC_BASE<"fmax.d", int_mips_fmax_d, MSA128DOpnd>; + +class FMAX_A_W_DESC : MSA_3RF_DESC_BASE<"fmax_a.w", int_mips_fmax_a_w, + MSA128WOpnd>; +class FMAX_A_D_DESC : MSA_3RF_DESC_BASE<"fmax_a.d", int_mips_fmax_a_d, + MSA128DOpnd>; + +class FMIN_W_DESC : MSA_3RF_DESC_BASE<"fmin.w", int_mips_fmin_w, MSA128WOpnd>; +class FMIN_D_DESC : MSA_3RF_DESC_BASE<"fmin.d", int_mips_fmin_d, MSA128DOpnd>; + +class FMIN_A_W_DESC : MSA_3RF_DESC_BASE<"fmin_a.w", int_mips_fmin_a_w, + MSA128WOpnd>; +class FMIN_A_D_DESC : MSA_3RF_DESC_BASE<"fmin_a.d", int_mips_fmin_a_d, + MSA128DOpnd>; + +class FMSUB_W_DESC : MSA_3RF_4RF_DESC_BASE<"fmsub.w", fms, MSA128WOpnd>; +class FMSUB_D_DESC : MSA_3RF_4RF_DESC_BASE<"fmsub.d", fms, MSA128DOpnd>; + +class FMUL_W_DESC : MSA_3RF_DESC_BASE<"fmul.w", fmul, MSA128WOpnd>; +class FMUL_D_DESC : MSA_3RF_DESC_BASE<"fmul.d", fmul, MSA128DOpnd>; + +class FRINT_W_DESC : MSA_2RF_DESC_BASE<"frint.w", frint, MSA128WOpnd>; +class FRINT_D_DESC : MSA_2RF_DESC_BASE<"frint.d", frint, MSA128DOpnd>; + +class FRCP_W_DESC : MSA_2RF_DESC_BASE<"frcp.w", int_mips_frcp_w, MSA128WOpnd>; +class FRCP_D_DESC : MSA_2RF_DESC_BASE<"frcp.d", int_mips_frcp_d, MSA128DOpnd>; + +class FRSQRT_W_DESC : MSA_2RF_DESC_BASE<"frsqrt.w", int_mips_frsqrt_w, + MSA128WOpnd>; +class FRSQRT_D_DESC : MSA_2RF_DESC_BASE<"frsqrt.d", int_mips_frsqrt_d, + MSA128DOpnd>; + +class FSAF_W_DESC : MSA_3RF_DESC_BASE<"fsaf.w", int_mips_fsaf_w, MSA128WOpnd>; +class FSAF_D_DESC : MSA_3RF_DESC_BASE<"fsaf.d", int_mips_fsaf_d, MSA128DOpnd>; + +class FSEQ_W_DESC : MSA_3RF_DESC_BASE<"fseq.w", int_mips_fseq_w, MSA128WOpnd>; +class FSEQ_D_DESC : MSA_3RF_DESC_BASE<"fseq.d", int_mips_fseq_d, MSA128DOpnd>; + +class FSLE_W_DESC : MSA_3RF_DESC_BASE<"fsle.w", int_mips_fsle_w, MSA128WOpnd>; +class FSLE_D_DESC : MSA_3RF_DESC_BASE<"fsle.d", int_mips_fsle_d, MSA128DOpnd>; + +class FSLT_W_DESC : MSA_3RF_DESC_BASE<"fslt.w", int_mips_fslt_w, MSA128WOpnd>; +class FSLT_D_DESC : MSA_3RF_DESC_BASE<"fslt.d", int_mips_fslt_d, MSA128DOpnd>; + +class FSNE_W_DESC : MSA_3RF_DESC_BASE<"fsne.w", int_mips_fsne_w, MSA128WOpnd>; +class FSNE_D_DESC : MSA_3RF_DESC_BASE<"fsne.d", int_mips_fsne_d, MSA128DOpnd>; + +class FSOR_W_DESC : MSA_3RF_DESC_BASE<"fsor.w", int_mips_fsor_w, MSA128WOpnd>; +class FSOR_D_DESC : MSA_3RF_DESC_BASE<"fsor.d", int_mips_fsor_d, MSA128DOpnd>; + +class FSQRT_W_DESC : MSA_2RF_DESC_BASE<"fsqrt.w", fsqrt, MSA128WOpnd>; +class FSQRT_D_DESC : MSA_2RF_DESC_BASE<"fsqrt.d", fsqrt, MSA128DOpnd>; + +class FSUB_W_DESC : MSA_3RF_DESC_BASE<"fsub.w", fsub, MSA128WOpnd>; +class FSUB_D_DESC : MSA_3RF_DESC_BASE<"fsub.d", fsub, MSA128DOpnd>; + +class FSUEQ_W_DESC : MSA_3RF_DESC_BASE<"fsueq.w", int_mips_fsueq_w, + MSA128WOpnd>; +class FSUEQ_D_DESC : MSA_3RF_DESC_BASE<"fsueq.d", int_mips_fsueq_d, + MSA128DOpnd>; + +class FSULE_W_DESC : MSA_3RF_DESC_BASE<"fsule.w", int_mips_fsule_w, + MSA128WOpnd>; +class FSULE_D_DESC : MSA_3RF_DESC_BASE<"fsule.d", int_mips_fsule_d, + MSA128DOpnd>; + +class FSULT_W_DESC : MSA_3RF_DESC_BASE<"fsult.w", int_mips_fsult_w, + MSA128WOpnd>; +class FSULT_D_DESC : MSA_3RF_DESC_BASE<"fsult.d", int_mips_fsult_d, + MSA128DOpnd>; + +class FSUN_W_DESC : MSA_3RF_DESC_BASE<"fsun.w", int_mips_fsun_w, + MSA128WOpnd>; +class FSUN_D_DESC : MSA_3RF_DESC_BASE<"fsun.d", int_mips_fsun_d, + MSA128DOpnd>; + +class FSUNE_W_DESC : MSA_3RF_DESC_BASE<"fsune.w", int_mips_fsune_w, + MSA128WOpnd>; +class FSUNE_D_DESC : MSA_3RF_DESC_BASE<"fsune.d", int_mips_fsune_d, + MSA128DOpnd>; + +class FTINT_S_W_DESC : MSA_2RF_DESC_BASE<"ftint_s.w", int_mips_ftint_s_w, + MSA128WOpnd>; +class FTINT_S_D_DESC : MSA_2RF_DESC_BASE<"ftint_s.d", int_mips_ftint_s_d, + MSA128DOpnd>; + +class FTINT_U_W_DESC : MSA_2RF_DESC_BASE<"ftint_u.w", int_mips_ftint_u_w, + MSA128WOpnd>; +class FTINT_U_D_DESC : MSA_2RF_DESC_BASE<"ftint_u.d", int_mips_ftint_u_d, + MSA128DOpnd>; + +class FTQ_H_DESC : MSA_3RF_DESC_BASE<"ftq.h", int_mips_ftq_h, + MSA128HOpnd, MSA128WOpnd, MSA128WOpnd>; +class FTQ_W_DESC : MSA_3RF_DESC_BASE<"ftq.w", int_mips_ftq_w, + MSA128WOpnd, MSA128DOpnd, MSA128DOpnd>; + +class FTRUNC_S_W_DESC : MSA_2RF_DESC_BASE<"ftrunc_s.w", fp_to_sint, + MSA128WOpnd>; +class FTRUNC_S_D_DESC : MSA_2RF_DESC_BASE<"ftrunc_s.d", fp_to_sint, + MSA128DOpnd>; + +class FTRUNC_U_W_DESC : MSA_2RF_DESC_BASE<"ftrunc_u.w", fp_to_uint, + MSA128WOpnd>; +class FTRUNC_U_D_DESC : MSA_2RF_DESC_BASE<"ftrunc_u.d", fp_to_uint, + MSA128DOpnd>; + +class HADD_S_H_DESC : MSA_3R_DESC_BASE<"hadd_s.h", int_mips_hadd_s_h, + MSA128HOpnd, MSA128BOpnd, MSA128BOpnd>; +class HADD_S_W_DESC : MSA_3R_DESC_BASE<"hadd_s.w", int_mips_hadd_s_w, + MSA128WOpnd, MSA128HOpnd, MSA128HOpnd>; +class HADD_S_D_DESC : MSA_3R_DESC_BASE<"hadd_s.d", int_mips_hadd_s_d, + MSA128DOpnd, MSA128WOpnd, MSA128WOpnd>; + +class HADD_U_H_DESC : MSA_3R_DESC_BASE<"hadd_u.h", int_mips_hadd_u_h, + MSA128HOpnd, MSA128BOpnd, MSA128BOpnd>; +class HADD_U_W_DESC : MSA_3R_DESC_BASE<"hadd_u.w", int_mips_hadd_u_w, + MSA128WOpnd, MSA128HOpnd, MSA128HOpnd>; +class HADD_U_D_DESC : MSA_3R_DESC_BASE<"hadd_u.d", int_mips_hadd_u_d, + MSA128DOpnd, MSA128WOpnd, MSA128WOpnd>; + +class HSUB_S_H_DESC : MSA_3R_DESC_BASE<"hsub_s.h", int_mips_hsub_s_h, + MSA128HOpnd, MSA128BOpnd, MSA128BOpnd>; +class HSUB_S_W_DESC : MSA_3R_DESC_BASE<"hsub_s.w", int_mips_hsub_s_w, + MSA128WOpnd, MSA128HOpnd, MSA128HOpnd>; +class HSUB_S_D_DESC : MSA_3R_DESC_BASE<"hsub_s.d", int_mips_hsub_s_d, + MSA128DOpnd, MSA128WOpnd, MSA128WOpnd>; + +class HSUB_U_H_DESC : MSA_3R_DESC_BASE<"hsub_u.h", int_mips_hsub_u_h, + MSA128HOpnd, MSA128BOpnd, MSA128BOpnd>; +class HSUB_U_W_DESC : MSA_3R_DESC_BASE<"hsub_u.w", int_mips_hsub_u_w, + MSA128WOpnd, MSA128HOpnd, MSA128HOpnd>; +class HSUB_U_D_DESC : MSA_3R_DESC_BASE<"hsub_u.d", int_mips_hsub_u_d, + MSA128DOpnd, MSA128WOpnd, MSA128WOpnd>; + +class ILVEV_B_DESC : MSA_3R_DESC_BASE<"ilvev.b", MipsILVEV, MSA128BOpnd>; +class ILVEV_H_DESC : MSA_3R_DESC_BASE<"ilvev.h", MipsILVEV, MSA128HOpnd>; +class ILVEV_W_DESC : MSA_3R_DESC_BASE<"ilvev.w", MipsILVEV, MSA128WOpnd>; +class ILVEV_D_DESC : MSA_3R_DESC_BASE<"ilvev.d", MipsILVEV, MSA128DOpnd>; + +class ILVL_B_DESC : MSA_3R_DESC_BASE<"ilvl.b", MipsILVL, MSA128BOpnd>; +class ILVL_H_DESC : MSA_3R_DESC_BASE<"ilvl.h", MipsILVL, MSA128HOpnd>; +class ILVL_W_DESC : MSA_3R_DESC_BASE<"ilvl.w", MipsILVL, MSA128WOpnd>; +class ILVL_D_DESC : MSA_3R_DESC_BASE<"ilvl.d", MipsILVL, MSA128DOpnd>; + +class ILVOD_B_DESC : MSA_3R_DESC_BASE<"ilvod.b", MipsILVOD, MSA128BOpnd>; +class ILVOD_H_DESC : MSA_3R_DESC_BASE<"ilvod.h", MipsILVOD, MSA128HOpnd>; +class ILVOD_W_DESC : MSA_3R_DESC_BASE<"ilvod.w", MipsILVOD, MSA128WOpnd>; +class ILVOD_D_DESC : MSA_3R_DESC_BASE<"ilvod.d", MipsILVOD, MSA128DOpnd>; + +class ILVR_B_DESC : MSA_3R_DESC_BASE<"ilvr.b", MipsILVR, MSA128BOpnd>; +class ILVR_H_DESC : MSA_3R_DESC_BASE<"ilvr.h", MipsILVR, MSA128HOpnd>; +class ILVR_W_DESC : MSA_3R_DESC_BASE<"ilvr.w", MipsILVR, MSA128WOpnd>; +class ILVR_D_DESC : MSA_3R_DESC_BASE<"ilvr.d", MipsILVR, MSA128DOpnd>; + +class INSERT_B_DESC : MSA_INSERT_DESC_BASE<"insert.b", vinsert_v16i8, + MSA128BOpnd, GPR32Opnd>; +class INSERT_H_DESC : MSA_INSERT_DESC_BASE<"insert.h", vinsert_v8i16, + MSA128HOpnd, GPR32Opnd>; +class INSERT_W_DESC : MSA_INSERT_DESC_BASE<"insert.w", vinsert_v4i32, + MSA128WOpnd, GPR32Opnd>; + +class INSERT_FW_PSEUDO_DESC : MSA_INSERT_PSEUDO_BASE<vector_insert, v4f32, + MSA128WOpnd, FGR32Opnd>; +class INSERT_FD_PSEUDO_DESC : MSA_INSERT_PSEUDO_BASE<vector_insert, v2f64, + MSA128DOpnd, FGR64Opnd>; + +class INSVE_B_DESC : MSA_INSVE_DESC_BASE<"insve.b", int_mips_insve_b, + MSA128BOpnd>; +class INSVE_H_DESC : MSA_INSVE_DESC_BASE<"insve.h", int_mips_insve_h, + MSA128HOpnd>; +class INSVE_W_DESC : MSA_INSVE_DESC_BASE<"insve.w", int_mips_insve_w, + MSA128WOpnd>; +class INSVE_D_DESC : MSA_INSVE_DESC_BASE<"insve.d", int_mips_insve_d, + MSA128DOpnd>; + +class LD_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ValueType TyNode, RegisterOperand ROWD, + Operand MemOpnd = mem, ComplexPattern Addr = addrRegImm, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs ROWD:$wd); + dag InOperandList = (ins MemOpnd:$addr); + string AsmString = !strconcat(instr_asm, "\t$wd, $addr"); + list<dag> Pattern = [(set ROWD:$wd, (TyNode (OpNode Addr:$addr)))]; + InstrItinClass Itinerary = itin; + string DecoderMethod = "DecodeMSA128Mem"; +} + +class LD_B_DESC : LD_DESC_BASE<"ld.b", load, v16i8, MSA128BOpnd>; +class LD_H_DESC : LD_DESC_BASE<"ld.h", load, v8i16, MSA128HOpnd>; +class LD_W_DESC : LD_DESC_BASE<"ld.w", load, v4i32, MSA128WOpnd>; +class LD_D_DESC : LD_DESC_BASE<"ld.d", load, v2i64, MSA128DOpnd>; + +class LDI_B_DESC : MSA_I10_LDI_DESC_BASE<"ldi.b", MSA128BOpnd>; +class LDI_H_DESC : MSA_I10_LDI_DESC_BASE<"ldi.h", MSA128HOpnd>; +class LDI_W_DESC : MSA_I10_LDI_DESC_BASE<"ldi.w", MSA128WOpnd>; +class LDI_D_DESC : MSA_I10_LDI_DESC_BASE<"ldi.d", MSA128DOpnd>; + +class LSA_DESC { + dag OutOperandList = (outs GPR32Opnd:$rd); + dag InOperandList = (ins GPR32Opnd:$rs, GPR32Opnd:$rt, LSAImm:$sa); + string AsmString = "lsa\t$rd, $rs, $rt, $sa"; + list<dag> Pattern = [(set GPR32Opnd:$rd, (add GPR32Opnd:$rs, + (shl GPR32Opnd:$rt, + immZExt2Lsa:$sa)))]; + InstrItinClass Itinerary = NoItinerary; +} + +class MADD_Q_H_DESC : MSA_3RF_4RF_DESC_BASE<"madd_q.h", int_mips_madd_q_h, + MSA128HOpnd>; +class MADD_Q_W_DESC : MSA_3RF_4RF_DESC_BASE<"madd_q.w", int_mips_madd_q_w, + MSA128WOpnd>; + +class MADDR_Q_H_DESC : MSA_3RF_4RF_DESC_BASE<"maddr_q.h", int_mips_maddr_q_h, + MSA128HOpnd>; +class MADDR_Q_W_DESC : MSA_3RF_4RF_DESC_BASE<"maddr_q.w", int_mips_maddr_q_w, + MSA128WOpnd>; + +class MADDV_B_DESC : MSA_3R_4R_DESC_BASE<"maddv.b", muladd, MSA128BOpnd>; +class MADDV_H_DESC : MSA_3R_4R_DESC_BASE<"maddv.h", muladd, MSA128HOpnd>; +class MADDV_W_DESC : MSA_3R_4R_DESC_BASE<"maddv.w", muladd, MSA128WOpnd>; +class MADDV_D_DESC : MSA_3R_4R_DESC_BASE<"maddv.d", muladd, MSA128DOpnd>; + +class MAX_A_B_DESC : MSA_3R_DESC_BASE<"max_a.b", int_mips_max_a_b, MSA128BOpnd>; +class MAX_A_H_DESC : MSA_3R_DESC_BASE<"max_a.h", int_mips_max_a_h, MSA128HOpnd>; +class MAX_A_W_DESC : MSA_3R_DESC_BASE<"max_a.w", int_mips_max_a_w, MSA128WOpnd>; +class MAX_A_D_DESC : MSA_3R_DESC_BASE<"max_a.d", int_mips_max_a_d, MSA128DOpnd>; + +class MAX_S_B_DESC : MSA_3R_DESC_BASE<"max_s.b", MipsVSMax, MSA128BOpnd>; +class MAX_S_H_DESC : MSA_3R_DESC_BASE<"max_s.h", MipsVSMax, MSA128HOpnd>; +class MAX_S_W_DESC : MSA_3R_DESC_BASE<"max_s.w", MipsVSMax, MSA128WOpnd>; +class MAX_S_D_DESC : MSA_3R_DESC_BASE<"max_s.d", MipsVSMax, MSA128DOpnd>; + +class MAX_U_B_DESC : MSA_3R_DESC_BASE<"max_u.b", MipsVUMax, MSA128BOpnd>; +class MAX_U_H_DESC : MSA_3R_DESC_BASE<"max_u.h", MipsVUMax, MSA128HOpnd>; +class MAX_U_W_DESC : MSA_3R_DESC_BASE<"max_u.w", MipsVUMax, MSA128WOpnd>; +class MAX_U_D_DESC : MSA_3R_DESC_BASE<"max_u.d", MipsVUMax, MSA128DOpnd>; + +class MAXI_S_B_DESC : MSA_I5_DESC_BASE<"maxi_s.b", MipsVSMax, vsplati8_simm5, + MSA128BOpnd>; +class MAXI_S_H_DESC : MSA_I5_DESC_BASE<"maxi_s.h", MipsVSMax, vsplati16_simm5, + MSA128HOpnd>; +class MAXI_S_W_DESC : MSA_I5_DESC_BASE<"maxi_s.w", MipsVSMax, vsplati32_simm5, + MSA128WOpnd>; +class MAXI_S_D_DESC : MSA_I5_DESC_BASE<"maxi_s.d", MipsVSMax, vsplati64_simm5, + MSA128DOpnd>; + +class MAXI_U_B_DESC : MSA_I5_DESC_BASE<"maxi_u.b", MipsVUMax, vsplati8_uimm5, + MSA128BOpnd>; +class MAXI_U_H_DESC : MSA_I5_DESC_BASE<"maxi_u.h", MipsVUMax, vsplati16_uimm5, + MSA128HOpnd>; +class MAXI_U_W_DESC : MSA_I5_DESC_BASE<"maxi_u.w", MipsVUMax, vsplati32_uimm5, + MSA128WOpnd>; +class MAXI_U_D_DESC : MSA_I5_DESC_BASE<"maxi_u.d", MipsVUMax, vsplati64_uimm5, + MSA128DOpnd>; + +class MIN_A_B_DESC : MSA_3R_DESC_BASE<"min_a.b", int_mips_min_a_b, MSA128BOpnd>; +class MIN_A_H_DESC : MSA_3R_DESC_BASE<"min_a.h", int_mips_min_a_h, MSA128HOpnd>; +class MIN_A_W_DESC : MSA_3R_DESC_BASE<"min_a.w", int_mips_min_a_w, MSA128WOpnd>; +class MIN_A_D_DESC : MSA_3R_DESC_BASE<"min_a.d", int_mips_min_a_d, MSA128DOpnd>; + +class MIN_S_B_DESC : MSA_3R_DESC_BASE<"min_s.b", MipsVSMin, MSA128BOpnd>; +class MIN_S_H_DESC : MSA_3R_DESC_BASE<"min_s.h", MipsVSMin, MSA128HOpnd>; +class MIN_S_W_DESC : MSA_3R_DESC_BASE<"min_s.w", MipsVSMin, MSA128WOpnd>; +class MIN_S_D_DESC : MSA_3R_DESC_BASE<"min_s.d", MipsVSMin, MSA128DOpnd>; + +class MIN_U_B_DESC : MSA_3R_DESC_BASE<"min_u.b", MipsVUMin, MSA128BOpnd>; +class MIN_U_H_DESC : MSA_3R_DESC_BASE<"min_u.h", MipsVUMin, MSA128HOpnd>; +class MIN_U_W_DESC : MSA_3R_DESC_BASE<"min_u.w", MipsVUMin, MSA128WOpnd>; +class MIN_U_D_DESC : MSA_3R_DESC_BASE<"min_u.d", MipsVUMin, MSA128DOpnd>; + +class MINI_S_B_DESC : MSA_I5_DESC_BASE<"mini_s.b", MipsVSMin, vsplati8_simm5, + MSA128BOpnd>; +class MINI_S_H_DESC : MSA_I5_DESC_BASE<"mini_s.h", MipsVSMin, vsplati16_simm5, + MSA128HOpnd>; +class MINI_S_W_DESC : MSA_I5_DESC_BASE<"mini_s.w", MipsVSMin, vsplati32_simm5, + MSA128WOpnd>; +class MINI_S_D_DESC : MSA_I5_DESC_BASE<"mini_s.d", MipsVSMin, vsplati64_simm5, + MSA128DOpnd>; + +class MINI_U_B_DESC : MSA_I5_DESC_BASE<"mini_u.b", MipsVUMin, vsplati8_uimm5, + MSA128BOpnd>; +class MINI_U_H_DESC : MSA_I5_DESC_BASE<"mini_u.h", MipsVUMin, vsplati16_uimm5, + MSA128HOpnd>; +class MINI_U_W_DESC : MSA_I5_DESC_BASE<"mini_u.w", MipsVUMin, vsplati32_uimm5, + MSA128WOpnd>; +class MINI_U_D_DESC : MSA_I5_DESC_BASE<"mini_u.d", MipsVUMin, vsplati64_uimm5, + MSA128DOpnd>; + +class MOD_S_B_DESC : MSA_3R_DESC_BASE<"mod_s.b", srem, MSA128BOpnd>; +class MOD_S_H_DESC : MSA_3R_DESC_BASE<"mod_s.h", srem, MSA128HOpnd>; +class MOD_S_W_DESC : MSA_3R_DESC_BASE<"mod_s.w", srem, MSA128WOpnd>; +class MOD_S_D_DESC : MSA_3R_DESC_BASE<"mod_s.d", srem, MSA128DOpnd>; + +class MOD_U_B_DESC : MSA_3R_DESC_BASE<"mod_u.b", urem, MSA128BOpnd>; +class MOD_U_H_DESC : MSA_3R_DESC_BASE<"mod_u.h", urem, MSA128HOpnd>; +class MOD_U_W_DESC : MSA_3R_DESC_BASE<"mod_u.w", urem, MSA128WOpnd>; +class MOD_U_D_DESC : MSA_3R_DESC_BASE<"mod_u.d", urem, MSA128DOpnd>; + +class MOVE_V_DESC { + dag OutOperandList = (outs MSA128BOpnd:$wd); + dag InOperandList = (ins MSA128BOpnd:$ws); + string AsmString = "move.v\t$wd, $ws"; + list<dag> Pattern = []; + InstrItinClass Itinerary = NoItinerary; +} + +class MSUB_Q_H_DESC : MSA_3RF_4RF_DESC_BASE<"msub_q.h", int_mips_msub_q_h, + MSA128HOpnd>; +class MSUB_Q_W_DESC : MSA_3RF_4RF_DESC_BASE<"msub_q.w", int_mips_msub_q_w, + MSA128WOpnd>; + +class MSUBR_Q_H_DESC : MSA_3RF_4RF_DESC_BASE<"msubr_q.h", int_mips_msubr_q_h, + MSA128HOpnd>; +class MSUBR_Q_W_DESC : MSA_3RF_4RF_DESC_BASE<"msubr_q.w", int_mips_msubr_q_w, + MSA128WOpnd>; + +class MSUBV_B_DESC : MSA_3R_4R_DESC_BASE<"msubv.b", mulsub, MSA128BOpnd>; +class MSUBV_H_DESC : MSA_3R_4R_DESC_BASE<"msubv.h", mulsub, MSA128HOpnd>; +class MSUBV_W_DESC : MSA_3R_4R_DESC_BASE<"msubv.w", mulsub, MSA128WOpnd>; +class MSUBV_D_DESC : MSA_3R_4R_DESC_BASE<"msubv.d", mulsub, MSA128DOpnd>; + +class MUL_Q_H_DESC : MSA_3RF_DESC_BASE<"mul_q.h", int_mips_mul_q_h, + MSA128HOpnd>; +class MUL_Q_W_DESC : MSA_3RF_DESC_BASE<"mul_q.w", int_mips_mul_q_w, + MSA128WOpnd>; + +class MULR_Q_H_DESC : MSA_3RF_DESC_BASE<"mulr_q.h", int_mips_mulr_q_h, + MSA128HOpnd>; +class MULR_Q_W_DESC : MSA_3RF_DESC_BASE<"mulr_q.w", int_mips_mulr_q_w, + MSA128WOpnd>; + +class MULV_B_DESC : MSA_3R_DESC_BASE<"mulv.b", mul, MSA128BOpnd>; +class MULV_H_DESC : MSA_3R_DESC_BASE<"mulv.h", mul, MSA128HOpnd>; +class MULV_W_DESC : MSA_3R_DESC_BASE<"mulv.w", mul, MSA128WOpnd>; +class MULV_D_DESC : MSA_3R_DESC_BASE<"mulv.d", mul, MSA128DOpnd>; + +class NLOC_B_DESC : MSA_2R_DESC_BASE<"nloc.b", int_mips_nloc_b, MSA128BOpnd>; +class NLOC_H_DESC : MSA_2R_DESC_BASE<"nloc.h", int_mips_nloc_h, MSA128HOpnd>; +class NLOC_W_DESC : MSA_2R_DESC_BASE<"nloc.w", int_mips_nloc_w, MSA128WOpnd>; +class NLOC_D_DESC : MSA_2R_DESC_BASE<"nloc.d", int_mips_nloc_d, MSA128DOpnd>; + +class NLZC_B_DESC : MSA_2R_DESC_BASE<"nlzc.b", ctlz, MSA128BOpnd>; +class NLZC_H_DESC : MSA_2R_DESC_BASE<"nlzc.h", ctlz, MSA128HOpnd>; +class NLZC_W_DESC : MSA_2R_DESC_BASE<"nlzc.w", ctlz, MSA128WOpnd>; +class NLZC_D_DESC : MSA_2R_DESC_BASE<"nlzc.d", ctlz, MSA128DOpnd>; + +class NOR_V_DESC : MSA_VEC_DESC_BASE<"nor.v", MipsVNOR, MSA128BOpnd>; +class NOR_V_H_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<MipsVNOR, MSA128HOpnd>; +class NOR_V_W_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<MipsVNOR, MSA128WOpnd>; +class NOR_V_D_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<MipsVNOR, MSA128DOpnd>; + +class NORI_B_DESC : MSA_I8_DESC_BASE<"nori.b", MipsVNOR, vsplati8_uimm8, + MSA128BOpnd>; + +class OR_V_DESC : MSA_VEC_DESC_BASE<"or.v", or, MSA128BOpnd>; +class OR_V_H_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<or, MSA128HOpnd>; +class OR_V_W_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<or, MSA128WOpnd>; +class OR_V_D_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<or, MSA128DOpnd>; + +class ORI_B_DESC : MSA_I8_DESC_BASE<"ori.b", or, vsplati8_uimm8, MSA128BOpnd>; + +class PCKEV_B_DESC : MSA_3R_DESC_BASE<"pckev.b", MipsPCKEV, MSA128BOpnd>; +class PCKEV_H_DESC : MSA_3R_DESC_BASE<"pckev.h", MipsPCKEV, MSA128HOpnd>; +class PCKEV_W_DESC : MSA_3R_DESC_BASE<"pckev.w", MipsPCKEV, MSA128WOpnd>; +class PCKEV_D_DESC : MSA_3R_DESC_BASE<"pckev.d", MipsPCKEV, MSA128DOpnd>; + +class PCKOD_B_DESC : MSA_3R_DESC_BASE<"pckod.b", MipsPCKOD, MSA128BOpnd>; +class PCKOD_H_DESC : MSA_3R_DESC_BASE<"pckod.h", MipsPCKOD, MSA128HOpnd>; +class PCKOD_W_DESC : MSA_3R_DESC_BASE<"pckod.w", MipsPCKOD, MSA128WOpnd>; +class PCKOD_D_DESC : MSA_3R_DESC_BASE<"pckod.d", MipsPCKOD, MSA128DOpnd>; + +class PCNT_B_DESC : MSA_2R_DESC_BASE<"pcnt.b", ctpop, MSA128BOpnd>; +class PCNT_H_DESC : MSA_2R_DESC_BASE<"pcnt.h", ctpop, MSA128HOpnd>; +class PCNT_W_DESC : MSA_2R_DESC_BASE<"pcnt.w", ctpop, MSA128WOpnd>; +class PCNT_D_DESC : MSA_2R_DESC_BASE<"pcnt.d", ctpop, MSA128DOpnd>; + +class SAT_S_B_DESC : MSA_BIT_B_X_DESC_BASE<"sat_s.b", int_mips_sat_s_b, + MSA128BOpnd>; +class SAT_S_H_DESC : MSA_BIT_H_X_DESC_BASE<"sat_s.h", int_mips_sat_s_h, + MSA128HOpnd>; +class SAT_S_W_DESC : MSA_BIT_W_X_DESC_BASE<"sat_s.w", int_mips_sat_s_w, + MSA128WOpnd>; +class SAT_S_D_DESC : MSA_BIT_D_X_DESC_BASE<"sat_s.d", int_mips_sat_s_d, + MSA128DOpnd>; + +class SAT_U_B_DESC : MSA_BIT_B_X_DESC_BASE<"sat_u.b", int_mips_sat_u_b, + MSA128BOpnd>; +class SAT_U_H_DESC : MSA_BIT_H_X_DESC_BASE<"sat_u.h", int_mips_sat_u_h, + MSA128HOpnd>; +class SAT_U_W_DESC : MSA_BIT_W_X_DESC_BASE<"sat_u.w", int_mips_sat_u_w, + MSA128WOpnd>; +class SAT_U_D_DESC : MSA_BIT_D_X_DESC_BASE<"sat_u.d", int_mips_sat_u_d, + MSA128DOpnd>; + +class SHF_B_DESC : MSA_I8_SHF_DESC_BASE<"shf.b", MSA128BOpnd>; +class SHF_H_DESC : MSA_I8_SHF_DESC_BASE<"shf.h", MSA128HOpnd>; +class SHF_W_DESC : MSA_I8_SHF_DESC_BASE<"shf.w", MSA128WOpnd>; + +class SLD_B_DESC : MSA_3R_SLD_DESC_BASE<"sld.b", int_mips_sld_b, MSA128BOpnd>; +class SLD_H_DESC : MSA_3R_SLD_DESC_BASE<"sld.h", int_mips_sld_h, MSA128HOpnd>; +class SLD_W_DESC : MSA_3R_SLD_DESC_BASE<"sld.w", int_mips_sld_w, MSA128WOpnd>; +class SLD_D_DESC : MSA_3R_SLD_DESC_BASE<"sld.d", int_mips_sld_d, MSA128DOpnd>; + +class SLDI_B_DESC : MSA_ELM_DESC_BASE<"sldi.b", int_mips_sldi_b, MSA128BOpnd>; +class SLDI_H_DESC : MSA_ELM_DESC_BASE<"sldi.h", int_mips_sldi_h, MSA128HOpnd>; +class SLDI_W_DESC : MSA_ELM_DESC_BASE<"sldi.w", int_mips_sldi_w, MSA128WOpnd>; +class SLDI_D_DESC : MSA_ELM_DESC_BASE<"sldi.d", int_mips_sldi_d, MSA128DOpnd>; + +class SLL_B_DESC : MSA_3R_DESC_BASE<"sll.b", shl, MSA128BOpnd>; +class SLL_H_DESC : MSA_3R_DESC_BASE<"sll.h", shl, MSA128HOpnd>; +class SLL_W_DESC : MSA_3R_DESC_BASE<"sll.w", shl, MSA128WOpnd>; +class SLL_D_DESC : MSA_3R_DESC_BASE<"sll.d", shl, MSA128DOpnd>; + +class SLLI_B_DESC : MSA_BIT_SPLAT_DESC_BASE<"slli.b", shl, vsplati8_uimm3, + MSA128BOpnd>; +class SLLI_H_DESC : MSA_BIT_SPLAT_DESC_BASE<"slli.h", shl, vsplati16_uimm4, + MSA128HOpnd>; +class SLLI_W_DESC : MSA_BIT_SPLAT_DESC_BASE<"slli.w", shl, vsplati32_uimm5, + MSA128WOpnd>; +class SLLI_D_DESC : MSA_BIT_SPLAT_DESC_BASE<"slli.d", shl, vsplati64_uimm6, + MSA128DOpnd>; + +class SPLAT_B_DESC : MSA_3R_SPLAT_DESC_BASE<"splat.b", vsplati8_elt, + MSA128BOpnd>; +class SPLAT_H_DESC : MSA_3R_SPLAT_DESC_BASE<"splat.h", vsplati16_elt, + MSA128HOpnd>; +class SPLAT_W_DESC : MSA_3R_SPLAT_DESC_BASE<"splat.w", vsplati32_elt, + MSA128WOpnd>; +class SPLAT_D_DESC : MSA_3R_SPLAT_DESC_BASE<"splat.d", vsplati64_elt, + MSA128DOpnd>; + +class SPLATI_B_DESC : MSA_ELM_SPLAT_DESC_BASE<"splati.b", vsplati8_uimm4, + MSA128BOpnd>; +class SPLATI_H_DESC : MSA_ELM_SPLAT_DESC_BASE<"splati.h", vsplati16_uimm3, + MSA128HOpnd>; +class SPLATI_W_DESC : MSA_ELM_SPLAT_DESC_BASE<"splati.w", vsplati32_uimm2, + MSA128WOpnd>; +class SPLATI_D_DESC : MSA_ELM_SPLAT_DESC_BASE<"splati.d", vsplati64_uimm1, + MSA128DOpnd>; + +class SRA_B_DESC : MSA_3R_DESC_BASE<"sra.b", sra, MSA128BOpnd>; +class SRA_H_DESC : MSA_3R_DESC_BASE<"sra.h", sra, MSA128HOpnd>; +class SRA_W_DESC : MSA_3R_DESC_BASE<"sra.w", sra, MSA128WOpnd>; +class SRA_D_DESC : MSA_3R_DESC_BASE<"sra.d", sra, MSA128DOpnd>; + +class SRAI_B_DESC : MSA_BIT_SPLAT_DESC_BASE<"srai.b", sra, vsplati8_uimm3, + MSA128BOpnd>; +class SRAI_H_DESC : MSA_BIT_SPLAT_DESC_BASE<"srai.h", sra, vsplati16_uimm4, + MSA128HOpnd>; +class SRAI_W_DESC : MSA_BIT_SPLAT_DESC_BASE<"srai.w", sra, vsplati32_uimm5, + MSA128WOpnd>; +class SRAI_D_DESC : MSA_BIT_SPLAT_DESC_BASE<"srai.d", sra, vsplati64_uimm6, + MSA128DOpnd>; + +class SRAR_B_DESC : MSA_3R_DESC_BASE<"srar.b", int_mips_srar_b, MSA128BOpnd>; +class SRAR_H_DESC : MSA_3R_DESC_BASE<"srar.h", int_mips_srar_h, MSA128HOpnd>; +class SRAR_W_DESC : MSA_3R_DESC_BASE<"srar.w", int_mips_srar_w, MSA128WOpnd>; +class SRAR_D_DESC : MSA_3R_DESC_BASE<"srar.d", int_mips_srar_d, MSA128DOpnd>; + +class SRARI_B_DESC : MSA_BIT_B_X_DESC_BASE<"srari.b", int_mips_srari_b, + MSA128BOpnd>; +class SRARI_H_DESC : MSA_BIT_H_X_DESC_BASE<"srari.h", int_mips_srari_h, + MSA128HOpnd>; +class SRARI_W_DESC : MSA_BIT_W_X_DESC_BASE<"srari.w", int_mips_srari_w, + MSA128WOpnd>; +class SRARI_D_DESC : MSA_BIT_D_X_DESC_BASE<"srari.d", int_mips_srari_d, + MSA128DOpnd>; + +class SRL_B_DESC : MSA_3R_DESC_BASE<"srl.b", srl, MSA128BOpnd>; +class SRL_H_DESC : MSA_3R_DESC_BASE<"srl.h", srl, MSA128HOpnd>; +class SRL_W_DESC : MSA_3R_DESC_BASE<"srl.w", srl, MSA128WOpnd>; +class SRL_D_DESC : MSA_3R_DESC_BASE<"srl.d", srl, MSA128DOpnd>; + +class SRLI_B_DESC : MSA_BIT_SPLAT_DESC_BASE<"srli.b", srl, vsplati8_uimm3, + MSA128BOpnd>; +class SRLI_H_DESC : MSA_BIT_SPLAT_DESC_BASE<"srli.h", srl, vsplati16_uimm4, + MSA128HOpnd>; +class SRLI_W_DESC : MSA_BIT_SPLAT_DESC_BASE<"srli.w", srl, vsplati32_uimm5, + MSA128WOpnd>; +class SRLI_D_DESC : MSA_BIT_SPLAT_DESC_BASE<"srli.d", srl, vsplati64_uimm6, + MSA128DOpnd>; + +class SRLR_B_DESC : MSA_3R_DESC_BASE<"srlr.b", int_mips_srlr_b, MSA128BOpnd>; +class SRLR_H_DESC : MSA_3R_DESC_BASE<"srlr.h", int_mips_srlr_h, MSA128HOpnd>; +class SRLR_W_DESC : MSA_3R_DESC_BASE<"srlr.w", int_mips_srlr_w, MSA128WOpnd>; +class SRLR_D_DESC : MSA_3R_DESC_BASE<"srlr.d", int_mips_srlr_d, MSA128DOpnd>; + +class SRLRI_B_DESC : MSA_BIT_B_X_DESC_BASE<"srlri.b", int_mips_srlri_b, + MSA128BOpnd>; +class SRLRI_H_DESC : MSA_BIT_H_X_DESC_BASE<"srlri.h", int_mips_srlri_h, + MSA128HOpnd>; +class SRLRI_W_DESC : MSA_BIT_W_X_DESC_BASE<"srlri.w", int_mips_srlri_w, + MSA128WOpnd>; +class SRLRI_D_DESC : MSA_BIT_D_X_DESC_BASE<"srlri.d", int_mips_srlri_d, + MSA128DOpnd>; + +class ST_DESC_BASE<string instr_asm, SDPatternOperator OpNode, + ValueType TyNode, RegisterOperand ROWD, + Operand MemOpnd = mem, ComplexPattern Addr = addrRegImm, + InstrItinClass itin = NoItinerary> { + dag OutOperandList = (outs); + dag InOperandList = (ins ROWD:$wd, MemOpnd:$addr); + string AsmString = !strconcat(instr_asm, "\t$wd, $addr"); + list<dag> Pattern = [(OpNode (TyNode ROWD:$wd), Addr:$addr)]; + InstrItinClass Itinerary = itin; + string DecoderMethod = "DecodeMSA128Mem"; +} + +class ST_B_DESC : ST_DESC_BASE<"st.b", store, v16i8, MSA128BOpnd>; +class ST_H_DESC : ST_DESC_BASE<"st.h", store, v8i16, MSA128HOpnd>; +class ST_W_DESC : ST_DESC_BASE<"st.w", store, v4i32, MSA128WOpnd>; +class ST_D_DESC : ST_DESC_BASE<"st.d", store, v2i64, MSA128DOpnd>; + +class SUBS_S_B_DESC : MSA_3R_DESC_BASE<"subs_s.b", int_mips_subs_s_b, + MSA128BOpnd>; +class SUBS_S_H_DESC : MSA_3R_DESC_BASE<"subs_s.h", int_mips_subs_s_h, + MSA128HOpnd>; +class SUBS_S_W_DESC : MSA_3R_DESC_BASE<"subs_s.w", int_mips_subs_s_w, + MSA128WOpnd>; +class SUBS_S_D_DESC : MSA_3R_DESC_BASE<"subs_s.d", int_mips_subs_s_d, + MSA128DOpnd>; + +class SUBS_U_B_DESC : MSA_3R_DESC_BASE<"subs_u.b", int_mips_subs_u_b, + MSA128BOpnd>; +class SUBS_U_H_DESC : MSA_3R_DESC_BASE<"subs_u.h", int_mips_subs_u_h, + MSA128HOpnd>; +class SUBS_U_W_DESC : MSA_3R_DESC_BASE<"subs_u.w", int_mips_subs_u_w, + MSA128WOpnd>; +class SUBS_U_D_DESC : MSA_3R_DESC_BASE<"subs_u.d", int_mips_subs_u_d, + MSA128DOpnd>; + +class SUBSUS_U_B_DESC : MSA_3R_DESC_BASE<"subsus_u.b", int_mips_subsus_u_b, + MSA128BOpnd>; +class SUBSUS_U_H_DESC : MSA_3R_DESC_BASE<"subsus_u.h", int_mips_subsus_u_h, + MSA128HOpnd>; +class SUBSUS_U_W_DESC : MSA_3R_DESC_BASE<"subsus_u.w", int_mips_subsus_u_w, + MSA128WOpnd>; +class SUBSUS_U_D_DESC : MSA_3R_DESC_BASE<"subsus_u.d", int_mips_subsus_u_d, + MSA128DOpnd>; + +class SUBSUU_S_B_DESC : MSA_3R_DESC_BASE<"subsuu_s.b", int_mips_subsuu_s_b, + MSA128BOpnd>; +class SUBSUU_S_H_DESC : MSA_3R_DESC_BASE<"subsuu_s.h", int_mips_subsuu_s_h, + MSA128HOpnd>; +class SUBSUU_S_W_DESC : MSA_3R_DESC_BASE<"subsuu_s.w", int_mips_subsuu_s_w, + MSA128WOpnd>; +class SUBSUU_S_D_DESC : MSA_3R_DESC_BASE<"subsuu_s.d", int_mips_subsuu_s_d, + MSA128DOpnd>; + +class SUBV_B_DESC : MSA_3R_DESC_BASE<"subv.b", sub, MSA128BOpnd>; +class SUBV_H_DESC : MSA_3R_DESC_BASE<"subv.h", sub, MSA128HOpnd>; +class SUBV_W_DESC : MSA_3R_DESC_BASE<"subv.w", sub, MSA128WOpnd>; +class SUBV_D_DESC : MSA_3R_DESC_BASE<"subv.d", sub, MSA128DOpnd>; + +class SUBVI_B_DESC : MSA_I5_DESC_BASE<"subvi.b", sub, vsplati8_uimm5, + MSA128BOpnd>; +class SUBVI_H_DESC : MSA_I5_DESC_BASE<"subvi.h", sub, vsplati16_uimm5, + MSA128HOpnd>; +class SUBVI_W_DESC : MSA_I5_DESC_BASE<"subvi.w", sub, vsplati32_uimm5, + MSA128WOpnd>; +class SUBVI_D_DESC : MSA_I5_DESC_BASE<"subvi.d", sub, vsplati64_uimm5, + MSA128DOpnd>; + +class VSHF_B_DESC : MSA_3R_VSHF_DESC_BASE<"vshf.b", MSA128BOpnd>; +class VSHF_H_DESC : MSA_3R_VSHF_DESC_BASE<"vshf.h", MSA128HOpnd>; +class VSHF_W_DESC : MSA_3R_VSHF_DESC_BASE<"vshf.w", MSA128WOpnd>; +class VSHF_D_DESC : MSA_3R_VSHF_DESC_BASE<"vshf.d", MSA128DOpnd>; + +class XOR_V_DESC : MSA_VEC_DESC_BASE<"xor.v", xor, MSA128BOpnd>; +class XOR_V_H_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<xor, MSA128HOpnd>; +class XOR_V_W_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<xor, MSA128WOpnd>; +class XOR_V_D_PSEUDO_DESC : MSA_VEC_PSEUDO_BASE<xor, MSA128DOpnd>; + +class XORI_B_DESC : MSA_I8_DESC_BASE<"xori.b", xor, vsplati8_uimm8, + MSA128BOpnd>; + +// Instruction defs. +def ADD_A_B : ADD_A_B_ENC, ADD_A_B_DESC; +def ADD_A_H : ADD_A_H_ENC, ADD_A_H_DESC; +def ADD_A_W : ADD_A_W_ENC, ADD_A_W_DESC; +def ADD_A_D : ADD_A_D_ENC, ADD_A_D_DESC; + +def ADDS_A_B : ADDS_A_B_ENC, ADDS_A_B_DESC; +def ADDS_A_H : ADDS_A_H_ENC, ADDS_A_H_DESC; +def ADDS_A_W : ADDS_A_W_ENC, ADDS_A_W_DESC; +def ADDS_A_D : ADDS_A_D_ENC, ADDS_A_D_DESC; + +def ADDS_S_B : ADDS_S_B_ENC, ADDS_S_B_DESC; +def ADDS_S_H : ADDS_S_H_ENC, ADDS_S_H_DESC; +def ADDS_S_W : ADDS_S_W_ENC, ADDS_S_W_DESC; +def ADDS_S_D : ADDS_S_D_ENC, ADDS_S_D_DESC; + +def ADDS_U_B : ADDS_U_B_ENC, ADDS_U_B_DESC; +def ADDS_U_H : ADDS_U_H_ENC, ADDS_U_H_DESC; +def ADDS_U_W : ADDS_U_W_ENC, ADDS_U_W_DESC; +def ADDS_U_D : ADDS_U_D_ENC, ADDS_U_D_DESC; + +def ADDV_B : ADDV_B_ENC, ADDV_B_DESC; +def ADDV_H : ADDV_H_ENC, ADDV_H_DESC; +def ADDV_W : ADDV_W_ENC, ADDV_W_DESC; +def ADDV_D : ADDV_D_ENC, ADDV_D_DESC; + +def ADDVI_B : ADDVI_B_ENC, ADDVI_B_DESC; +def ADDVI_H : ADDVI_H_ENC, ADDVI_H_DESC; +def ADDVI_W : ADDVI_W_ENC, ADDVI_W_DESC; +def ADDVI_D : ADDVI_D_ENC, ADDVI_D_DESC; + +def AND_V : AND_V_ENC, AND_V_DESC; +def AND_V_H_PSEUDO : AND_V_H_PSEUDO_DESC, + PseudoInstExpansion<(AND_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def AND_V_W_PSEUDO : AND_V_W_PSEUDO_DESC, + PseudoInstExpansion<(AND_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def AND_V_D_PSEUDO : AND_V_D_PSEUDO_DESC, + PseudoInstExpansion<(AND_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; + +def ANDI_B : ANDI_B_ENC, ANDI_B_DESC; + +def ASUB_S_B : ASUB_S_B_ENC, ASUB_S_B_DESC; +def ASUB_S_H : ASUB_S_H_ENC, ASUB_S_H_DESC; +def ASUB_S_W : ASUB_S_W_ENC, ASUB_S_W_DESC; +def ASUB_S_D : ASUB_S_D_ENC, ASUB_S_D_DESC; + +def ASUB_U_B : ASUB_U_B_ENC, ASUB_U_B_DESC; +def ASUB_U_H : ASUB_U_H_ENC, ASUB_U_H_DESC; +def ASUB_U_W : ASUB_U_W_ENC, ASUB_U_W_DESC; +def ASUB_U_D : ASUB_U_D_ENC, ASUB_U_D_DESC; + +def AVE_S_B : AVE_S_B_ENC, AVE_S_B_DESC; +def AVE_S_H : AVE_S_H_ENC, AVE_S_H_DESC; +def AVE_S_W : AVE_S_W_ENC, AVE_S_W_DESC; +def AVE_S_D : AVE_S_D_ENC, AVE_S_D_DESC; + +def AVE_U_B : AVE_U_B_ENC, AVE_U_B_DESC; +def AVE_U_H : AVE_U_H_ENC, AVE_U_H_DESC; +def AVE_U_W : AVE_U_W_ENC, AVE_U_W_DESC; +def AVE_U_D : AVE_U_D_ENC, AVE_U_D_DESC; + +def AVER_S_B : AVER_S_B_ENC, AVER_S_B_DESC; +def AVER_S_H : AVER_S_H_ENC, AVER_S_H_DESC; +def AVER_S_W : AVER_S_W_ENC, AVER_S_W_DESC; +def AVER_S_D : AVER_S_D_ENC, AVER_S_D_DESC; + +def AVER_U_B : AVER_U_B_ENC, AVER_U_B_DESC; +def AVER_U_H : AVER_U_H_ENC, AVER_U_H_DESC; +def AVER_U_W : AVER_U_W_ENC, AVER_U_W_DESC; +def AVER_U_D : AVER_U_D_ENC, AVER_U_D_DESC; + +def BCLR_B : BCLR_B_ENC, BCLR_B_DESC; +def BCLR_H : BCLR_H_ENC, BCLR_H_DESC; +def BCLR_W : BCLR_W_ENC, BCLR_W_DESC; +def BCLR_D : BCLR_D_ENC, BCLR_D_DESC; + +def BCLRI_B : BCLRI_B_ENC, BCLRI_B_DESC; +def BCLRI_H : BCLRI_H_ENC, BCLRI_H_DESC; +def BCLRI_W : BCLRI_W_ENC, BCLRI_W_DESC; +def BCLRI_D : BCLRI_D_ENC, BCLRI_D_DESC; + +def BINSL_B : BINSL_B_ENC, BINSL_B_DESC; +def BINSL_H : BINSL_H_ENC, BINSL_H_DESC; +def BINSL_W : BINSL_W_ENC, BINSL_W_DESC; +def BINSL_D : BINSL_D_ENC, BINSL_D_DESC; + +def BINSLI_B : BINSLI_B_ENC, BINSLI_B_DESC; +def BINSLI_H : BINSLI_H_ENC, BINSLI_H_DESC; +def BINSLI_W : BINSLI_W_ENC, BINSLI_W_DESC; +def BINSLI_D : BINSLI_D_ENC, BINSLI_D_DESC; + +def BINSR_B : BINSR_B_ENC, BINSR_B_DESC; +def BINSR_H : BINSR_H_ENC, BINSR_H_DESC; +def BINSR_W : BINSR_W_ENC, BINSR_W_DESC; +def BINSR_D : BINSR_D_ENC, BINSR_D_DESC; + +def BINSRI_B : BINSRI_B_ENC, BINSRI_B_DESC; +def BINSRI_H : BINSRI_H_ENC, BINSRI_H_DESC; +def BINSRI_W : BINSRI_W_ENC, BINSRI_W_DESC; +def BINSRI_D : BINSRI_D_ENC, BINSRI_D_DESC; + +def BMNZ_V : BMNZ_V_ENC, BMNZ_V_DESC; + +def BMNZI_B : BMNZI_B_ENC, BMNZI_B_DESC; + +def BMZ_V : BMZ_V_ENC, BMZ_V_DESC; + +def BMZI_B : BMZI_B_ENC, BMZI_B_DESC; + +def BNEG_B : BNEG_B_ENC, BNEG_B_DESC; +def BNEG_H : BNEG_H_ENC, BNEG_H_DESC; +def BNEG_W : BNEG_W_ENC, BNEG_W_DESC; +def BNEG_D : BNEG_D_ENC, BNEG_D_DESC; + +def BNEGI_B : BNEGI_B_ENC, BNEGI_B_DESC; +def BNEGI_H : BNEGI_H_ENC, BNEGI_H_DESC; +def BNEGI_W : BNEGI_W_ENC, BNEGI_W_DESC; +def BNEGI_D : BNEGI_D_ENC, BNEGI_D_DESC; + +def BNZ_B : BNZ_B_ENC, BNZ_B_DESC; +def BNZ_H : BNZ_H_ENC, BNZ_H_DESC; +def BNZ_W : BNZ_W_ENC, BNZ_W_DESC; +def BNZ_D : BNZ_D_ENC, BNZ_D_DESC; + +def BNZ_V : BNZ_V_ENC, BNZ_V_DESC; + +def BSEL_V : BSEL_V_ENC, BSEL_V_DESC; + +class MSA_BSEL_PSEUDO_BASE<RegisterOperand RO, ValueType Ty> : + MipsPseudo<(outs RO:$wd), (ins RO:$wd_in, RO:$ws, RO:$wt), + [(set RO:$wd, (Ty (vselect RO:$wd_in, RO:$ws, RO:$wt)))]>, + PseudoInstExpansion<(BSEL_V MSA128BOpnd:$wd, MSA128BOpnd:$wd_in, + MSA128BOpnd:$ws, MSA128BOpnd:$wt)> { + let Constraints = "$wd_in = $wd"; +} + +def BSEL_H_PSEUDO : MSA_BSEL_PSEUDO_BASE<MSA128HOpnd, v8i16>; +def BSEL_W_PSEUDO : MSA_BSEL_PSEUDO_BASE<MSA128WOpnd, v4i32>; +def BSEL_D_PSEUDO : MSA_BSEL_PSEUDO_BASE<MSA128DOpnd, v2i64>; +def BSEL_FW_PSEUDO : MSA_BSEL_PSEUDO_BASE<MSA128WOpnd, v4f32>; +def BSEL_FD_PSEUDO : MSA_BSEL_PSEUDO_BASE<MSA128DOpnd, v2f64>; + +def BSELI_B : BSELI_B_ENC, BSELI_B_DESC; + +def BSET_B : BSET_B_ENC, BSET_B_DESC; +def BSET_H : BSET_H_ENC, BSET_H_DESC; +def BSET_W : BSET_W_ENC, BSET_W_DESC; +def BSET_D : BSET_D_ENC, BSET_D_DESC; + +def BSETI_B : BSETI_B_ENC, BSETI_B_DESC; +def BSETI_H : BSETI_H_ENC, BSETI_H_DESC; +def BSETI_W : BSETI_W_ENC, BSETI_W_DESC; +def BSETI_D : BSETI_D_ENC, BSETI_D_DESC; + +def BZ_B : BZ_B_ENC, BZ_B_DESC; +def BZ_H : BZ_H_ENC, BZ_H_DESC; +def BZ_W : BZ_W_ENC, BZ_W_DESC; +def BZ_D : BZ_D_ENC, BZ_D_DESC; + +def BZ_V : BZ_V_ENC, BZ_V_DESC; + +def CEQ_B : CEQ_B_ENC, CEQ_B_DESC; +def CEQ_H : CEQ_H_ENC, CEQ_H_DESC; +def CEQ_W : CEQ_W_ENC, CEQ_W_DESC; +def CEQ_D : CEQ_D_ENC, CEQ_D_DESC; + +def CEQI_B : CEQI_B_ENC, CEQI_B_DESC; +def CEQI_H : CEQI_H_ENC, CEQI_H_DESC; +def CEQI_W : CEQI_W_ENC, CEQI_W_DESC; +def CEQI_D : CEQI_D_ENC, CEQI_D_DESC; + +def CFCMSA : CFCMSA_ENC, CFCMSA_DESC; + +def CLE_S_B : CLE_S_B_ENC, CLE_S_B_DESC; +def CLE_S_H : CLE_S_H_ENC, CLE_S_H_DESC; +def CLE_S_W : CLE_S_W_ENC, CLE_S_W_DESC; +def CLE_S_D : CLE_S_D_ENC, CLE_S_D_DESC; + +def CLE_U_B : CLE_U_B_ENC, CLE_U_B_DESC; +def CLE_U_H : CLE_U_H_ENC, CLE_U_H_DESC; +def CLE_U_W : CLE_U_W_ENC, CLE_U_W_DESC; +def CLE_U_D : CLE_U_D_ENC, CLE_U_D_DESC; + +def CLEI_S_B : CLEI_S_B_ENC, CLEI_S_B_DESC; +def CLEI_S_H : CLEI_S_H_ENC, CLEI_S_H_DESC; +def CLEI_S_W : CLEI_S_W_ENC, CLEI_S_W_DESC; +def CLEI_S_D : CLEI_S_D_ENC, CLEI_S_D_DESC; + +def CLEI_U_B : CLEI_U_B_ENC, CLEI_U_B_DESC; +def CLEI_U_H : CLEI_U_H_ENC, CLEI_U_H_DESC; +def CLEI_U_W : CLEI_U_W_ENC, CLEI_U_W_DESC; +def CLEI_U_D : CLEI_U_D_ENC, CLEI_U_D_DESC; + +def CLT_S_B : CLT_S_B_ENC, CLT_S_B_DESC; +def CLT_S_H : CLT_S_H_ENC, CLT_S_H_DESC; +def CLT_S_W : CLT_S_W_ENC, CLT_S_W_DESC; +def CLT_S_D : CLT_S_D_ENC, CLT_S_D_DESC; + +def CLT_U_B : CLT_U_B_ENC, CLT_U_B_DESC; +def CLT_U_H : CLT_U_H_ENC, CLT_U_H_DESC; +def CLT_U_W : CLT_U_W_ENC, CLT_U_W_DESC; +def CLT_U_D : CLT_U_D_ENC, CLT_U_D_DESC; + +def CLTI_S_B : CLTI_S_B_ENC, CLTI_S_B_DESC; +def CLTI_S_H : CLTI_S_H_ENC, CLTI_S_H_DESC; +def CLTI_S_W : CLTI_S_W_ENC, CLTI_S_W_DESC; +def CLTI_S_D : CLTI_S_D_ENC, CLTI_S_D_DESC; + +def CLTI_U_B : CLTI_U_B_ENC, CLTI_U_B_DESC; +def CLTI_U_H : CLTI_U_H_ENC, CLTI_U_H_DESC; +def CLTI_U_W : CLTI_U_W_ENC, CLTI_U_W_DESC; +def CLTI_U_D : CLTI_U_D_ENC, CLTI_U_D_DESC; + +def COPY_S_B : COPY_S_B_ENC, COPY_S_B_DESC; +def COPY_S_H : COPY_S_H_ENC, COPY_S_H_DESC; +def COPY_S_W : COPY_S_W_ENC, COPY_S_W_DESC; + +def COPY_U_B : COPY_U_B_ENC, COPY_U_B_DESC; +def COPY_U_H : COPY_U_H_ENC, COPY_U_H_DESC; +def COPY_U_W : COPY_U_W_ENC, COPY_U_W_DESC; + +def COPY_FW_PSEUDO : COPY_FW_PSEUDO_DESC; +def COPY_FD_PSEUDO : COPY_FD_PSEUDO_DESC; + +def CTCMSA : CTCMSA_ENC, CTCMSA_DESC; + +def DIV_S_B : DIV_S_B_ENC, DIV_S_B_DESC; +def DIV_S_H : DIV_S_H_ENC, DIV_S_H_DESC; +def DIV_S_W : DIV_S_W_ENC, DIV_S_W_DESC; +def DIV_S_D : DIV_S_D_ENC, DIV_S_D_DESC; + +def DIV_U_B : DIV_U_B_ENC, DIV_U_B_DESC; +def DIV_U_H : DIV_U_H_ENC, DIV_U_H_DESC; +def DIV_U_W : DIV_U_W_ENC, DIV_U_W_DESC; +def DIV_U_D : DIV_U_D_ENC, DIV_U_D_DESC; + +def DOTP_S_H : DOTP_S_H_ENC, DOTP_S_H_DESC; +def DOTP_S_W : DOTP_S_W_ENC, DOTP_S_W_DESC; +def DOTP_S_D : DOTP_S_D_ENC, DOTP_S_D_DESC; + +def DOTP_U_H : DOTP_U_H_ENC, DOTP_U_H_DESC; +def DOTP_U_W : DOTP_U_W_ENC, DOTP_U_W_DESC; +def DOTP_U_D : DOTP_U_D_ENC, DOTP_U_D_DESC; + +def DPADD_S_H : DPADD_S_H_ENC, DPADD_S_H_DESC; +def DPADD_S_W : DPADD_S_W_ENC, DPADD_S_W_DESC; +def DPADD_S_D : DPADD_S_D_ENC, DPADD_S_D_DESC; + +def DPADD_U_H : DPADD_U_H_ENC, DPADD_U_H_DESC; +def DPADD_U_W : DPADD_U_W_ENC, DPADD_U_W_DESC; +def DPADD_U_D : DPADD_U_D_ENC, DPADD_U_D_DESC; + +def DPSUB_S_H : DPSUB_S_H_ENC, DPSUB_S_H_DESC; +def DPSUB_S_W : DPSUB_S_W_ENC, DPSUB_S_W_DESC; +def DPSUB_S_D : DPSUB_S_D_ENC, DPSUB_S_D_DESC; + +def DPSUB_U_H : DPSUB_U_H_ENC, DPSUB_U_H_DESC; +def DPSUB_U_W : DPSUB_U_W_ENC, DPSUB_U_W_DESC; +def DPSUB_U_D : DPSUB_U_D_ENC, DPSUB_U_D_DESC; + +def FADD_W : FADD_W_ENC, FADD_W_DESC; +def FADD_D : FADD_D_ENC, FADD_D_DESC; + +def FCAF_W : FCAF_W_ENC, FCAF_W_DESC; +def FCAF_D : FCAF_D_ENC, FCAF_D_DESC; + +def FCEQ_W : FCEQ_W_ENC, FCEQ_W_DESC; +def FCEQ_D : FCEQ_D_ENC, FCEQ_D_DESC; + +def FCLE_W : FCLE_W_ENC, FCLE_W_DESC; +def FCLE_D : FCLE_D_ENC, FCLE_D_DESC; + +def FCLT_W : FCLT_W_ENC, FCLT_W_DESC; +def FCLT_D : FCLT_D_ENC, FCLT_D_DESC; + +def FCLASS_W : FCLASS_W_ENC, FCLASS_W_DESC; +def FCLASS_D : FCLASS_D_ENC, FCLASS_D_DESC; + +def FCNE_W : FCNE_W_ENC, FCNE_W_DESC; +def FCNE_D : FCNE_D_ENC, FCNE_D_DESC; + +def FCOR_W : FCOR_W_ENC, FCOR_W_DESC; +def FCOR_D : FCOR_D_ENC, FCOR_D_DESC; + +def FCUEQ_W : FCUEQ_W_ENC, FCUEQ_W_DESC; +def FCUEQ_D : FCUEQ_D_ENC, FCUEQ_D_DESC; + +def FCULE_W : FCULE_W_ENC, FCULE_W_DESC; +def FCULE_D : FCULE_D_ENC, FCULE_D_DESC; + +def FCULT_W : FCULT_W_ENC, FCULT_W_DESC; +def FCULT_D : FCULT_D_ENC, FCULT_D_DESC; + +def FCUN_W : FCUN_W_ENC, FCUN_W_DESC; +def FCUN_D : FCUN_D_ENC, FCUN_D_DESC; + +def FCUNE_W : FCUNE_W_ENC, FCUNE_W_DESC; +def FCUNE_D : FCUNE_D_ENC, FCUNE_D_DESC; + +def FDIV_W : FDIV_W_ENC, FDIV_W_DESC; +def FDIV_D : FDIV_D_ENC, FDIV_D_DESC; + +def FEXDO_H : FEXDO_H_ENC, FEXDO_H_DESC; +def FEXDO_W : FEXDO_W_ENC, FEXDO_W_DESC; + +def FEXP2_W : FEXP2_W_ENC, FEXP2_W_DESC; +def FEXP2_D : FEXP2_D_ENC, FEXP2_D_DESC; +def FEXP2_W_1_PSEUDO : FEXP2_W_1_PSEUDO_DESC; +def FEXP2_D_1_PSEUDO : FEXP2_D_1_PSEUDO_DESC; + +def FEXUPL_W : FEXUPL_W_ENC, FEXUPL_W_DESC; +def FEXUPL_D : FEXUPL_D_ENC, FEXUPL_D_DESC; + +def FEXUPR_W : FEXUPR_W_ENC, FEXUPR_W_DESC; +def FEXUPR_D : FEXUPR_D_ENC, FEXUPR_D_DESC; + +def FFINT_S_W : FFINT_S_W_ENC, FFINT_S_W_DESC; +def FFINT_S_D : FFINT_S_D_ENC, FFINT_S_D_DESC; + +def FFINT_U_W : FFINT_U_W_ENC, FFINT_U_W_DESC; +def FFINT_U_D : FFINT_U_D_ENC, FFINT_U_D_DESC; + +def FFQL_W : FFQL_W_ENC, FFQL_W_DESC; +def FFQL_D : FFQL_D_ENC, FFQL_D_DESC; + +def FFQR_W : FFQR_W_ENC, FFQR_W_DESC; +def FFQR_D : FFQR_D_ENC, FFQR_D_DESC; + +def FILL_B : FILL_B_ENC, FILL_B_DESC; +def FILL_H : FILL_H_ENC, FILL_H_DESC; +def FILL_W : FILL_W_ENC, FILL_W_DESC; +def FILL_FW_PSEUDO : FILL_FW_PSEUDO_DESC; +def FILL_FD_PSEUDO : FILL_FD_PSEUDO_DESC; + +def FLOG2_W : FLOG2_W_ENC, FLOG2_W_DESC; +def FLOG2_D : FLOG2_D_ENC, FLOG2_D_DESC; + +def FMADD_W : FMADD_W_ENC, FMADD_W_DESC; +def FMADD_D : FMADD_D_ENC, FMADD_D_DESC; + +def FMAX_W : FMAX_W_ENC, FMAX_W_DESC; +def FMAX_D : FMAX_D_ENC, FMAX_D_DESC; + +def FMAX_A_W : FMAX_A_W_ENC, FMAX_A_W_DESC; +def FMAX_A_D : FMAX_A_D_ENC, FMAX_A_D_DESC; + +def FMIN_W : FMIN_W_ENC, FMIN_W_DESC; +def FMIN_D : FMIN_D_ENC, FMIN_D_DESC; + +def FMIN_A_W : FMIN_A_W_ENC, FMIN_A_W_DESC; +def FMIN_A_D : FMIN_A_D_ENC, FMIN_A_D_DESC; + +def FMSUB_W : FMSUB_W_ENC, FMSUB_W_DESC; +def FMSUB_D : FMSUB_D_ENC, FMSUB_D_DESC; + +def FMUL_W : FMUL_W_ENC, FMUL_W_DESC; +def FMUL_D : FMUL_D_ENC, FMUL_D_DESC; + +def FRINT_W : FRINT_W_ENC, FRINT_W_DESC; +def FRINT_D : FRINT_D_ENC, FRINT_D_DESC; + +def FRCP_W : FRCP_W_ENC, FRCP_W_DESC; +def FRCP_D : FRCP_D_ENC, FRCP_D_DESC; + +def FRSQRT_W : FRSQRT_W_ENC, FRSQRT_W_DESC; +def FRSQRT_D : FRSQRT_D_ENC, FRSQRT_D_DESC; + +def FSAF_W : FSAF_W_ENC, FSAF_W_DESC; +def FSAF_D : FSAF_D_ENC, FSAF_D_DESC; + +def FSEQ_W : FSEQ_W_ENC, FSEQ_W_DESC; +def FSEQ_D : FSEQ_D_ENC, FSEQ_D_DESC; + +def FSLE_W : FSLE_W_ENC, FSLE_W_DESC; +def FSLE_D : FSLE_D_ENC, FSLE_D_DESC; + +def FSLT_W : FSLT_W_ENC, FSLT_W_DESC; +def FSLT_D : FSLT_D_ENC, FSLT_D_DESC; + +def FSNE_W : FSNE_W_ENC, FSNE_W_DESC; +def FSNE_D : FSNE_D_ENC, FSNE_D_DESC; + +def FSOR_W : FSOR_W_ENC, FSOR_W_DESC; +def FSOR_D : FSOR_D_ENC, FSOR_D_DESC; + +def FSQRT_W : FSQRT_W_ENC, FSQRT_W_DESC; +def FSQRT_D : FSQRT_D_ENC, FSQRT_D_DESC; + +def FSUB_W : FSUB_W_ENC, FSUB_W_DESC; +def FSUB_D : FSUB_D_ENC, FSUB_D_DESC; + +def FSUEQ_W : FSUEQ_W_ENC, FSUEQ_W_DESC; +def FSUEQ_D : FSUEQ_D_ENC, FSUEQ_D_DESC; + +def FSULE_W : FSULE_W_ENC, FSULE_W_DESC; +def FSULE_D : FSULE_D_ENC, FSULE_D_DESC; + +def FSULT_W : FSULT_W_ENC, FSULT_W_DESC; +def FSULT_D : FSULT_D_ENC, FSULT_D_DESC; + +def FSUN_W : FSUN_W_ENC, FSUN_W_DESC; +def FSUN_D : FSUN_D_ENC, FSUN_D_DESC; + +def FSUNE_W : FSUNE_W_ENC, FSUNE_W_DESC; +def FSUNE_D : FSUNE_D_ENC, FSUNE_D_DESC; + +def FTINT_S_W : FTINT_S_W_ENC, FTINT_S_W_DESC; +def FTINT_S_D : FTINT_S_D_ENC, FTINT_S_D_DESC; + +def FTINT_U_W : FTINT_U_W_ENC, FTINT_U_W_DESC; +def FTINT_U_D : FTINT_U_D_ENC, FTINT_U_D_DESC; + +def FTQ_H : FTQ_H_ENC, FTQ_H_DESC; +def FTQ_W : FTQ_W_ENC, FTQ_W_DESC; + +def FTRUNC_S_W : FTRUNC_S_W_ENC, FTRUNC_S_W_DESC; +def FTRUNC_S_D : FTRUNC_S_D_ENC, FTRUNC_S_D_DESC; + +def FTRUNC_U_W : FTRUNC_U_W_ENC, FTRUNC_U_W_DESC; +def FTRUNC_U_D : FTRUNC_U_D_ENC, FTRUNC_U_D_DESC; + +def HADD_S_H : HADD_S_H_ENC, HADD_S_H_DESC; +def HADD_S_W : HADD_S_W_ENC, HADD_S_W_DESC; +def HADD_S_D : HADD_S_D_ENC, HADD_S_D_DESC; + +def HADD_U_H : HADD_U_H_ENC, HADD_U_H_DESC; +def HADD_U_W : HADD_U_W_ENC, HADD_U_W_DESC; +def HADD_U_D : HADD_U_D_ENC, HADD_U_D_DESC; + +def HSUB_S_H : HSUB_S_H_ENC, HSUB_S_H_DESC; +def HSUB_S_W : HSUB_S_W_ENC, HSUB_S_W_DESC; +def HSUB_S_D : HSUB_S_D_ENC, HSUB_S_D_DESC; + +def HSUB_U_H : HSUB_U_H_ENC, HSUB_U_H_DESC; +def HSUB_U_W : HSUB_U_W_ENC, HSUB_U_W_DESC; +def HSUB_U_D : HSUB_U_D_ENC, HSUB_U_D_DESC; + +def ILVEV_B : ILVEV_B_ENC, ILVEV_B_DESC; +def ILVEV_H : ILVEV_H_ENC, ILVEV_H_DESC; +def ILVEV_W : ILVEV_W_ENC, ILVEV_W_DESC; +def ILVEV_D : ILVEV_D_ENC, ILVEV_D_DESC; + +def ILVL_B : ILVL_B_ENC, ILVL_B_DESC; +def ILVL_H : ILVL_H_ENC, ILVL_H_DESC; +def ILVL_W : ILVL_W_ENC, ILVL_W_DESC; +def ILVL_D : ILVL_D_ENC, ILVL_D_DESC; + +def ILVOD_B : ILVOD_B_ENC, ILVOD_B_DESC; +def ILVOD_H : ILVOD_H_ENC, ILVOD_H_DESC; +def ILVOD_W : ILVOD_W_ENC, ILVOD_W_DESC; +def ILVOD_D : ILVOD_D_ENC, ILVOD_D_DESC; + +def ILVR_B : ILVR_B_ENC, ILVR_B_DESC; +def ILVR_H : ILVR_H_ENC, ILVR_H_DESC; +def ILVR_W : ILVR_W_ENC, ILVR_W_DESC; +def ILVR_D : ILVR_D_ENC, ILVR_D_DESC; + +def INSERT_B : INSERT_B_ENC, INSERT_B_DESC; +def INSERT_H : INSERT_H_ENC, INSERT_H_DESC; +def INSERT_W : INSERT_W_ENC, INSERT_W_DESC; + +// INSERT_FW_PSEUDO defined after INSVE_W +// INSERT_FD_PSEUDO defined after INSVE_D + +def INSVE_B : INSVE_B_ENC, INSVE_B_DESC; +def INSVE_H : INSVE_H_ENC, INSVE_H_DESC; +def INSVE_W : INSVE_W_ENC, INSVE_W_DESC; +def INSVE_D : INSVE_D_ENC, INSVE_D_DESC; + +def INSERT_FW_PSEUDO : INSERT_FW_PSEUDO_DESC; +def INSERT_FD_PSEUDO : INSERT_FD_PSEUDO_DESC; + +def LD_B: LD_B_ENC, LD_B_DESC; +def LD_H: LD_H_ENC, LD_H_DESC; +def LD_W: LD_W_ENC, LD_W_DESC; +def LD_D: LD_D_ENC, LD_D_DESC; + +def LDI_B : LDI_B_ENC, LDI_B_DESC; +def LDI_H : LDI_H_ENC, LDI_H_DESC; +def LDI_W : LDI_W_ENC, LDI_W_DESC; +def LDI_D : LDI_D_ENC, LDI_D_DESC; + +def LSA : LSA_ENC, LSA_DESC; + +def MADD_Q_H : MADD_Q_H_ENC, MADD_Q_H_DESC; +def MADD_Q_W : MADD_Q_W_ENC, MADD_Q_W_DESC; + +def MADDR_Q_H : MADDR_Q_H_ENC, MADDR_Q_H_DESC; +def MADDR_Q_W : MADDR_Q_W_ENC, MADDR_Q_W_DESC; + +def MADDV_B : MADDV_B_ENC, MADDV_B_DESC; +def MADDV_H : MADDV_H_ENC, MADDV_H_DESC; +def MADDV_W : MADDV_W_ENC, MADDV_W_DESC; +def MADDV_D : MADDV_D_ENC, MADDV_D_DESC; + +def MAX_A_B : MAX_A_B_ENC, MAX_A_B_DESC; +def MAX_A_H : MAX_A_H_ENC, MAX_A_H_DESC; +def MAX_A_W : MAX_A_W_ENC, MAX_A_W_DESC; +def MAX_A_D : MAX_A_D_ENC, MAX_A_D_DESC; + +def MAX_S_B : MAX_S_B_ENC, MAX_S_B_DESC; +def MAX_S_H : MAX_S_H_ENC, MAX_S_H_DESC; +def MAX_S_W : MAX_S_W_ENC, MAX_S_W_DESC; +def MAX_S_D : MAX_S_D_ENC, MAX_S_D_DESC; + +def MAX_U_B : MAX_U_B_ENC, MAX_U_B_DESC; +def MAX_U_H : MAX_U_H_ENC, MAX_U_H_DESC; +def MAX_U_W : MAX_U_W_ENC, MAX_U_W_DESC; +def MAX_U_D : MAX_U_D_ENC, MAX_U_D_DESC; + +def MAXI_S_B : MAXI_S_B_ENC, MAXI_S_B_DESC; +def MAXI_S_H : MAXI_S_H_ENC, MAXI_S_H_DESC; +def MAXI_S_W : MAXI_S_W_ENC, MAXI_S_W_DESC; +def MAXI_S_D : MAXI_S_D_ENC, MAXI_S_D_DESC; + +def MAXI_U_B : MAXI_U_B_ENC, MAXI_U_B_DESC; +def MAXI_U_H : MAXI_U_H_ENC, MAXI_U_H_DESC; +def MAXI_U_W : MAXI_U_W_ENC, MAXI_U_W_DESC; +def MAXI_U_D : MAXI_U_D_ENC, MAXI_U_D_DESC; + +def MIN_A_B : MIN_A_B_ENC, MIN_A_B_DESC; +def MIN_A_H : MIN_A_H_ENC, MIN_A_H_DESC; +def MIN_A_W : MIN_A_W_ENC, MIN_A_W_DESC; +def MIN_A_D : MIN_A_D_ENC, MIN_A_D_DESC; + +def MIN_S_B : MIN_S_B_ENC, MIN_S_B_DESC; +def MIN_S_H : MIN_S_H_ENC, MIN_S_H_DESC; +def MIN_S_W : MIN_S_W_ENC, MIN_S_W_DESC; +def MIN_S_D : MIN_S_D_ENC, MIN_S_D_DESC; + +def MIN_U_B : MIN_U_B_ENC, MIN_U_B_DESC; +def MIN_U_H : MIN_U_H_ENC, MIN_U_H_DESC; +def MIN_U_W : MIN_U_W_ENC, MIN_U_W_DESC; +def MIN_U_D : MIN_U_D_ENC, MIN_U_D_DESC; + +def MINI_S_B : MINI_S_B_ENC, MINI_S_B_DESC; +def MINI_S_H : MINI_S_H_ENC, MINI_S_H_DESC; +def MINI_S_W : MINI_S_W_ENC, MINI_S_W_DESC; +def MINI_S_D : MINI_S_D_ENC, MINI_S_D_DESC; + +def MINI_U_B : MINI_U_B_ENC, MINI_U_B_DESC; +def MINI_U_H : MINI_U_H_ENC, MINI_U_H_DESC; +def MINI_U_W : MINI_U_W_ENC, MINI_U_W_DESC; +def MINI_U_D : MINI_U_D_ENC, MINI_U_D_DESC; + +def MOD_S_B : MOD_S_B_ENC, MOD_S_B_DESC; +def MOD_S_H : MOD_S_H_ENC, MOD_S_H_DESC; +def MOD_S_W : MOD_S_W_ENC, MOD_S_W_DESC; +def MOD_S_D : MOD_S_D_ENC, MOD_S_D_DESC; + +def MOD_U_B : MOD_U_B_ENC, MOD_U_B_DESC; +def MOD_U_H : MOD_U_H_ENC, MOD_U_H_DESC; +def MOD_U_W : MOD_U_W_ENC, MOD_U_W_DESC; +def MOD_U_D : MOD_U_D_ENC, MOD_U_D_DESC; + +def MOVE_V : MOVE_V_ENC, MOVE_V_DESC; + +def MSUB_Q_H : MSUB_Q_H_ENC, MSUB_Q_H_DESC; +def MSUB_Q_W : MSUB_Q_W_ENC, MSUB_Q_W_DESC; + +def MSUBR_Q_H : MSUBR_Q_H_ENC, MSUBR_Q_H_DESC; +def MSUBR_Q_W : MSUBR_Q_W_ENC, MSUBR_Q_W_DESC; + +def MSUBV_B : MSUBV_B_ENC, MSUBV_B_DESC; +def MSUBV_H : MSUBV_H_ENC, MSUBV_H_DESC; +def MSUBV_W : MSUBV_W_ENC, MSUBV_W_DESC; +def MSUBV_D : MSUBV_D_ENC, MSUBV_D_DESC; + +def MUL_Q_H : MUL_Q_H_ENC, MUL_Q_H_DESC; +def MUL_Q_W : MUL_Q_W_ENC, MUL_Q_W_DESC; + +def MULR_Q_H : MULR_Q_H_ENC, MULR_Q_H_DESC; +def MULR_Q_W : MULR_Q_W_ENC, MULR_Q_W_DESC; + +def MULV_B : MULV_B_ENC, MULV_B_DESC; +def MULV_H : MULV_H_ENC, MULV_H_DESC; +def MULV_W : MULV_W_ENC, MULV_W_DESC; +def MULV_D : MULV_D_ENC, MULV_D_DESC; + +def NLOC_B : NLOC_B_ENC, NLOC_B_DESC; +def NLOC_H : NLOC_H_ENC, NLOC_H_DESC; +def NLOC_W : NLOC_W_ENC, NLOC_W_DESC; +def NLOC_D : NLOC_D_ENC, NLOC_D_DESC; + +def NLZC_B : NLZC_B_ENC, NLZC_B_DESC; +def NLZC_H : NLZC_H_ENC, NLZC_H_DESC; +def NLZC_W : NLZC_W_ENC, NLZC_W_DESC; +def NLZC_D : NLZC_D_ENC, NLZC_D_DESC; + +def NOR_V : NOR_V_ENC, NOR_V_DESC; +def NOR_V_H_PSEUDO : NOR_V_H_PSEUDO_DESC, + PseudoInstExpansion<(NOR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def NOR_V_W_PSEUDO : NOR_V_W_PSEUDO_DESC, + PseudoInstExpansion<(NOR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def NOR_V_D_PSEUDO : NOR_V_D_PSEUDO_DESC, + PseudoInstExpansion<(NOR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; + +def NORI_B : NORI_B_ENC, NORI_B_DESC; + +def OR_V : OR_V_ENC, OR_V_DESC; +def OR_V_H_PSEUDO : OR_V_H_PSEUDO_DESC, + PseudoInstExpansion<(OR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def OR_V_W_PSEUDO : OR_V_W_PSEUDO_DESC, + PseudoInstExpansion<(OR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def OR_V_D_PSEUDO : OR_V_D_PSEUDO_DESC, + PseudoInstExpansion<(OR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; + +def ORI_B : ORI_B_ENC, ORI_B_DESC; + +def PCKEV_B : PCKEV_B_ENC, PCKEV_B_DESC; +def PCKEV_H : PCKEV_H_ENC, PCKEV_H_DESC; +def PCKEV_W : PCKEV_W_ENC, PCKEV_W_DESC; +def PCKEV_D : PCKEV_D_ENC, PCKEV_D_DESC; + +def PCKOD_B : PCKOD_B_ENC, PCKOD_B_DESC; +def PCKOD_H : PCKOD_H_ENC, PCKOD_H_DESC; +def PCKOD_W : PCKOD_W_ENC, PCKOD_W_DESC; +def PCKOD_D : PCKOD_D_ENC, PCKOD_D_DESC; + +def PCNT_B : PCNT_B_ENC, PCNT_B_DESC; +def PCNT_H : PCNT_H_ENC, PCNT_H_DESC; +def PCNT_W : PCNT_W_ENC, PCNT_W_DESC; +def PCNT_D : PCNT_D_ENC, PCNT_D_DESC; + +def SAT_S_B : SAT_S_B_ENC, SAT_S_B_DESC; +def SAT_S_H : SAT_S_H_ENC, SAT_S_H_DESC; +def SAT_S_W : SAT_S_W_ENC, SAT_S_W_DESC; +def SAT_S_D : SAT_S_D_ENC, SAT_S_D_DESC; + +def SAT_U_B : SAT_U_B_ENC, SAT_U_B_DESC; +def SAT_U_H : SAT_U_H_ENC, SAT_U_H_DESC; +def SAT_U_W : SAT_U_W_ENC, SAT_U_W_DESC; +def SAT_U_D : SAT_U_D_ENC, SAT_U_D_DESC; + +def SHF_B : SHF_B_ENC, SHF_B_DESC; +def SHF_H : SHF_H_ENC, SHF_H_DESC; +def SHF_W : SHF_W_ENC, SHF_W_DESC; + +def SLD_B : SLD_B_ENC, SLD_B_DESC; +def SLD_H : SLD_H_ENC, SLD_H_DESC; +def SLD_W : SLD_W_ENC, SLD_W_DESC; +def SLD_D : SLD_D_ENC, SLD_D_DESC; + +def SLDI_B : SLDI_B_ENC, SLDI_B_DESC; +def SLDI_H : SLDI_H_ENC, SLDI_H_DESC; +def SLDI_W : SLDI_W_ENC, SLDI_W_DESC; +def SLDI_D : SLDI_D_ENC, SLDI_D_DESC; + +def SLL_B : SLL_B_ENC, SLL_B_DESC; +def SLL_H : SLL_H_ENC, SLL_H_DESC; +def SLL_W : SLL_W_ENC, SLL_W_DESC; +def SLL_D : SLL_D_ENC, SLL_D_DESC; + +def SLLI_B : SLLI_B_ENC, SLLI_B_DESC; +def SLLI_H : SLLI_H_ENC, SLLI_H_DESC; +def SLLI_W : SLLI_W_ENC, SLLI_W_DESC; +def SLLI_D : SLLI_D_ENC, SLLI_D_DESC; + +def SPLAT_B : SPLAT_B_ENC, SPLAT_B_DESC; +def SPLAT_H : SPLAT_H_ENC, SPLAT_H_DESC; +def SPLAT_W : SPLAT_W_ENC, SPLAT_W_DESC; +def SPLAT_D : SPLAT_D_ENC, SPLAT_D_DESC; + +def SPLATI_B : SPLATI_B_ENC, SPLATI_B_DESC; +def SPLATI_H : SPLATI_H_ENC, SPLATI_H_DESC; +def SPLATI_W : SPLATI_W_ENC, SPLATI_W_DESC; +def SPLATI_D : SPLATI_D_ENC, SPLATI_D_DESC; + +def SRA_B : SRA_B_ENC, SRA_B_DESC; +def SRA_H : SRA_H_ENC, SRA_H_DESC; +def SRA_W : SRA_W_ENC, SRA_W_DESC; +def SRA_D : SRA_D_ENC, SRA_D_DESC; + +def SRAI_B : SRAI_B_ENC, SRAI_B_DESC; +def SRAI_H : SRAI_H_ENC, SRAI_H_DESC; +def SRAI_W : SRAI_W_ENC, SRAI_W_DESC; +def SRAI_D : SRAI_D_ENC, SRAI_D_DESC; + +def SRAR_B : SRAR_B_ENC, SRAR_B_DESC; +def SRAR_H : SRAR_H_ENC, SRAR_H_DESC; +def SRAR_W : SRAR_W_ENC, SRAR_W_DESC; +def SRAR_D : SRAR_D_ENC, SRAR_D_DESC; + +def SRARI_B : SRARI_B_ENC, SRARI_B_DESC; +def SRARI_H : SRARI_H_ENC, SRARI_H_DESC; +def SRARI_W : SRARI_W_ENC, SRARI_W_DESC; +def SRARI_D : SRARI_D_ENC, SRARI_D_DESC; + +def SRL_B : SRL_B_ENC, SRL_B_DESC; +def SRL_H : SRL_H_ENC, SRL_H_DESC; +def SRL_W : SRL_W_ENC, SRL_W_DESC; +def SRL_D : SRL_D_ENC, SRL_D_DESC; + +def SRLI_B : SRLI_B_ENC, SRLI_B_DESC; +def SRLI_H : SRLI_H_ENC, SRLI_H_DESC; +def SRLI_W : SRLI_W_ENC, SRLI_W_DESC; +def SRLI_D : SRLI_D_ENC, SRLI_D_DESC; + +def SRLR_B : SRLR_B_ENC, SRLR_B_DESC; +def SRLR_H : SRLR_H_ENC, SRLR_H_DESC; +def SRLR_W : SRLR_W_ENC, SRLR_W_DESC; +def SRLR_D : SRLR_D_ENC, SRLR_D_DESC; + +def SRLRI_B : SRLRI_B_ENC, SRLRI_B_DESC; +def SRLRI_H : SRLRI_H_ENC, SRLRI_H_DESC; +def SRLRI_W : SRLRI_W_ENC, SRLRI_W_DESC; +def SRLRI_D : SRLRI_D_ENC, SRLRI_D_DESC; + +def ST_B: ST_B_ENC, ST_B_DESC; +def ST_H: ST_H_ENC, ST_H_DESC; +def ST_W: ST_W_ENC, ST_W_DESC; +def ST_D: ST_D_ENC, ST_D_DESC; + +def SUBS_S_B : SUBS_S_B_ENC, SUBS_S_B_DESC; +def SUBS_S_H : SUBS_S_H_ENC, SUBS_S_H_DESC; +def SUBS_S_W : SUBS_S_W_ENC, SUBS_S_W_DESC; +def SUBS_S_D : SUBS_S_D_ENC, SUBS_S_D_DESC; + +def SUBS_U_B : SUBS_U_B_ENC, SUBS_U_B_DESC; +def SUBS_U_H : SUBS_U_H_ENC, SUBS_U_H_DESC; +def SUBS_U_W : SUBS_U_W_ENC, SUBS_U_W_DESC; +def SUBS_U_D : SUBS_U_D_ENC, SUBS_U_D_DESC; + +def SUBSUS_U_B : SUBSUS_U_B_ENC, SUBSUS_U_B_DESC; +def SUBSUS_U_H : SUBSUS_U_H_ENC, SUBSUS_U_H_DESC; +def SUBSUS_U_W : SUBSUS_U_W_ENC, SUBSUS_U_W_DESC; +def SUBSUS_U_D : SUBSUS_U_D_ENC, SUBSUS_U_D_DESC; + +def SUBSUU_S_B : SUBSUU_S_B_ENC, SUBSUU_S_B_DESC; +def SUBSUU_S_H : SUBSUU_S_H_ENC, SUBSUU_S_H_DESC; +def SUBSUU_S_W : SUBSUU_S_W_ENC, SUBSUU_S_W_DESC; +def SUBSUU_S_D : SUBSUU_S_D_ENC, SUBSUU_S_D_DESC; + +def SUBV_B : SUBV_B_ENC, SUBV_B_DESC; +def SUBV_H : SUBV_H_ENC, SUBV_H_DESC; +def SUBV_W : SUBV_W_ENC, SUBV_W_DESC; +def SUBV_D : SUBV_D_ENC, SUBV_D_DESC; + +def SUBVI_B : SUBVI_B_ENC, SUBVI_B_DESC; +def SUBVI_H : SUBVI_H_ENC, SUBVI_H_DESC; +def SUBVI_W : SUBVI_W_ENC, SUBVI_W_DESC; +def SUBVI_D : SUBVI_D_ENC, SUBVI_D_DESC; + +def VSHF_B : VSHF_B_ENC, VSHF_B_DESC; +def VSHF_H : VSHF_H_ENC, VSHF_H_DESC; +def VSHF_W : VSHF_W_ENC, VSHF_W_DESC; +def VSHF_D : VSHF_D_ENC, VSHF_D_DESC; + +def XOR_V : XOR_V_ENC, XOR_V_DESC; +def XOR_V_H_PSEUDO : XOR_V_H_PSEUDO_DESC, + PseudoInstExpansion<(XOR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def XOR_V_W_PSEUDO : XOR_V_W_PSEUDO_DESC, + PseudoInstExpansion<(XOR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; +def XOR_V_D_PSEUDO : XOR_V_D_PSEUDO_DESC, + PseudoInstExpansion<(XOR_V MSA128BOpnd:$wd, + MSA128BOpnd:$ws, + MSA128BOpnd:$wt)>; + +def XORI_B : XORI_B_ENC, XORI_B_DESC; + +// Patterns. +class MSAPat<dag pattern, dag result, list<Predicate> pred = [HasMSA]> : + Pat<pattern, result>, Requires<pred>; + +def : MSAPat<(extractelt (v4i32 MSA128W:$ws), immZExt4:$idx), + (COPY_S_W MSA128W:$ws, immZExt4:$idx)>; + +def : MSAPat<(v16i8 (load addr:$addr)), (LD_B addr:$addr)>; +def : MSAPat<(v8i16 (load addr:$addr)), (LD_H addr:$addr)>; +def : MSAPat<(v4i32 (load addr:$addr)), (LD_W addr:$addr)>; +def : MSAPat<(v2i64 (load addr:$addr)), (LD_D addr:$addr)>; +def : MSAPat<(v8f16 (load addr:$addr)), (LD_H addr:$addr)>; +def : MSAPat<(v4f32 (load addr:$addr)), (LD_W addr:$addr)>; +def : MSAPat<(v2f64 (load addr:$addr)), (LD_D addr:$addr)>; + +def : MSAPat<(v8f16 (load addrRegImm:$addr)), (LD_H addrRegImm:$addr)>; +def : MSAPat<(v4f32 (load addrRegImm:$addr)), (LD_W addrRegImm:$addr)>; +def : MSAPat<(v2f64 (load addrRegImm:$addr)), (LD_D addrRegImm:$addr)>; + +def : MSAPat<(store (v16i8 MSA128B:$ws), addr:$addr), + (ST_B MSA128B:$ws, addr:$addr)>; +def : MSAPat<(store (v8i16 MSA128H:$ws), addr:$addr), + (ST_H MSA128H:$ws, addr:$addr)>; +def : MSAPat<(store (v4i32 MSA128W:$ws), addr:$addr), + (ST_W MSA128W:$ws, addr:$addr)>; +def : MSAPat<(store (v2i64 MSA128D:$ws), addr:$addr), + (ST_D MSA128D:$ws, addr:$addr)>; +def : MSAPat<(store (v8f16 MSA128H:$ws), addr:$addr), + (ST_H MSA128H:$ws, addr:$addr)>; +def : MSAPat<(store (v4f32 MSA128W:$ws), addr:$addr), + (ST_W MSA128W:$ws, addr:$addr)>; +def : MSAPat<(store (v2f64 MSA128D:$ws), addr:$addr), + (ST_D MSA128D:$ws, addr:$addr)>; + +def ST_FH : MSAPat<(store (v8f16 MSA128H:$ws), addrRegImm:$addr), + (ST_H MSA128H:$ws, addrRegImm:$addr)>; +def ST_FW : MSAPat<(store (v4f32 MSA128W:$ws), addrRegImm:$addr), + (ST_W MSA128W:$ws, addrRegImm:$addr)>; +def ST_FD : MSAPat<(store (v2f64 MSA128D:$ws), addrRegImm:$addr), + (ST_D MSA128D:$ws, addrRegImm:$addr)>; + +class MSA_FABS_PSEUDO_DESC_BASE<RegisterOperand ROWD, + RegisterOperand ROWS = ROWD, + InstrItinClass itin = NoItinerary> : + MipsPseudo<(outs ROWD:$wd), + (ins ROWS:$ws), + [(set ROWD:$wd, (fabs ROWS:$ws))]> { + InstrItinClass Itinerary = itin; +} +def FABS_W : MSA_FABS_PSEUDO_DESC_BASE<MSA128WOpnd>, + PseudoInstExpansion<(FMAX_A_W MSA128WOpnd:$wd, MSA128WOpnd:$ws, + MSA128WOpnd:$ws)>; +def FABS_D : MSA_FABS_PSEUDO_DESC_BASE<MSA128DOpnd>, + PseudoInstExpansion<(FMAX_A_D MSA128DOpnd:$wd, MSA128DOpnd:$ws, + MSA128DOpnd:$ws)>; + +class MSABitconvertPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC, list<Predicate> preds = [HasMSA]> : + MSAPat<(DstVT (bitconvert SrcVT:$src)), + (COPY_TO_REGCLASS SrcVT:$src, DstRC), preds>; + +// These are endian-independant because the element size doesnt change +def : MSABitconvertPat<v8i16, v8f16, MSA128H>; +def : MSABitconvertPat<v4i32, v4f32, MSA128W>; +def : MSABitconvertPat<v2i64, v2f64, MSA128D>; +def : MSABitconvertPat<v8f16, v8i16, MSA128H>; +def : MSABitconvertPat<v4f32, v4i32, MSA128W>; +def : MSABitconvertPat<v2f64, v2i64, MSA128D>; + +// Little endian bitcasts are always no-ops +def : MSABitconvertPat<v16i8, v8i16, MSA128B, [HasMSA, IsLE]>; +def : MSABitconvertPat<v16i8, v4i32, MSA128B, [HasMSA, IsLE]>; +def : MSABitconvertPat<v16i8, v2i64, MSA128B, [HasMSA, IsLE]>; +def : MSABitconvertPat<v16i8, v8f16, MSA128B, [HasMSA, IsLE]>; +def : MSABitconvertPat<v16i8, v4f32, MSA128B, [HasMSA, IsLE]>; +def : MSABitconvertPat<v16i8, v2f64, MSA128B, [HasMSA, IsLE]>; + +def : MSABitconvertPat<v8i16, v16i8, MSA128H, [HasMSA, IsLE]>; +def : MSABitconvertPat<v8i16, v4i32, MSA128H, [HasMSA, IsLE]>; +def : MSABitconvertPat<v8i16, v2i64, MSA128H, [HasMSA, IsLE]>; +def : MSABitconvertPat<v8i16, v4f32, MSA128H, [HasMSA, IsLE]>; +def : MSABitconvertPat<v8i16, v2f64, MSA128H, [HasMSA, IsLE]>; + +def : MSABitconvertPat<v4i32, v16i8, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4i32, v8i16, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4i32, v2i64, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4i32, v8f16, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4i32, v2f64, MSA128W, [HasMSA, IsLE]>; + +def : MSABitconvertPat<v2i64, v16i8, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2i64, v8i16, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2i64, v4i32, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2i64, v8f16, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2i64, v4f32, MSA128D, [HasMSA, IsLE]>; + +def : MSABitconvertPat<v4f32, v16i8, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4f32, v8i16, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4f32, v2i64, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4f32, v8f16, MSA128W, [HasMSA, IsLE]>; +def : MSABitconvertPat<v4f32, v2f64, MSA128W, [HasMSA, IsLE]>; + +def : MSABitconvertPat<v2f64, v16i8, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2f64, v8i16, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2f64, v4i32, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2f64, v8f16, MSA128D, [HasMSA, IsLE]>; +def : MSABitconvertPat<v2f64, v4f32, MSA128D, [HasMSA, IsLE]>; + +// Big endian bitcasts expand to shuffle instructions. +// This is because bitcast is defined to be a store/load sequence and the +// vector store/load instructions are mixed-endian with respect to the vector +// as a whole (little endian with respect to element order, but big endian +// elements). + +class MSABitconvertReverseQuartersPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC, MSAInst Insn, + RegisterClass ViaRC> : + MSAPat<(DstVT (bitconvert SrcVT:$src)), + (COPY_TO_REGCLASS (Insn (COPY_TO_REGCLASS SrcVT:$src, ViaRC), 27), + DstRC), + [HasMSA, IsBE]>; + +class MSABitconvertReverseHalvesPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC, MSAInst Insn, + RegisterClass ViaRC> : + MSAPat<(DstVT (bitconvert SrcVT:$src)), + (COPY_TO_REGCLASS (Insn (COPY_TO_REGCLASS SrcVT:$src, ViaRC), 177), + DstRC), + [HasMSA, IsBE]>; + +class MSABitconvertReverseBInHPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC> : + MSABitconvertReverseHalvesPat<DstVT, SrcVT, DstRC, SHF_B, MSA128B>; + +class MSABitconvertReverseBInWPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC> : + MSABitconvertReverseQuartersPat<DstVT, SrcVT, DstRC, SHF_B, MSA128B>; + +class MSABitconvertReverseBInDPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC> : + MSAPat<(DstVT (bitconvert SrcVT:$src)), + (COPY_TO_REGCLASS + (SHF_W + (COPY_TO_REGCLASS + (SHF_B (COPY_TO_REGCLASS SrcVT:$src, MSA128B), 27), + MSA128W), 177), + DstRC), + [HasMSA, IsBE]>; + +class MSABitconvertReverseHInWPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC> : + MSABitconvertReverseHalvesPat<DstVT, SrcVT, DstRC, SHF_H, MSA128H>; + +class MSABitconvertReverseHInDPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC> : + MSABitconvertReverseQuartersPat<DstVT, SrcVT, DstRC, SHF_H, MSA128H>; + +class MSABitconvertReverseWInDPat<ValueType DstVT, ValueType SrcVT, + RegisterClass DstRC> : + MSABitconvertReverseHalvesPat<DstVT, SrcVT, DstRC, SHF_W, MSA128W>; + +def : MSABitconvertReverseBInHPat<v8i16, v16i8, MSA128H>; +def : MSABitconvertReverseBInHPat<v8f16, v16i8, MSA128H>; +def : MSABitconvertReverseBInWPat<v4i32, v16i8, MSA128W>; +def : MSABitconvertReverseBInWPat<v4f32, v16i8, MSA128W>; +def : MSABitconvertReverseBInDPat<v2i64, v16i8, MSA128D>; +def : MSABitconvertReverseBInDPat<v2f64, v16i8, MSA128D>; + +def : MSABitconvertReverseBInHPat<v16i8, v8i16, MSA128B>; +def : MSABitconvertReverseHInWPat<v4i32, v8i16, MSA128W>; +def : MSABitconvertReverseHInWPat<v4f32, v8i16, MSA128W>; +def : MSABitconvertReverseHInDPat<v2i64, v8i16, MSA128D>; +def : MSABitconvertReverseHInDPat<v2f64, v8i16, MSA128D>; + +def : MSABitconvertReverseBInHPat<v16i8, v8f16, MSA128B>; +def : MSABitconvertReverseHInWPat<v4i32, v8f16, MSA128W>; +def : MSABitconvertReverseHInWPat<v4f32, v8f16, MSA128W>; +def : MSABitconvertReverseHInDPat<v2i64, v8f16, MSA128D>; +def : MSABitconvertReverseHInDPat<v2f64, v8f16, MSA128D>; + +def : MSABitconvertReverseBInWPat<v16i8, v4i32, MSA128B>; +def : MSABitconvertReverseHInWPat<v8i16, v4i32, MSA128H>; +def : MSABitconvertReverseHInWPat<v8f16, v4i32, MSA128H>; +def : MSABitconvertReverseWInDPat<v2i64, v4i32, MSA128D>; +def : MSABitconvertReverseWInDPat<v2f64, v4i32, MSA128D>; + +def : MSABitconvertReverseBInWPat<v16i8, v4f32, MSA128B>; +def : MSABitconvertReverseHInWPat<v8i16, v4f32, MSA128H>; +def : MSABitconvertReverseHInWPat<v8f16, v4f32, MSA128H>; +def : MSABitconvertReverseWInDPat<v2i64, v4f32, MSA128D>; +def : MSABitconvertReverseWInDPat<v2f64, v4f32, MSA128D>; + +def : MSABitconvertReverseBInDPat<v16i8, v2i64, MSA128B>; +def : MSABitconvertReverseHInDPat<v8i16, v2i64, MSA128H>; +def : MSABitconvertReverseHInDPat<v8f16, v2i64, MSA128H>; +def : MSABitconvertReverseWInDPat<v4i32, v2i64, MSA128W>; +def : MSABitconvertReverseWInDPat<v4f32, v2i64, MSA128W>; + +def : MSABitconvertReverseBInDPat<v16i8, v2f64, MSA128B>; +def : MSABitconvertReverseHInDPat<v8i16, v2f64, MSA128H>; +def : MSABitconvertReverseHInDPat<v8f16, v2f64, MSA128H>; +def : MSABitconvertReverseWInDPat<v4i32, v2f64, MSA128W>; +def : MSABitconvertReverseWInDPat<v4f32, v2f64, MSA128W>; + +// Pseudos used to implement BNZ.df, and BZ.df + +class MSA_CBRANCH_PSEUDO_DESC_BASE<SDPatternOperator OpNode, ValueType TyNode, + RegisterClass RCWS, + InstrItinClass itin = NoItinerary> : + MipsPseudo<(outs GPR32:$dst), + (ins RCWS:$ws), + [(set GPR32:$dst, (OpNode (TyNode RCWS:$ws)))]> { + bit usesCustomInserter = 1; +} + +def SNZ_B_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllNonZero, v16i8, + MSA128B, NoItinerary>; +def SNZ_H_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllNonZero, v8i16, + MSA128H, NoItinerary>; +def SNZ_W_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllNonZero, v4i32, + MSA128W, NoItinerary>; +def SNZ_D_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllNonZero, v2i64, + MSA128D, NoItinerary>; +def SNZ_V_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAnyNonZero, v16i8, + MSA128B, NoItinerary>; + +def SZ_B_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllZero, v16i8, + MSA128B, NoItinerary>; +def SZ_H_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllZero, v8i16, + MSA128H, NoItinerary>; +def SZ_W_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllZero, v4i32, + MSA128W, NoItinerary>; +def SZ_D_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAllZero, v2i64, + MSA128D, NoItinerary>; +def SZ_V_PSEUDO : MSA_CBRANCH_PSEUDO_DESC_BASE<MipsVAnyZero, v16i8, + MSA128B, NoItinerary>; diff --git a/contrib/llvm/lib/Target/Mips/MipsMachineFunction.cpp b/contrib/llvm/lib/Target/Mips/MipsMachineFunction.cpp new file mode 100644 index 000000000000..dedf802f80ac --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMachineFunction.cpp @@ -0,0 +1,141 @@ +//===-- MipsMachineFunctionInfo.cpp - Private data used for Mips ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsMachineFunction.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsInstrInfo.h" +#include "MipsSubtarget.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +static cl::opt<bool> +FixGlobalBaseReg("mips-fix-global-base-reg", cl::Hidden, cl::init(true), + cl::desc("Always use $gp as the global base register.")); + +// class MipsCallEntry. +MipsCallEntry::MipsCallEntry(const StringRef &N) { +#ifndef NDEBUG + Name = N; + Val = 0; +#endif +} + +MipsCallEntry::MipsCallEntry(const GlobalValue *V) { +#ifndef NDEBUG + Val = V; +#endif +} + +bool MipsCallEntry::isConstant(const MachineFrameInfo *) const { + return false; +} + +bool MipsCallEntry::isAliased(const MachineFrameInfo *) const { + return false; +} + +bool MipsCallEntry::mayAlias(const MachineFrameInfo *) const { + return false; +} + +void MipsCallEntry::printCustom(raw_ostream &O) const { + O << "MipsCallEntry: "; +#ifndef NDEBUG + if (Val) + O << Val->getName(); + else + O << Name; +#endif +} + +MipsFunctionInfo::~MipsFunctionInfo() { + for (StringMap<const MipsCallEntry *>::iterator + I = ExternalCallEntries.begin(), E = ExternalCallEntries.end(); I != E; + ++I) + delete I->getValue(); + + for (ValueMap<const GlobalValue *, const MipsCallEntry *>::iterator + I = GlobalCallEntries.begin(), E = GlobalCallEntries.end(); I != E; ++I) + delete I->second; +} + +bool MipsFunctionInfo::globalBaseRegSet() const { + return GlobalBaseReg; +} + +unsigned MipsFunctionInfo::getGlobalBaseReg() { + // Return if it has already been initialized. + if (GlobalBaseReg) + return GlobalBaseReg; + + const MipsSubtarget &ST = MF.getTarget().getSubtarget<MipsSubtarget>(); + + const TargetRegisterClass *RC; + if (ST.inMips16Mode()) + RC=(const TargetRegisterClass*)&Mips::CPU16RegsRegClass; + else + RC = ST.isABI_N64() ? + (const TargetRegisterClass*)&Mips::GPR64RegClass : + (const TargetRegisterClass*)&Mips::GPR32RegClass; + return GlobalBaseReg = MF.getRegInfo().createVirtualRegister(RC); +} + +bool MipsFunctionInfo::mips16SPAliasRegSet() const { + return Mips16SPAliasReg; +} +unsigned MipsFunctionInfo::getMips16SPAliasReg() { + // Return if it has already been initialized. + if (Mips16SPAliasReg) + return Mips16SPAliasReg; + + const TargetRegisterClass *RC; + RC=(const TargetRegisterClass*)&Mips::CPU16RegsRegClass; + return Mips16SPAliasReg = MF.getRegInfo().createVirtualRegister(RC); +} + +void MipsFunctionInfo::createEhDataRegsFI() { + for (int I = 0; I < 4; ++I) { + const MipsSubtarget &ST = MF.getTarget().getSubtarget<MipsSubtarget>(); + const TargetRegisterClass *RC = ST.isABI_N64() ? + &Mips::GPR64RegClass : &Mips::GPR32RegClass; + + EhDataRegFI[I] = MF.getFrameInfo()->CreateStackObject(RC->getSize(), + RC->getAlignment(), false); + } +} + +bool MipsFunctionInfo::isEhDataRegFI(int FI) const { + return CallsEhReturn && (FI == EhDataRegFI[0] || FI == EhDataRegFI[1] + || FI == EhDataRegFI[2] || FI == EhDataRegFI[3]); +} + +MachinePointerInfo MipsFunctionInfo::callPtrInfo(const StringRef &Name) { + const MipsCallEntry *&E = ExternalCallEntries[Name]; + + if (!E) + E = new MipsCallEntry(Name); + + return MachinePointerInfo(E); +} + +MachinePointerInfo MipsFunctionInfo::callPtrInfo(const GlobalValue *Val) { + const MipsCallEntry *&E = GlobalCallEntries[Val]; + + if (!E) + E = new MipsCallEntry(Val); + + return MachinePointerInfo(E); +} + +void MipsFunctionInfo::anchor() { } diff --git a/contrib/llvm/lib/Target/Mips/MipsMachineFunction.h b/contrib/llvm/lib/Target/Mips/MipsMachineFunction.h new file mode 100644 index 000000000000..43bf6827eefb --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsMachineFunction.h @@ -0,0 +1,136 @@ +//===-- MipsMachineFunctionInfo.h - Private data used for Mips ----*- 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 Mips specific subclass of MachineFunctionInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPS_MACHINE_FUNCTION_INFO_H +#define MIPS_MACHINE_FUNCTION_INFO_H + +#include "MipsSubtarget.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/ValueMap.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetMachine.h" +#include <utility> + +namespace llvm { + +/// \brief A class derived from PseudoSourceValue that represents a GOT entry +/// resolved by lazy-binding. +class MipsCallEntry : public PseudoSourceValue { +public: + explicit MipsCallEntry(const StringRef &N); + explicit MipsCallEntry(const GlobalValue *V); + virtual bool isConstant(const MachineFrameInfo *) const; + virtual bool isAliased(const MachineFrameInfo *) const; + virtual bool mayAlias(const MachineFrameInfo *) const; + +private: + virtual void printCustom(raw_ostream &O) const; +#ifndef NDEBUG + std::string Name; + const GlobalValue *Val; +#endif +}; + +/// MipsFunctionInfo - This class is derived from MachineFunction private +/// Mips target-specific information for each MachineFunction. +class MipsFunctionInfo : public MachineFunctionInfo { +public: + MipsFunctionInfo(MachineFunction& MF) + : MF(MF), SRetReturnReg(0), GlobalBaseReg(0), Mips16SPAliasReg(0), + VarArgsFrameIndex(0), CallsEhReturn(false) + {} + + ~MipsFunctionInfo(); + + unsigned getSRetReturnReg() const { return SRetReturnReg; } + void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; } + + bool globalBaseRegSet() const; + unsigned getGlobalBaseReg(); + + bool mips16SPAliasRegSet() const; + unsigned getMips16SPAliasReg(); + + int getVarArgsFrameIndex() const { return VarArgsFrameIndex; } + void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; } + + bool hasByvalArg() const { return HasByvalArg; } + void setFormalArgInfo(unsigned Size, bool HasByval) { + IncomingArgSize = Size; + HasByvalArg = HasByval; + } + + unsigned getIncomingArgSize() const { return IncomingArgSize; } + + bool callsEhReturn() const { return CallsEhReturn; } + void setCallsEhReturn() { CallsEhReturn = true; } + + void createEhDataRegsFI(); + int getEhDataRegFI(unsigned Reg) const { return EhDataRegFI[Reg]; } + bool isEhDataRegFI(int FI) const; + + /// \brief Create a MachinePointerInfo that has a MipsCallEntr object + /// representing a GOT entry for an external function. + MachinePointerInfo callPtrInfo(const StringRef &Name); + + /// \brief Create a MachinePointerInfo that has a MipsCallEntr object + /// representing a GOT entry for a global function. + MachinePointerInfo callPtrInfo(const GlobalValue *Val); + +private: + virtual void anchor(); + + MachineFunction& MF; + /// 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; + + /// Mips16SPAliasReg - keeps track of the virtual register initialized for + /// use as an alias for SP for use in load/store of halfword/byte from/to + /// the stack + unsigned Mips16SPAliasReg; + + /// VarArgsFrameIndex - FrameIndex for start of varargs area. + int VarArgsFrameIndex; + + /// True if function has a byval argument. + bool HasByvalArg; + + /// Size of incoming argument area. + unsigned IncomingArgSize; + + /// CallsEhReturn - Whether the function calls llvm.eh.return. + bool CallsEhReturn; + + /// Frame objects for spilling eh data registers. + int EhDataRegFI[4]; + + /// MipsCallEntry maps. + StringMap<const MipsCallEntry *> ExternalCallEntries; + ValueMap<const GlobalValue *, const MipsCallEntry *> GlobalCallEntries; +}; + +} // end of namespace llvm + +#endif // MIPS_MACHINE_FUNCTION_INFO_H diff --git a/contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp new file mode 100644 index 000000000000..c6abf17df353 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// Instruction Selector Subtarget Control +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// This file defines a pass used to change the subtarget for the +// Mips Instruction selector. +// +//===----------------------------------------------------------------------===// + +#include "MipsISelDAGToDAG.h" +#include "MipsModuleISelDAGToDAG.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +bool MipsModuleDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { + DEBUG(errs() << "In MipsModuleDAGToDAGISel::runMachineFunction\n"); + const_cast<MipsSubtarget&>(Subtarget).resetSubtarget(&MF); + return false; +} + +char MipsModuleDAGToDAGISel::ID = 0; + +} + + +llvm::FunctionPass *llvm::createMipsModuleISelDag(MipsTargetMachine &TM) { + return new MipsModuleDAGToDAGISel(TM); +} + + diff --git a/contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.h b/contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.h new file mode 100644 index 000000000000..fda35ae288bb --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsModuleISelDAGToDAG.h @@ -0,0 +1,66 @@ +//===---- MipsModuleISelDAGToDAG.h - Change Subtarget --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a pass used to change the subtarget for the +// Mips Instruction selector. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSMODULEISELDAGTODAG_H +#define MIPSMODULEISELDAGTODAG_H + +#include "Mips.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" +#include "llvm/CodeGen/SelectionDAGISel.h" + + +//===----------------------------------------------------------------------===// +// Instruction Selector Implementation +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MipsModuleDAGToDAGISel - MIPS specific code to select MIPS machine +// instructions for SelectionDAG operations. +//===----------------------------------------------------------------------===// +namespace llvm { + +class MipsModuleDAGToDAGISel : public MachineFunctionPass { +public: + + static char ID; + + explicit MipsModuleDAGToDAGISel(MipsTargetMachine &TM_) + : MachineFunctionPass(ID), + TM(TM_), Subtarget(TM.getSubtarget<MipsSubtarget>()) {} + + // Pass Name + virtual const char *getPassName() const { + return "MIPS DAG->DAG Pattern Instruction Selection"; + } + + virtual bool runOnMachineFunction(MachineFunction &MF); + + virtual SDNode *Select(SDNode *N) { + llvm_unreachable("unexpected"); + } + +protected: + /// Keep a pointer to the MipsSubtarget around so that we can make the right + /// decision when generating code for different targets. + const TargetMachine &TM; + const MipsSubtarget &Subtarget; +}; + +/// createMipsISelDag - This pass converts a legalized DAG into a +/// MIPS-specific DAG, ready for instruction scheduling. +FunctionPass *createMipsModuleISelDag(MipsTargetMachine &TM); +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsOs16.cpp b/contrib/llvm/lib/Target/Mips/MipsOs16.cpp new file mode 100644 index 000000000000..fe60841212e0 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsOs16.cpp @@ -0,0 +1,146 @@ +//===---- MipsOs16.cpp for Mips Option -Os16 --------===// +// +// 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 optimization phase for the MIPS target. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-os16" +#include "MipsOs16.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + + +static cl::opt<std::string> Mips32FunctionMask( + "mips32-function-mask", + cl::init(""), + cl::desc("Force function to be mips32"), + cl::Hidden); + +namespace { + + // Figure out if we need float point based on the function signature. + // We need to move variables in and/or out of floating point + // registers because of the ABI + // + bool needsFPFromSig(Function &F) { + Type* RetType = F.getReturnType(); + switch (RetType->getTypeID()) { + case Type::FloatTyID: + case Type::DoubleTyID: + return true; + default: + ; + } + if (F.arg_size() >=1) { + Argument &Arg = F.getArgumentList().front(); + switch (Arg.getType()->getTypeID()) { + case Type::FloatTyID: + case Type::DoubleTyID: + return true; + default: + ; + } + } + return false; + } + + // Figure out if the function will need floating point operations + // + bool needsFP(Function &F) { + if (needsFPFromSig(F)) + return true; + for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB) + for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); + I != E; ++I) { + const Instruction &Inst = *I; + switch (Inst.getOpcode()) { + case Instruction::FAdd: + case Instruction::FSub: + case Instruction::FMul: + case Instruction::FDiv: + case Instruction::FRem: + case Instruction::FPToUI: + case Instruction::FPToSI: + case Instruction::UIToFP: + case Instruction::SIToFP: + case Instruction::FPTrunc: + case Instruction::FPExt: + case Instruction::FCmp: + return true; + default: + ; + } + if (const CallInst *CI = dyn_cast<CallInst>(I)) { + DEBUG(dbgs() << "Working on call" << "\n"); + Function &F_ = *CI->getCalledFunction(); + if (needsFPFromSig(F_)) + return true; + } + } + return false; + } +} +namespace llvm { + + +bool MipsOs16::runOnModule(Module &M) { + bool usingMask = Mips32FunctionMask.length() > 0; + bool doneUsingMask = false; // this will make it stop repeating + DEBUG(dbgs() << "Run on Module MipsOs16 \n" << Mips32FunctionMask << "\n"); + if (usingMask) + DEBUG(dbgs() << "using mask \n" << Mips32FunctionMask << "\n"); + unsigned int functionIndex = 0; + bool modified = false; + for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { + if (F->isDeclaration()) continue; + DEBUG(dbgs() << "Working on " << F->getName() << "\n"); + if (usingMask) { + if (!doneUsingMask) { + if (functionIndex == Mips32FunctionMask.length()) + functionIndex = 0; + switch (Mips32FunctionMask[functionIndex]) { + case '1': + DEBUG(dbgs() << "mask forced mips32: " << F->getName() << "\n"); + F->addFnAttr("nomips16"); + break; + case '.': + doneUsingMask = true; + break; + default: + break; + } + functionIndex++; + } + } + else { + if (needsFP(*F)) { + DEBUG(dbgs() << "os16 forced mips32: " << F->getName() << "\n"); + F->addFnAttr("nomips16"); + } + else { + DEBUG(dbgs() << "os16 forced mips16: " << F->getName() << "\n"); + F->addFnAttr("mips16"); + } + } + } + return modified; +} + +char MipsOs16::ID = 0; + +} + +ModulePass *llvm::createMipsOs16(MipsTargetMachine &TM) { + return new MipsOs16; +} + + diff --git a/contrib/llvm/lib/Target/Mips/MipsOs16.h b/contrib/llvm/lib/Target/Mips/MipsOs16.h new file mode 100644 index 000000000000..21beef8549cd --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsOs16.h @@ -0,0 +1,49 @@ +//===---- MipsOs16.h for Mips Option -Os16 --------===// +// +// 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 optimization phase for the MIPS target. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MipsMCTargetDesc.h" +#include "MipsTargetMachine.h" +#include "llvm/Pass.h" +#include "llvm/Target/TargetMachine.h" + + + +#ifndef MIPSOS16_H +#define MIPSOS16_H + +using namespace llvm; + +namespace llvm { + +class MipsOs16 : public ModulePass { + +public: + static char ID; + + MipsOs16() : ModulePass(ID) { + + } + + virtual const char *getPassName() const { + return "MIPS Os16 Optimization"; + } + + virtual bool runOnModule(Module &M); + +}; + +ModulePass *createMipsOs16(MipsTargetMachine &TM); + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp new file mode 100644 index 000000000000..3105b0208451 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.cpp @@ -0,0 +1,242 @@ +//===-- MipsRegisterInfo.cpp - MIPS 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 MIPS implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-reg-info" + +#include "MipsRegisterInfo.h" +#include "Mips.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsInstrInfo.h" +#include "MipsMachineFunction.h" +#include "MipsSubtarget.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/DebugInfo.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" + +#define GET_REGINFO_TARGET_DESC +#include "MipsGenRegisterInfo.inc" + +using namespace llvm; + +MipsRegisterInfo::MipsRegisterInfo(const MipsSubtarget &ST) + : MipsGenRegisterInfo(Mips::RA), Subtarget(ST) {} + +unsigned MipsRegisterInfo::getPICCallReg() { return Mips::T9; } + +const TargetRegisterClass * +MipsRegisterInfo::getPointerRegClass(const MachineFunction &MF, + unsigned Kind) const { + return Subtarget.isABI_N64() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; +} + +unsigned +MipsRegisterInfo::getRegPressureLimit(const TargetRegisterClass *RC, + MachineFunction &MF) const { + switch (RC->getID()) { + default: + return 0; + case Mips::GPR32RegClassID: + case Mips::GPR64RegClassID: + case Mips::DSPRRegClassID: { + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + return 28 - TFI->hasFP(MF); + } + case Mips::FGR32RegClassID: + return 32; + case Mips::AFGR64RegClassID: + return 16; + case Mips::FGR64RegClassID: + return 32; + } +} + +//===----------------------------------------------------------------------===// +// Callee Saved Registers methods +//===----------------------------------------------------------------------===// + +/// Mips Callee Saved Registers +const uint16_t* MipsRegisterInfo:: +getCalleeSavedRegs(const MachineFunction *MF) const { + if (Subtarget.isSingleFloat()) + return CSR_SingleFloatOnly_SaveList; + + if (Subtarget.isABI_N64()) + return CSR_N64_SaveList; + + if (Subtarget.isABI_N32()) + return CSR_N32_SaveList; + + if (Subtarget.isFP64bit()) + return CSR_O32_FP64_SaveList; + + return CSR_O32_SaveList; +} + +const uint32_t* +MipsRegisterInfo::getCallPreservedMask(CallingConv::ID) const { + if (Subtarget.isSingleFloat()) + return CSR_SingleFloatOnly_RegMask; + + if (Subtarget.isABI_N64()) + return CSR_N64_RegMask; + + if (Subtarget.isABI_N32()) + return CSR_N32_RegMask; + + if (Subtarget.isFP64bit()) + return CSR_O32_FP64_RegMask; + + return CSR_O32_RegMask; +} + +const uint32_t *MipsRegisterInfo::getMips16RetHelperMask() { + return CSR_Mips16RetHelper_RegMask; +} + +BitVector MipsRegisterInfo:: +getReservedRegs(const MachineFunction &MF) const { + static const uint16_t ReservedGPR32[] = { + Mips::ZERO, Mips::K0, Mips::K1, Mips::SP + }; + + static const uint16_t ReservedGPR64[] = { + Mips::ZERO_64, Mips::K0_64, Mips::K1_64, Mips::SP_64 + }; + + BitVector Reserved(getNumRegs()); + typedef TargetRegisterClass::const_iterator RegIter; + + for (unsigned I = 0; I < array_lengthof(ReservedGPR32); ++I) + Reserved.set(ReservedGPR32[I]); + + for (unsigned I = 0; I < array_lengthof(ReservedGPR64); ++I) + Reserved.set(ReservedGPR64[I]); + + if (Subtarget.isFP64bit()) { + // Reserve all registers in AFGR64. + for (RegIter Reg = Mips::AFGR64RegClass.begin(), + EReg = Mips::AFGR64RegClass.end(); Reg != EReg; ++Reg) + Reserved.set(*Reg); + } else { + // Reserve all registers in FGR64. + for (RegIter Reg = Mips::FGR64RegClass.begin(), + EReg = Mips::FGR64RegClass.end(); Reg != EReg; ++Reg) + Reserved.set(*Reg); + } + // Reserve FP if this function should have a dedicated frame pointer register. + if (MF.getTarget().getFrameLowering()->hasFP(MF)) { + if (Subtarget.inMips16Mode()) + Reserved.set(Mips::S0); + else { + Reserved.set(Mips::FP); + Reserved.set(Mips::FP_64); + } + } + + // Reserve hardware registers. + Reserved.set(Mips::HWR29); + + // Reserve DSP control register. + Reserved.set(Mips::DSPPos); + Reserved.set(Mips::DSPSCount); + Reserved.set(Mips::DSPCarry); + Reserved.set(Mips::DSPEFI); + Reserved.set(Mips::DSPOutFlag); + + // Reserve MSA control registers. + Reserved.set(Mips::MSAIR); + Reserved.set(Mips::MSACSR); + Reserved.set(Mips::MSAAccess); + Reserved.set(Mips::MSASave); + Reserved.set(Mips::MSAModify); + Reserved.set(Mips::MSARequest); + Reserved.set(Mips::MSAMap); + Reserved.set(Mips::MSAUnmap); + + // Reserve RA if in mips16 mode. + if (Subtarget.inMips16Mode()) { + Reserved.set(Mips::RA); + Reserved.set(Mips::RA_64); + Reserved.set(Mips::T0); + Reserved.set(Mips::T1); + } + + // Reserve GP if small section is used. + if (Subtarget.useSmallSection()) { + Reserved.set(Mips::GP); + Reserved.set(Mips::GP_64); + } + + return Reserved; +} + +bool +MipsRegisterInfo::requiresRegisterScavenging(const MachineFunction &MF) const { + return true; +} + +bool +MipsRegisterInfo::trackLivenessAfterRegAlloc(const MachineFunction &MF) const { + return true; +} + +// FrameIndex represent objects inside a abstract stack. +// We must replace FrameIndex with an stack/frame pointer +// direct reference. +void MipsRegisterInfo:: +eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, + unsigned FIOperandNum, RegScavenger *RS) const { + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + + DEBUG(errs() << "\nFunction : " << MF.getName() << "\n"; + errs() << "<--------->\n" << MI); + + int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); + uint64_t stackSize = MF.getFrameInfo()->getStackSize(); + int64_t spOffset = MF.getFrameInfo()->getObjectOffset(FrameIndex); + + DEBUG(errs() << "FrameIndex : " << FrameIndex << "\n" + << "spOffset : " << spOffset << "\n" + << "stackSize : " << stackSize << "\n"); + + eliminateFI(MI, FIOperandNum, FrameIndex, stackSize, spOffset); +} + +unsigned MipsRegisterInfo:: +getFrameRegister(const MachineFunction &MF) const { + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + bool IsN64 = Subtarget.isABI_N64(); + + if (Subtarget.inMips16Mode()) + return TFI->hasFP(MF) ? Mips::S0 : Mips::SP; + else + return TFI->hasFP(MF) ? (IsN64 ? Mips::FP_64 : Mips::FP) : + (IsN64 ? Mips::SP_64 : Mips::SP); + +} + diff --git a/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.h b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.h new file mode 100644 index 000000000000..0450c6fbe47e --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.h @@ -0,0 +1,82 @@ +//===-- MipsRegisterInfo.h - Mips 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 Mips implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSREGISTERINFO_H +#define MIPSREGISTERINFO_H + +#include "Mips.h" +#include "llvm/Target/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "MipsGenRegisterInfo.inc" + +namespace llvm { +class MipsSubtarget; +class Type; + +class MipsRegisterInfo : public MipsGenRegisterInfo { +protected: + const MipsSubtarget &Subtarget; + +public: + MipsRegisterInfo(const MipsSubtarget &Subtarget); + + /// getRegisterNumbering - Given the enum value for some register, e.g. + /// Mips::RA, return the number that it corresponds to (e.g. 31). + static unsigned getRegisterNumbering(unsigned RegEnum); + + /// Get PIC indirect call register + static unsigned getPICCallReg(); + + /// Adjust the Mips stack frame. + void adjustMipsStackFrame(MachineFunction &MF) const; + + /// Code Generation virtual methods... + const TargetRegisterClass *getPointerRegClass(const MachineFunction &MF, + unsigned Kind) const; + + unsigned getRegPressureLimit(const TargetRegisterClass *RC, + MachineFunction &MF) const; + const uint16_t *getCalleeSavedRegs(const MachineFunction *MF = 0) const; + const uint32_t *getCallPreservedMask(CallingConv::ID) const; + static const uint32_t *getMips16RetHelperMask(); + + BitVector getReservedRegs(const MachineFunction &MF) const; + + virtual bool requiresRegisterScavenging(const MachineFunction &MF) const; + + virtual bool trackLivenessAfterRegAlloc(const MachineFunction &MF) const; + + /// Stack Frame Processing Methods + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS = NULL) const; + + void processFunctionBeforeFrameFinalized(MachineFunction &MF, + RegScavenger *RS = NULL) const; + + /// Debug information queries. + unsigned getFrameRegister(const MachineFunction &MF) const; + + /// \brief Return GPR register class. + virtual const TargetRegisterClass *intRegClass(unsigned Size) const = 0; + +private: + virtual void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo, + int FrameIndex, uint64_t StackSize, + int64_t SPOffset) const = 0; +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td new file mode 100644 index 000000000000..3173d0927af1 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsRegisterInfo.td @@ -0,0 +1,549 @@ +//===-- MipsRegisterInfo.td - Mips 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 MIPS register file +//===----------------------------------------------------------------------===// +let Namespace = "Mips" in { +def sub_32 : SubRegIndex<32>; +def sub_64 : SubRegIndex<64>; +def sub_lo : SubRegIndex<32>; +def sub_hi : SubRegIndex<32, 32>; +def sub_dsp16_19 : SubRegIndex<4, 16>; +def sub_dsp20 : SubRegIndex<1, 20>; +def sub_dsp21 : SubRegIndex<1, 21>; +def sub_dsp22 : SubRegIndex<1, 22>; +def sub_dsp23 : SubRegIndex<1, 23>; +} + +class Unallocatable { + bit isAllocatable = 0; +} + +// We have banks of 32 registers each. +class MipsReg<bits<16> Enc, string n> : Register<n> { + let HWEncoding = Enc; + let Namespace = "Mips"; +} + +class MipsRegWithSubRegs<bits<16> Enc, string n, list<Register> subregs> + : RegisterWithSubRegs<n, subregs> { + let HWEncoding = Enc; + let Namespace = "Mips"; +} + +// Mips CPU Registers +class MipsGPRReg<bits<16> Enc, string n> : MipsReg<Enc, n>; + +// Mips 64-bit CPU Registers +class Mips64GPRReg<bits<16> Enc, string n, list<Register> subregs> + : MipsRegWithSubRegs<Enc, n, subregs> { + let SubRegIndices = [sub_32]; +} + +// Mips 32-bit FPU Registers +class FPR<bits<16> Enc, string n> : MipsReg<Enc, n>; + +// Mips 64-bit (aliased) FPU Registers +class AFPR<bits<16> Enc, string n, list<Register> subregs> + : MipsRegWithSubRegs<Enc, n, subregs> { + let SubRegIndices = [sub_lo, sub_hi]; + let CoveredBySubRegs = 1; +} + +class AFPR64<bits<16> Enc, string n, list<Register> subregs> + : MipsRegWithSubRegs<Enc, n, subregs> { + let SubRegIndices = [sub_lo, sub_hi]; + let CoveredBySubRegs = 1; +} + +// Mips 128-bit (aliased) MSA Registers +class AFPR128<bits<16> Enc, string n, list<Register> subregs> + : MipsRegWithSubRegs<Enc, n, subregs> { + let SubRegIndices = [sub_64]; +} + +// Accumulator Registers +class ACCReg<bits<16> Enc, string n, list<Register> subregs> + : MipsRegWithSubRegs<Enc, n, subregs> { + let SubRegIndices = [sub_lo, sub_hi]; + let CoveredBySubRegs = 1; +} + +// Mips Hardware Registers +class HWR<bits<16> Enc, string n> : MipsReg<Enc, n>; + +//===----------------------------------------------------------------------===// +// Registers +//===----------------------------------------------------------------------===// + +let Namespace = "Mips" in { + // General Purpose Registers + def ZERO : MipsGPRReg< 0, "zero">, DwarfRegNum<[0]>; + def AT : MipsGPRReg< 1, "1">, DwarfRegNum<[1]>; + def V0 : MipsGPRReg< 2, "2">, DwarfRegNum<[2]>; + def V1 : MipsGPRReg< 3, "3">, DwarfRegNum<[3]>; + def A0 : MipsGPRReg< 4, "4">, DwarfRegNum<[4]>; + def A1 : MipsGPRReg< 5, "5">, DwarfRegNum<[5]>; + def A2 : MipsGPRReg< 6, "6">, DwarfRegNum<[6]>; + def A3 : MipsGPRReg< 7, "7">, DwarfRegNum<[7]>; + def T0 : MipsGPRReg< 8, "8">, DwarfRegNum<[8]>; + def T1 : MipsGPRReg< 9, "9">, DwarfRegNum<[9]>; + def T2 : MipsGPRReg< 10, "10">, DwarfRegNum<[10]>; + def T3 : MipsGPRReg< 11, "11">, DwarfRegNum<[11]>; + def T4 : MipsGPRReg< 12, "12">, DwarfRegNum<[12]>; + def T5 : MipsGPRReg< 13, "13">, DwarfRegNum<[13]>; + def T6 : MipsGPRReg< 14, "14">, DwarfRegNum<[14]>; + def T7 : MipsGPRReg< 15, "15">, DwarfRegNum<[15]>; + def S0 : MipsGPRReg< 16, "16">, DwarfRegNum<[16]>; + def S1 : MipsGPRReg< 17, "17">, DwarfRegNum<[17]>; + def S2 : MipsGPRReg< 18, "18">, DwarfRegNum<[18]>; + def S3 : MipsGPRReg< 19, "19">, DwarfRegNum<[19]>; + def S4 : MipsGPRReg< 20, "20">, DwarfRegNum<[20]>; + def S5 : MipsGPRReg< 21, "21">, DwarfRegNum<[21]>; + def S6 : MipsGPRReg< 22, "22">, DwarfRegNum<[22]>; + def S7 : MipsGPRReg< 23, "23">, DwarfRegNum<[23]>; + def T8 : MipsGPRReg< 24, "24">, DwarfRegNum<[24]>; + def T9 : MipsGPRReg< 25, "25">, DwarfRegNum<[25]>; + def K0 : MipsGPRReg< 26, "26">, DwarfRegNum<[26]>; + def K1 : MipsGPRReg< 27, "27">, DwarfRegNum<[27]>; + def GP : MipsGPRReg< 28, "gp">, DwarfRegNum<[28]>; + def SP : MipsGPRReg< 29, "sp">, DwarfRegNum<[29]>; + def FP : MipsGPRReg< 30, "fp">, DwarfRegNum<[30]>; + def RA : MipsGPRReg< 31, "ra">, DwarfRegNum<[31]>; + + // General Purpose 64-bit Registers + def ZERO_64 : Mips64GPRReg< 0, "zero", [ZERO]>, DwarfRegNum<[0]>; + def AT_64 : Mips64GPRReg< 1, "1", [AT]>, DwarfRegNum<[1]>; + def V0_64 : Mips64GPRReg< 2, "2", [V0]>, DwarfRegNum<[2]>; + def V1_64 : Mips64GPRReg< 3, "3", [V1]>, DwarfRegNum<[3]>; + def A0_64 : Mips64GPRReg< 4, "4", [A0]>, DwarfRegNum<[4]>; + def A1_64 : Mips64GPRReg< 5, "5", [A1]>, DwarfRegNum<[5]>; + def A2_64 : Mips64GPRReg< 6, "6", [A2]>, DwarfRegNum<[6]>; + def A3_64 : Mips64GPRReg< 7, "7", [A3]>, DwarfRegNum<[7]>; + def T0_64 : Mips64GPRReg< 8, "8", [T0]>, DwarfRegNum<[8]>; + def T1_64 : Mips64GPRReg< 9, "9", [T1]>, DwarfRegNum<[9]>; + def T2_64 : Mips64GPRReg< 10, "10", [T2]>, DwarfRegNum<[10]>; + def T3_64 : Mips64GPRReg< 11, "11", [T3]>, DwarfRegNum<[11]>; + def T4_64 : Mips64GPRReg< 12, "12", [T4]>, DwarfRegNum<[12]>; + def T5_64 : Mips64GPRReg< 13, "13", [T5]>, DwarfRegNum<[13]>; + def T6_64 : Mips64GPRReg< 14, "14", [T6]>, DwarfRegNum<[14]>; + def T7_64 : Mips64GPRReg< 15, "15", [T7]>, DwarfRegNum<[15]>; + def S0_64 : Mips64GPRReg< 16, "16", [S0]>, DwarfRegNum<[16]>; + def S1_64 : Mips64GPRReg< 17, "17", [S1]>, DwarfRegNum<[17]>; + def S2_64 : Mips64GPRReg< 18, "18", [S2]>, DwarfRegNum<[18]>; + def S3_64 : Mips64GPRReg< 19, "19", [S3]>, DwarfRegNum<[19]>; + def S4_64 : Mips64GPRReg< 20, "20", [S4]>, DwarfRegNum<[20]>; + def S5_64 : Mips64GPRReg< 21, "21", [S5]>, DwarfRegNum<[21]>; + def S6_64 : Mips64GPRReg< 22, "22", [S6]>, DwarfRegNum<[22]>; + def S7_64 : Mips64GPRReg< 23, "23", [S7]>, DwarfRegNum<[23]>; + def T8_64 : Mips64GPRReg< 24, "24", [T8]>, DwarfRegNum<[24]>; + def T9_64 : Mips64GPRReg< 25, "25", [T9]>, DwarfRegNum<[25]>; + def K0_64 : Mips64GPRReg< 26, "26", [K0]>, DwarfRegNum<[26]>; + def K1_64 : Mips64GPRReg< 27, "27", [K1]>, DwarfRegNum<[27]>; + def GP_64 : Mips64GPRReg< 28, "gp", [GP]>, DwarfRegNum<[28]>; + def SP_64 : Mips64GPRReg< 29, "sp", [SP]>, DwarfRegNum<[29]>; + def FP_64 : Mips64GPRReg< 30, "fp", [FP]>, DwarfRegNum<[30]>; + def RA_64 : Mips64GPRReg< 31, "ra", [RA]>, DwarfRegNum<[31]>; + + /// Mips Single point precision FPU Registers + foreach I = 0-31 in + def F#I : FPR<I, "f"#I>, DwarfRegNum<[!add(I, 32)]>; + + // Higher half of 64-bit FP registers. + foreach I = 0-31 in + def F_HI#I : FPR<I, "f"#I>, DwarfRegNum<[!add(I, 32)]>; + + /// Mips Double point precision FPU Registers (aliased + /// with the single precision to hold 64 bit values) + foreach I = 0-15 in + def D#I : AFPR<!shl(I, 1), "f"#!shl(I, 1), + [!cast<FPR>("F"#!shl(I, 1)), + !cast<FPR>("F"#!add(!shl(I, 1), 1))]>; + + /// Mips Double point precision FPU Registers in MFP64 mode. + foreach I = 0-31 in + def D#I#_64 : AFPR64<I, "f"#I, [!cast<FPR>("F"#I), !cast<FPR>("F_HI"#I)]>, + DwarfRegNum<[!add(I, 32)]>; + + /// Mips MSA registers + /// MSA and FPU cannot both be present unless the FPU has 64-bit registers + foreach I = 0-31 in + def W#I : AFPR128<I, "w"#I, [!cast<AFPR64>("D"#I#"_64")]>, + DwarfRegNum<[!add(I, 32)]>; + + // Hi/Lo registers + def HI0 : MipsReg<0, "ac0">, DwarfRegNum<[64]>; + def HI1 : MipsReg<1, "ac1">, DwarfRegNum<[176]>; + def HI2 : MipsReg<2, "ac2">, DwarfRegNum<[178]>; + def HI3 : MipsReg<3, "ac3">, DwarfRegNum<[180]>; + def LO0 : MipsReg<0, "ac0">, DwarfRegNum<[65]>; + def LO1 : MipsReg<1, "ac1">, DwarfRegNum<[177]>; + def LO2 : MipsReg<2, "ac2">, DwarfRegNum<[179]>; + def LO3 : MipsReg<3, "ac3">, DwarfRegNum<[181]>; + + let SubRegIndices = [sub_32] in { + def HI0_64 : RegisterWithSubRegs<"hi", [HI0]>; + def LO0_64 : RegisterWithSubRegs<"lo", [LO0]>; + } + + // FP control registers. + foreach I = 0-31 in + def FCR#I : MipsReg<#I, ""#I>; + + // FP condition code registers. + foreach I = 0-7 in + def FCC#I : MipsReg<#I, "fcc"#I>; + + // COP2 registers. + foreach I = 0-31 in + def COP2#I : MipsReg<#I, ""#I>; + + // PC register + def PC : Register<"pc">; + + // Hardware register $29 + def HWR29 : MipsReg<29, "29">; + + // Accum registers + foreach I = 0-3 in + def AC#I : ACCReg<#I, "ac"#I, + [!cast<Register>("LO"#I), !cast<Register>("HI"#I)]>; + + def AC0_64 : ACCReg<0, "ac0", [LO0_64, HI0_64]>; + + // DSP-ASE control register fields. + def DSPPos : Register<"">; + def DSPSCount : Register<"">; + def DSPCarry : Register<"">; + def DSPEFI : Register<"">; + def DSPOutFlag16_19 : Register<"">; + def DSPOutFlag20 : Register<"">; + def DSPOutFlag21 : Register<"">; + def DSPOutFlag22 : Register<"">; + def DSPOutFlag23 : Register<"">; + def DSPCCond : Register<"">; + + let SubRegIndices = [sub_dsp16_19, sub_dsp20, sub_dsp21, sub_dsp22, + sub_dsp23] in + def DSPOutFlag : RegisterWithSubRegs<"", [DSPOutFlag16_19, DSPOutFlag20, + DSPOutFlag21, DSPOutFlag22, + DSPOutFlag23]>; + + // MSA-ASE control registers. + def MSAIR : MipsReg<0, "0">; + def MSACSR : MipsReg<1, "1">; + def MSAAccess : MipsReg<2, "2">; + def MSASave : MipsReg<3, "3">; + def MSAModify : MipsReg<4, "4">; + def MSARequest : MipsReg<5, "5">; + def MSAMap : MipsReg<6, "6">; + def MSAUnmap : MipsReg<7, "7">; +} + +//===----------------------------------------------------------------------===// +// Register Classes +//===----------------------------------------------------------------------===// + +class GPR32Class<list<ValueType> regTypes> : + RegisterClass<"Mips", regTypes, 32, (add + // Reserved + ZERO, AT, + // Return Values and Arguments + V0, V1, A0, A1, A2, A3, + // Not preserved across procedure calls + T0, T1, T2, T3, T4, T5, T6, T7, + // Callee save + S0, S1, S2, S3, S4, S5, S6, S7, + // Not preserved across procedure calls + T8, T9, + // Reserved + K0, K1, GP, SP, FP, RA)>; + +def GPR32 : GPR32Class<[i32]>; +def DSPR : GPR32Class<[v4i8, v2i16]>; + +def GPR64 : RegisterClass<"Mips", [i64], 64, (add +// Reserved + ZERO_64, AT_64, + // Return Values and Arguments + V0_64, V1_64, A0_64, A1_64, A2_64, A3_64, + // Not preserved across procedure calls + T0_64, T1_64, T2_64, T3_64, T4_64, T5_64, T6_64, T7_64, + // Callee save + S0_64, S1_64, S2_64, S3_64, S4_64, S5_64, S6_64, S7_64, + // Not preserved across procedure calls + T8_64, T9_64, + // Reserved + K0_64, K1_64, GP_64, SP_64, FP_64, RA_64)>; + +def CPU16Regs : RegisterClass<"Mips", [i32], 32, (add + // Return Values and Arguments + V0, V1, A0, A1, A2, A3, + // Callee save + S0, S1)>; + +def CPU16RegsPlusSP : RegisterClass<"Mips", [i32], 32, (add + // Return Values and Arguments + V0, V1, A0, A1, A2, A3, + // Callee save + S0, S1, + SP)>; + +def CPURAReg : RegisterClass<"Mips", [i32], 32, (add RA)>, Unallocatable; + +def CPUSPReg : RegisterClass<"Mips", [i32], 32, (add SP)>, Unallocatable; + +// 64bit fp: +// * FGR64 - 32 64-bit registers +// * AFGR64 - 16 32-bit even registers (32-bit FP Mode) +// +// 32bit fp: +// * FGR32 - 16 32-bit even registers +// * FGR32 - 32 32-bit registers (single float only mode) +def FGR32 : RegisterClass<"Mips", [f32], 32, (sequence "F%u", 0, 31)>; + +def FGRH32 : RegisterClass<"Mips", [f32], 32, (sequence "F_HI%u", 0, 31)>, + Unallocatable; + +def AFGR64 : RegisterClass<"Mips", [f64], 64, (add + // Return Values and Arguments + D0, D1, + // Not preserved across procedure calls + D2, D3, D4, D5, + // Return Values and Arguments + D6, D7, + // Not preserved across procedure calls + D8, D9, + // Callee save + D10, D11, D12, D13, D14, D15)>; + +def FGR64 : RegisterClass<"Mips", [f64], 64, (sequence "D%u_64", 0, 31)>; + +// FP control registers. +def CCR : RegisterClass<"Mips", [i32], 32, (sequence "FCR%u", 0, 31)>, + Unallocatable; + +// FP condition code registers. +def FCC : RegisterClass<"Mips", [i32], 32, (sequence "FCC%u", 0, 7)>, + Unallocatable; + +def MSA128B: RegisterClass<"Mips", [v16i8], 128, + (sequence "W%u", 0, 31)>; +def MSA128H: RegisterClass<"Mips", [v8i16, v8f16], 128, + (sequence "W%u", 0, 31)>; +def MSA128W: RegisterClass<"Mips", [v4i32, v4f32], 128, + (sequence "W%u", 0, 31)>; +def MSA128D: RegisterClass<"Mips", [v2i64, v2f64], 128, + (sequence "W%u", 0, 31)>; + +def MSACtrl: RegisterClass<"Mips", [i32], 32, (add + MSAIR, MSACSR, MSAAccess, MSASave, MSAModify, MSARequest, MSAMap, MSAUnmap)>; + +// Hi/Lo Registers +def LO32 : RegisterClass<"Mips", [i32], 32, (add LO0)>; +def HI32 : RegisterClass<"Mips", [i32], 32, (add HI0)>; +def LO32DSP : RegisterClass<"Mips", [i32], 32, (sequence "LO%u", 0, 3)>; +def HI32DSP : RegisterClass<"Mips", [i32], 32, (sequence "HI%u", 0, 3)>; +def LO64 : RegisterClass<"Mips", [i64], 64, (add LO0_64)>; +def HI64 : RegisterClass<"Mips", [i64], 64, (add HI0_64)>; + +// Hardware registers +def HWRegs : RegisterClass<"Mips", [i32], 32, (add HWR29)>, Unallocatable; + +// Accumulator Registers +def ACC64 : RegisterClass<"Mips", [untyped], 64, (add AC0)> { + let Size = 64; +} + +def ACC128 : RegisterClass<"Mips", [untyped], 128, (add AC0_64)> { + let Size = 128; +} + +def ACC64DSP : RegisterClass<"Mips", [untyped], 64, (sequence "AC%u", 0, 3)> { + let Size = 64; +} + +def DSPCC : RegisterClass<"Mips", [v4i8, v2i16], 32, (add DSPCCond)>; + +// Coprocessor 2 registers. +def COP2 : RegisterClass<"Mips", [i32], 32, (sequence "COP2%u", 0, 31)>, + Unallocatable; + +// Register Operands. + +class MipsAsmRegOperand : AsmOperandClass { + let RenderMethod = "addRegAsmOperands"; +} +def GPR32AsmOperand : MipsAsmRegOperand { + let Name = "GPR32Asm"; + let ParserMethod = "parseGPR32"; +} + +def GPR64AsmOperand : MipsAsmRegOperand { + let Name = "GPR64Asm"; + let ParserMethod = "parseGPR64"; +} + +def ACC64DSPAsmOperand : MipsAsmRegOperand { + let Name = "ACC64DSPAsm"; + let ParserMethod = "parseACC64DSP"; +} + +def LO32DSPAsmOperand : MipsAsmRegOperand { + let Name = "LO32DSPAsm"; + let ParserMethod = "parseLO32DSP"; +} + +def HI32DSPAsmOperand : MipsAsmRegOperand { + let Name = "HI32DSPAsm"; + let ParserMethod = "parseHI32DSP"; +} + +def CCRAsmOperand : MipsAsmRegOperand { + let Name = "CCRAsm"; + let ParserMethod = "parseCCRRegs"; +} + +def AFGR64AsmOperand : MipsAsmRegOperand { + let Name = "AFGR64Asm"; + let ParserMethod = "parseAFGR64Regs"; +} + +def FGR64AsmOperand : MipsAsmRegOperand { + let Name = "FGR64Asm"; + let ParserMethod = "parseFGR64Regs"; +} + +def FGR32AsmOperand : MipsAsmRegOperand { + let Name = "FGR32Asm"; + let ParserMethod = "parseFGR32Regs"; +} + +def FGRH32AsmOperand : MipsAsmRegOperand { + let Name = "FGRH32Asm"; + let ParserMethod = "parseFGRH32Regs"; +} + +def FCCRegsAsmOperand : MipsAsmRegOperand { + let Name = "FCCRegsAsm"; + let ParserMethod = "parseFCCRegs"; +} + +def MSA128BAsmOperand : MipsAsmRegOperand { + let Name = "MSA128BAsm"; + let ParserMethod = "parseMSA128BRegs"; +} + +def MSA128HAsmOperand : MipsAsmRegOperand { + let Name = "MSA128HAsm"; + let ParserMethod = "parseMSA128HRegs"; +} + +def MSA128WAsmOperand : MipsAsmRegOperand { + let Name = "MSA128WAsm"; + let ParserMethod = "parseMSA128WRegs"; +} + +def MSA128DAsmOperand : MipsAsmRegOperand { + let Name = "MSA128DAsm"; + let ParserMethod = "parseMSA128DRegs"; +} + +def MSA128CRAsmOperand : MipsAsmRegOperand { + let Name = "MSA128CRAsm"; + let ParserMethod = "parseMSA128CtrlRegs"; +} + +def GPR32Opnd : RegisterOperand<GPR32> { + let ParserMatchClass = GPR32AsmOperand; +} + +def GPR64Opnd : RegisterOperand<GPR64> { + let ParserMatchClass = GPR64AsmOperand; +} + +def DSPROpnd : RegisterOperand<DSPR> { + let ParserMatchClass = GPR32AsmOperand; +} + +def CCROpnd : RegisterOperand<CCR> { + let ParserMatchClass = CCRAsmOperand; +} + +def HWRegsAsmOperand : MipsAsmRegOperand { + let Name = "HWRegsAsm"; + let ParserMethod = "parseHWRegs"; +} + +def COP2AsmOperand : MipsAsmRegOperand { + let Name = "COP2Asm"; + let ParserMethod = "parseCOP2"; +} + +def HWRegsOpnd : RegisterOperand<HWRegs> { + let ParserMatchClass = HWRegsAsmOperand; +} + +def AFGR64Opnd : RegisterOperand<AFGR64> { + let ParserMatchClass = AFGR64AsmOperand; +} + +def FGR64Opnd : RegisterOperand<FGR64> { + let ParserMatchClass = FGR64AsmOperand; +} + +def FGR32Opnd : RegisterOperand<FGR32> { + let ParserMatchClass = FGR32AsmOperand; +} + +def FGRH32Opnd : RegisterOperand<FGRH32> { + let ParserMatchClass = FGRH32AsmOperand; +} + +def FCCRegsOpnd : RegisterOperand<FCC> { + let ParserMatchClass = FCCRegsAsmOperand; +} + +def LO32DSPOpnd : RegisterOperand<LO32DSP> { + let ParserMatchClass = LO32DSPAsmOperand; +} + +def HI32DSPOpnd : RegisterOperand<HI32DSP> { + let ParserMatchClass = HI32DSPAsmOperand; +} + +def ACC64DSPOpnd : RegisterOperand<ACC64DSP> { + let ParserMatchClass = ACC64DSPAsmOperand; +} + +def COP2Opnd : RegisterOperand<COP2> { + let ParserMatchClass = COP2AsmOperand; +} + +def MSA128BOpnd : RegisterOperand<MSA128B> { + let ParserMatchClass = MSA128BAsmOperand; +} + +def MSA128HOpnd : RegisterOperand<MSA128H> { + let ParserMatchClass = MSA128HAsmOperand; +} + +def MSA128WOpnd : RegisterOperand<MSA128W> { + let ParserMatchClass = MSA128WAsmOperand; +} + +def MSA128DOpnd : RegisterOperand<MSA128D> { + let ParserMatchClass = MSA128DAsmOperand; +} + +def MSA128CROpnd : RegisterOperand<MSACtrl> { + let ParserMatchClass = MSA128CRAsmOperand; +} + diff --git a/contrib/llvm/lib/Target/Mips/MipsRelocations.h b/contrib/llvm/lib/Target/Mips/MipsRelocations.h new file mode 100644 index 000000000000..0787ed399d5f --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsRelocations.h @@ -0,0 +1,41 @@ +//===-- MipsRelocations.h - Mips 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 Mips target-specific relocation types +// (for relocation-model=static). +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSRELOCATIONS_H_ +#define MIPSRELOCATIONS_H_ + +#include "llvm/CodeGen/MachineRelocation.h" + +namespace llvm { + namespace Mips{ + enum RelocationType { + // reloc_mips_pc16 - pc relative relocation for branches. The lower 18 + // bits of the difference between the branch target and the branch + // instruction, shifted right by 2. + reloc_mips_pc16 = 1, + + // reloc_mips_hi - upper 16 bits of the address (modified by +1 if the + // lower 16 bits of the address is negative). + reloc_mips_hi = 2, + + // reloc_mips_lo - lower 16 bits of the address. + reloc_mips_lo = 3, + + // reloc_mips_26 - lower 28 bits of the address, shifted right by 2. + reloc_mips_26 = 4 + }; + } +} + +#endif /* MIPSRELOCATIONS_H_ */ diff --git a/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp new file mode 100644 index 000000000000..33ed4b3e3a67 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp @@ -0,0 +1,549 @@ +//===-- MipsSEFrameLowering.cpp - Mips32/64 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 Mips32/64 implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "MipsSEFrameLowering.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsMachineFunction.h" +#include "MipsSEInstrInfo.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/CodeGen/RegisterScavenging.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +namespace { +typedef MachineBasicBlock::iterator Iter; + +static std::pair<unsigned, unsigned> getMFHiLoOpc(unsigned Src) { + if (Mips::ACC64RegClass.contains(Src)) + return std::make_pair((unsigned)Mips::PseudoMFHI, + (unsigned)Mips::PseudoMFLO); + + if (Mips::ACC64DSPRegClass.contains(Src)) + return std::make_pair((unsigned)Mips::MFHI_DSP, (unsigned)Mips::MFLO_DSP); + + if (Mips::ACC128RegClass.contains(Src)) + return std::make_pair((unsigned)Mips::PseudoMFHI64, + (unsigned)Mips::PseudoMFLO64); + + return std::make_pair(0, 0); +} + +/// Helper class to expand pseudos. +class ExpandPseudo { +public: + ExpandPseudo(MachineFunction &MF); + bool expand(); + +private: + bool expandInstr(MachineBasicBlock &MBB, Iter I); + void expandLoadCCond(MachineBasicBlock &MBB, Iter I); + void expandStoreCCond(MachineBasicBlock &MBB, Iter I); + void expandLoadACC(MachineBasicBlock &MBB, Iter I, unsigned RegSize); + void expandStoreACC(MachineBasicBlock &MBB, Iter I, unsigned MFHiOpc, + unsigned MFLoOpc, unsigned RegSize); + bool expandCopy(MachineBasicBlock &MBB, Iter I); + bool expandCopyACC(MachineBasicBlock &MBB, Iter I, unsigned MFHiOpc, + unsigned MFLoOpc); + + MachineFunction &MF; + MachineRegisterInfo &MRI; +}; +} + +ExpandPseudo::ExpandPseudo(MachineFunction &MF_) + : MF(MF_), MRI(MF.getRegInfo()) {} + +bool ExpandPseudo::expand() { + bool Expanded = false; + + for (MachineFunction::iterator BB = MF.begin(), BBEnd = MF.end(); + BB != BBEnd; ++BB) + for (Iter I = BB->begin(), End = BB->end(); I != End;) + Expanded |= expandInstr(*BB, I++); + + return Expanded; +} + +bool ExpandPseudo::expandInstr(MachineBasicBlock &MBB, Iter I) { + switch(I->getOpcode()) { + case Mips::LOAD_CCOND_DSP: + expandLoadCCond(MBB, I); + break; + case Mips::STORE_CCOND_DSP: + expandStoreCCond(MBB, I); + break; + case Mips::LOAD_ACC64: + case Mips::LOAD_ACC64DSP: + expandLoadACC(MBB, I, 4); + break; + case Mips::LOAD_ACC128: + expandLoadACC(MBB, I, 8); + break; + case Mips::STORE_ACC64: + expandStoreACC(MBB, I, Mips::PseudoMFHI, Mips::PseudoMFLO, 4); + break; + case Mips::STORE_ACC64DSP: + expandStoreACC(MBB, I, Mips::MFHI_DSP, Mips::MFLO_DSP, 4); + break; + case Mips::STORE_ACC128: + expandStoreACC(MBB, I, Mips::PseudoMFHI64, Mips::PseudoMFLO64, 8); + break; + case TargetOpcode::COPY: + if (!expandCopy(MBB, I)) + return false; + break; + default: + return false; + } + + MBB.erase(I); + return true; +} + +void ExpandPseudo::expandLoadCCond(MachineBasicBlock &MBB, Iter I) { + // load $vr, FI + // copy ccond, $vr + + assert(I->getOperand(0).isReg() && I->getOperand(1).isFI()); + + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo*>(MF.getTarget().getInstrInfo()); + const MipsRegisterInfo &RegInfo = + *static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo()); + + const TargetRegisterClass *RC = RegInfo.intRegClass(4); + unsigned VR = MRI.createVirtualRegister(RC); + unsigned Dst = I->getOperand(0).getReg(), FI = I->getOperand(1).getIndex(); + + TII.loadRegFromStack(MBB, I, VR, FI, RC, &RegInfo, 0); + BuildMI(MBB, I, I->getDebugLoc(), TII.get(TargetOpcode::COPY), Dst) + .addReg(VR, RegState::Kill); +} + +void ExpandPseudo::expandStoreCCond(MachineBasicBlock &MBB, Iter I) { + // copy $vr, ccond + // store $vr, FI + + assert(I->getOperand(0).isReg() && I->getOperand(1).isFI()); + + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo*>(MF.getTarget().getInstrInfo()); + const MipsRegisterInfo &RegInfo = + *static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo()); + + const TargetRegisterClass *RC = RegInfo.intRegClass(4); + unsigned VR = MRI.createVirtualRegister(RC); + unsigned Src = I->getOperand(0).getReg(), FI = I->getOperand(1).getIndex(); + + BuildMI(MBB, I, I->getDebugLoc(), TII.get(TargetOpcode::COPY), VR) + .addReg(Src, getKillRegState(I->getOperand(0).isKill())); + TII.storeRegToStack(MBB, I, VR, true, FI, RC, &RegInfo, 0); +} + +void ExpandPseudo::expandLoadACC(MachineBasicBlock &MBB, Iter I, + unsigned RegSize) { + // load $vr0, FI + // copy lo, $vr0 + // load $vr1, FI + 4 + // copy hi, $vr1 + + assert(I->getOperand(0).isReg() && I->getOperand(1).isFI()); + + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo*>(MF.getTarget().getInstrInfo()); + const MipsRegisterInfo &RegInfo = + *static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo()); + + const TargetRegisterClass *RC = RegInfo.intRegClass(RegSize); + unsigned VR0 = MRI.createVirtualRegister(RC); + unsigned VR1 = MRI.createVirtualRegister(RC); + unsigned Dst = I->getOperand(0).getReg(), FI = I->getOperand(1).getIndex(); + unsigned Lo = RegInfo.getSubReg(Dst, Mips::sub_lo); + unsigned Hi = RegInfo.getSubReg(Dst, Mips::sub_hi); + DebugLoc DL = I->getDebugLoc(); + const MCInstrDesc &Desc = TII.get(TargetOpcode::COPY); + + TII.loadRegFromStack(MBB, I, VR0, FI, RC, &RegInfo, 0); + BuildMI(MBB, I, DL, Desc, Lo).addReg(VR0, RegState::Kill); + TII.loadRegFromStack(MBB, I, VR1, FI, RC, &RegInfo, RegSize); + BuildMI(MBB, I, DL, Desc, Hi).addReg(VR1, RegState::Kill); +} + +void ExpandPseudo::expandStoreACC(MachineBasicBlock &MBB, Iter I, + unsigned MFHiOpc, unsigned MFLoOpc, + unsigned RegSize) { + // mflo $vr0, src + // store $vr0, FI + // mfhi $vr1, src + // store $vr1, FI + 4 + + assert(I->getOperand(0).isReg() && I->getOperand(1).isFI()); + + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo*>(MF.getTarget().getInstrInfo()); + const MipsRegisterInfo &RegInfo = + *static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo()); + + const TargetRegisterClass *RC = RegInfo.intRegClass(RegSize); + unsigned VR0 = MRI.createVirtualRegister(RC); + unsigned VR1 = MRI.createVirtualRegister(RC); + unsigned Src = I->getOperand(0).getReg(), FI = I->getOperand(1).getIndex(); + unsigned SrcKill = getKillRegState(I->getOperand(0).isKill()); + DebugLoc DL = I->getDebugLoc(); + + BuildMI(MBB, I, DL, TII.get(MFLoOpc), VR0).addReg(Src); + TII.storeRegToStack(MBB, I, VR0, true, FI, RC, &RegInfo, 0); + BuildMI(MBB, I, DL, TII.get(MFHiOpc), VR1).addReg(Src, SrcKill); + TII.storeRegToStack(MBB, I, VR1, true, FI, RC, &RegInfo, RegSize); +} + +bool ExpandPseudo::expandCopy(MachineBasicBlock &MBB, Iter I) { + unsigned Src = I->getOperand(1).getReg(); + std::pair<unsigned, unsigned> Opcodes = getMFHiLoOpc(Src); + + if (!Opcodes.first) + return false; + + return expandCopyACC(MBB, I, Opcodes.first, Opcodes.second); +} + +bool ExpandPseudo::expandCopyACC(MachineBasicBlock &MBB, Iter I, + unsigned MFHiOpc, unsigned MFLoOpc) { + // mflo $vr0, src + // copy dst_lo, $vr0 + // mfhi $vr1, src + // copy dst_hi, $vr1 + + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo*>(MF.getTarget().getInstrInfo()); + const MipsRegisterInfo &RegInfo = + *static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo()); + + unsigned Dst = I->getOperand(0).getReg(), Src = I->getOperand(1).getReg(); + unsigned VRegSize = RegInfo.getMinimalPhysRegClass(Dst)->getSize() / 2; + const TargetRegisterClass *RC = RegInfo.intRegClass(VRegSize); + unsigned VR0 = MRI.createVirtualRegister(RC); + unsigned VR1 = MRI.createVirtualRegister(RC); + unsigned SrcKill = getKillRegState(I->getOperand(1).isKill()); + unsigned DstLo = RegInfo.getSubReg(Dst, Mips::sub_lo); + unsigned DstHi = RegInfo.getSubReg(Dst, Mips::sub_hi); + DebugLoc DL = I->getDebugLoc(); + + BuildMI(MBB, I, DL, TII.get(MFLoOpc), VR0).addReg(Src); + BuildMI(MBB, I, DL, TII.get(TargetOpcode::COPY), DstLo) + .addReg(VR0, RegState::Kill); + BuildMI(MBB, I, DL, TII.get(MFHiOpc), VR1).addReg(Src, SrcKill); + BuildMI(MBB, I, DL, TII.get(TargetOpcode::COPY), DstHi) + .addReg(VR1, RegState::Kill); + return true; +} + +unsigned MipsSEFrameLowering::ehDataReg(unsigned I) const { + static const unsigned EhDataReg[] = { + Mips::A0, Mips::A1, Mips::A2, Mips::A3 + }; + static const unsigned EhDataReg64[] = { + Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64 + }; + + return STI.isABI_N64() ? EhDataReg64[I] : EhDataReg[I]; +} + +void MipsSEFrameLowering::emitPrologue(MachineFunction &MF) const { + MachineBasicBlock &MBB = MF.front(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo*>(MF.getTarget().getInstrInfo()); + const MipsRegisterInfo &RegInfo = + *static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo()); + + MachineBasicBlock::iterator MBBI = MBB.begin(); + DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + unsigned SP = STI.isABI_N64() ? Mips::SP_64 : Mips::SP; + unsigned FP = STI.isABI_N64() ? Mips::FP_64 : Mips::FP; + unsigned ZERO = STI.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO; + unsigned ADDu = STI.isABI_N64() ? Mips::DADDu : Mips::ADDu; + + // First, compute final stack size. + uint64_t StackSize = MFI->getStackSize(); + + // No need to allocate space on the stack. + if (StackSize == 0 && !MFI->adjustsStack()) return; + + MachineModuleInfo &MMI = MF.getMMI(); + const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); + MachineLocation DstML, SrcML; + + // Adjust stack. + TII.adjustStackPtr(SP, -StackSize, MBB, MBBI); + + // emit ".cfi_def_cfa_offset StackSize" + MCSymbol *AdjustSPLabel = MMI.getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, + TII.get(TargetOpcode::PROLOG_LABEL)).addSym(AdjustSPLabel); + MMI.addFrameInst( + MCCFIInstruction::createDefCfaOffset(AdjustSPLabel, -StackSize)); + + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + + if (CSI.size()) { + // Find the instruction past the last instruction that saves a callee-saved + // register to the stack. + for (unsigned i = 0; i < CSI.size(); ++i) + ++MBBI; + + // Iterate over list of callee-saved registers and emit .cfi_offset + // directives. + MCSymbol *CSLabel = MMI.getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, + TII.get(TargetOpcode::PROLOG_LABEL)).addSym(CSLabel); + + for (std::vector<CalleeSavedInfo>::const_iterator I = CSI.begin(), + E = CSI.end(); I != E; ++I) { + int64_t Offset = MFI->getObjectOffset(I->getFrameIdx()); + unsigned Reg = I->getReg(); + + // If Reg is a double precision register, emit two cfa_offsets, + // one for each of the paired single precision registers. + if (Mips::AFGR64RegClass.contains(Reg)) { + unsigned Reg0 = + MRI->getDwarfRegNum(RegInfo.getSubReg(Reg, Mips::sub_lo), true); + unsigned Reg1 = + MRI->getDwarfRegNum(RegInfo.getSubReg(Reg, Mips::sub_hi), true); + + if (!STI.isLittle()) + std::swap(Reg0, Reg1); + + MMI.addFrameInst( + MCCFIInstruction::createOffset(CSLabel, Reg0, Offset)); + MMI.addFrameInst( + MCCFIInstruction::createOffset(CSLabel, Reg1, Offset + 4)); + } else { + // Reg is either in GPR32 or FGR32. + MMI.addFrameInst(MCCFIInstruction::createOffset( + CSLabel, MRI->getDwarfRegNum(Reg, 1), Offset)); + } + } + } + + if (MipsFI->callsEhReturn()) { + const TargetRegisterClass *RC = STI.isABI_N64() ? + &Mips::GPR64RegClass : &Mips::GPR32RegClass; + + // Insert instructions that spill eh data registers. + for (int I = 0; I < 4; ++I) { + if (!MBB.isLiveIn(ehDataReg(I))) + MBB.addLiveIn(ehDataReg(I)); + TII.storeRegToStackSlot(MBB, MBBI, ehDataReg(I), false, + MipsFI->getEhDataRegFI(I), RC, &RegInfo); + } + + // Emit .cfi_offset directives for eh data registers. + MCSymbol *CSLabel2 = MMI.getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, + TII.get(TargetOpcode::PROLOG_LABEL)).addSym(CSLabel2); + for (int I = 0; I < 4; ++I) { + int64_t Offset = MFI->getObjectOffset(MipsFI->getEhDataRegFI(I)); + unsigned Reg = MRI->getDwarfRegNum(ehDataReg(I), true); + MMI.addFrameInst(MCCFIInstruction::createOffset(CSLabel2, Reg, Offset)); + } + } + + // if framepointer enabled, set it to point to the stack pointer. + if (hasFP(MF)) { + // Insert instruction "move $fp, $sp" at this location. + BuildMI(MBB, MBBI, dl, TII.get(ADDu), FP).addReg(SP).addReg(ZERO); + + // emit ".cfi_def_cfa_register $fp" + MCSymbol *SetFPLabel = MMI.getContext().CreateTempSymbol(); + BuildMI(MBB, MBBI, dl, + TII.get(TargetOpcode::PROLOG_LABEL)).addSym(SetFPLabel); + MMI.addFrameInst(MCCFIInstruction::createDefCfaRegister( + SetFPLabel, MRI->getDwarfRegNum(FP, true))); + } +} + +void MipsSEFrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo*>(MF.getTarget().getInstrInfo()); + const MipsRegisterInfo &RegInfo = + *static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo()); + + DebugLoc dl = MBBI->getDebugLoc(); + unsigned SP = STI.isABI_N64() ? Mips::SP_64 : Mips::SP; + unsigned FP = STI.isABI_N64() ? Mips::FP_64 : Mips::FP; + unsigned ZERO = STI.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO; + unsigned ADDu = STI.isABI_N64() ? Mips::DADDu : Mips::ADDu; + + // if framepointer enabled, restore the stack pointer. + if (hasFP(MF)) { + // Find the first instruction that restores a callee-saved register. + MachineBasicBlock::iterator I = MBBI; + + for (unsigned i = 0; i < MFI->getCalleeSavedInfo().size(); ++i) + --I; + + // Insert instruction "move $sp, $fp" at this location. + BuildMI(MBB, I, dl, TII.get(ADDu), SP).addReg(FP).addReg(ZERO); + } + + if (MipsFI->callsEhReturn()) { + const TargetRegisterClass *RC = STI.isABI_N64() ? + &Mips::GPR64RegClass : &Mips::GPR32RegClass; + + // Find first instruction that restores a callee-saved register. + MachineBasicBlock::iterator I = MBBI; + for (unsigned i = 0; i < MFI->getCalleeSavedInfo().size(); ++i) + --I; + + // Insert instructions that restore eh data registers. + for (int J = 0; J < 4; ++J) { + TII.loadRegFromStackSlot(MBB, I, ehDataReg(J), MipsFI->getEhDataRegFI(J), + RC, &RegInfo); + } + } + + // Get the number of bytes from FrameInfo + uint64_t StackSize = MFI->getStackSize(); + + if (!StackSize) + return; + + // Adjust stack. + TII.adjustStackPtr(SP, StackSize, MBB, MBBI); +} + +bool MipsSEFrameLowering:: +spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const { + MachineFunction *MF = MBB.getParent(); + MachineBasicBlock *EntryBlock = MF->begin(); + const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo(); + + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + // Add the callee-saved register as live-in. Do not add if the register is + // RA and return address is taken, because it has already been added in + // method MipsTargetLowering::LowerRETURNADDR. + // It's killed at the spill, unless the register is RA and return address + // is taken. + unsigned Reg = CSI[i].getReg(); + bool IsRAAndRetAddrIsTaken = (Reg == Mips::RA || Reg == Mips::RA_64) + && MF->getFrameInfo()->isReturnAddressTaken(); + if (!IsRAAndRetAddrIsTaken) + EntryBlock->addLiveIn(Reg); + + // Insert the spill to the stack frame. + bool IsKill = !IsRAAndRetAddrIsTaken; + const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); + TII.storeRegToStackSlot(*EntryBlock, MI, Reg, IsKill, + CSI[i].getFrameIdx(), RC, TRI); + } + + return true; +} + +bool +MipsSEFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + + // Reserve call frame if the size of the maximum call frame fits into 16-bit + // immediate field and there are no variable sized objects on the stack. + // Make sure the second register scavenger spill slot can be accessed with one + // instruction. + return isInt<16>(MFI->getMaxCallFrameSize() + getStackAlignment()) && + !MFI->hasVarSizedObjects(); +} + +// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions +void MipsSEFrameLowering:: +eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo*>(MF.getTarget().getInstrInfo()); + + if (!hasReservedCallFrame(MF)) { + int64_t Amount = I->getOperand(0).getImm(); + + if (I->getOpcode() == Mips::ADJCALLSTACKDOWN) + Amount = -Amount; + + unsigned SP = STI.isABI_N64() ? Mips::SP_64 : Mips::SP; + TII.adjustStackPtr(SP, Amount, MBB, I); + } + + MBB.erase(I); +} + +void MipsSEFrameLowering:: +processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const { + MachineRegisterInfo &MRI = MF.getRegInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + unsigned FP = STI.isABI_N64() ? Mips::FP_64 : Mips::FP; + + // Mark $fp as used if function has dedicated frame pointer. + if (hasFP(MF)) + MRI.setPhysRegUsed(FP); + + // Create spill slots for eh data registers if function calls eh_return. + if (MipsFI->callsEhReturn()) + MipsFI->createEhDataRegsFI(); + + // Expand pseudo instructions which load, store or copy accumulators. + // Add an emergency spill slot if a pseudo was expanded. + if (ExpandPseudo(MF).expand()) { + // The spill slot should be half the size of the accumulator. If target is + // mips64, it should be 64-bit, otherwise it should be 32-bt. + const TargetRegisterClass *RC = STI.hasMips64() ? + &Mips::GPR64RegClass : &Mips::GPR32RegClass; + int FI = MF.getFrameInfo()->CreateStackObject(RC->getSize(), + RC->getAlignment(), false); + RS->addScavengingFrameIndex(FI); + } + + // Set scavenging frame index if necessary. + uint64_t MaxSPOffset = MF.getInfo<MipsFunctionInfo>()->getIncomingArgSize() + + estimateStackSize(MF); + + if (isInt<16>(MaxSPOffset)) + return; + + const TargetRegisterClass *RC = STI.isABI_N64() ? + &Mips::GPR64RegClass : &Mips::GPR32RegClass; + int FI = MF.getFrameInfo()->CreateStackObject(RC->getSize(), + RC->getAlignment(), false); + RS->addScavengingFrameIndex(FI); +} + +const MipsFrameLowering * +llvm::createMipsSEFrameLowering(const MipsSubtarget &ST) { + return new MipsSEFrameLowering(ST); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.h b/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.h new file mode 100644 index 000000000000..8fa9e469887d --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEFrameLowering.h @@ -0,0 +1,49 @@ +//===-- MipsSEFrameLowering.h - Mips32/64 frame lowering --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSSE_FRAMEINFO_H +#define MIPSSE_FRAMEINFO_H + +#include "MipsFrameLowering.h" + +namespace llvm { + +class MipsSEFrameLowering : public MipsFrameLowering { +public: + explicit MipsSEFrameLowering(const MipsSubtarget &STI) + : MipsFrameLowering(STI, STI.stackAlignment()) {} + + /// emitProlog/emitEpilog - These methods insert prolog and epilog code into + /// the function. + void emitPrologue(MachineFunction &MF) const; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const; + + bool hasReservedCallFrame(const MachineFunction &MF) const; + + void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const; + unsigned ehDataReg(unsigned I) const; +}; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp new file mode 100644 index 000000000000..737660ec876c --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp @@ -0,0 +1,849 @@ +//===-- MipsSEISelDAGToDAG.cpp - A Dag to Dag Inst Selector for MipsSE ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsDAGToDAGISel specialized for mips32/64. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-isel" +#include "MipsSEISelDAGToDAG.h" +#include "Mips.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsMachineFunction.h" +#include "MipsRegisterInfo.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/CFG.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +using namespace llvm; + +bool MipsSEDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { + if (Subtarget.inMips16Mode()) + return false; + return MipsDAGToDAGISel::runOnMachineFunction(MF); +} + +void MipsSEDAGToDAGISel::addDSPCtrlRegOperands(bool IsDef, MachineInstr &MI, + MachineFunction &MF) { + MachineInstrBuilder MIB(MF, &MI); + unsigned Mask = MI.getOperand(1).getImm(); + unsigned Flag = IsDef ? RegState::ImplicitDefine : RegState::Implicit; + + if (Mask & 1) + MIB.addReg(Mips::DSPPos, Flag); + + if (Mask & 2) + MIB.addReg(Mips::DSPSCount, Flag); + + if (Mask & 4) + MIB.addReg(Mips::DSPCarry, Flag); + + if (Mask & 8) + MIB.addReg(Mips::DSPOutFlag, Flag); + + if (Mask & 16) + MIB.addReg(Mips::DSPCCond, Flag); + + if (Mask & 32) + MIB.addReg(Mips::DSPEFI, Flag); +} + +unsigned MipsSEDAGToDAGISel::getMSACtrlReg(const SDValue RegIdx) const { + switch (cast<ConstantSDNode>(RegIdx)->getZExtValue()) { + default: + llvm_unreachable("Could not map int to register"); + case 0: return Mips::MSAIR; + case 1: return Mips::MSACSR; + case 2: return Mips::MSAAccess; + case 3: return Mips::MSASave; + case 4: return Mips::MSAModify; + case 5: return Mips::MSARequest; + case 6: return Mips::MSAMap; + case 7: return Mips::MSAUnmap; + } +} + +bool MipsSEDAGToDAGISel::replaceUsesWithZeroReg(MachineRegisterInfo *MRI, + const MachineInstr& MI) { + unsigned DstReg = 0, ZeroReg = 0; + + // Check if MI is "addiu $dst, $zero, 0" or "daddiu $dst, $zero, 0". + if ((MI.getOpcode() == Mips::ADDiu) && + (MI.getOperand(1).getReg() == Mips::ZERO) && + (MI.getOperand(2).getImm() == 0)) { + DstReg = MI.getOperand(0).getReg(); + ZeroReg = Mips::ZERO; + } else if ((MI.getOpcode() == Mips::DADDiu) && + (MI.getOperand(1).getReg() == Mips::ZERO_64) && + (MI.getOperand(2).getImm() == 0)) { + DstReg = MI.getOperand(0).getReg(); + ZeroReg = Mips::ZERO_64; + } + + if (!DstReg) + return false; + + // Replace uses with ZeroReg. + for (MachineRegisterInfo::use_iterator U = MRI->use_begin(DstReg), + E = MRI->use_end(); U != E;) { + MachineOperand &MO = U.getOperand(); + unsigned OpNo = U.getOperandNo(); + MachineInstr *MI = MO.getParent(); + ++U; + + // Do not replace if it is a phi's operand or is tied to def operand. + if (MI->isPHI() || MI->isRegTiedToDefOperand(OpNo) || MI->isPseudo()) + continue; + + MO.setReg(ZeroReg); + } + + return true; +} + +void MipsSEDAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + if (!MipsFI->globalBaseRegSet()) + return; + + MachineBasicBlock &MBB = MF.front(); + MachineBasicBlock::iterator I = MBB.begin(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + unsigned V0, V1, GlobalBaseReg = MipsFI->getGlobalBaseReg(); + const TargetRegisterClass *RC; + + if (Subtarget.isABI_N64()) + RC = (const TargetRegisterClass*)&Mips::GPR64RegClass; + else + RC = (const TargetRegisterClass*)&Mips::GPR32RegClass; + + V0 = RegInfo.createVirtualRegister(RC); + V1 = RegInfo.createVirtualRegister(RC); + + if (Subtarget.isABI_N64()) { + MF.getRegInfo().addLiveIn(Mips::T9_64); + MBB.addLiveIn(Mips::T9_64); + + // lui $v0, %hi(%neg(%gp_rel(fname))) + // daddu $v1, $v0, $t9 + // daddiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname))) + const GlobalValue *FName = MF.getFunction(); + BuildMI(MBB, I, DL, TII.get(Mips::LUi64), V0) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI); + BuildMI(MBB, I, DL, TII.get(Mips::DADDu), V1).addReg(V0) + .addReg(Mips::T9_64); + BuildMI(MBB, I, DL, TII.get(Mips::DADDiu), GlobalBaseReg).addReg(V1) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO); + return; + } + + if (MF.getTarget().getRelocationModel() == Reloc::Static) { + // Set global register to __gnu_local_gp. + // + // lui $v0, %hi(__gnu_local_gp) + // addiu $globalbasereg, $v0, %lo(__gnu_local_gp) + BuildMI(MBB, I, DL, TII.get(Mips::LUi), V0) + .addExternalSymbol("__gnu_local_gp", MipsII::MO_ABS_HI); + BuildMI(MBB, I, DL, TII.get(Mips::ADDiu), GlobalBaseReg).addReg(V0) + .addExternalSymbol("__gnu_local_gp", MipsII::MO_ABS_LO); + return; + } + + MF.getRegInfo().addLiveIn(Mips::T9); + MBB.addLiveIn(Mips::T9); + + if (Subtarget.isABI_N32()) { + // lui $v0, %hi(%neg(%gp_rel(fname))) + // addu $v1, $v0, $t9 + // addiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname))) + const GlobalValue *FName = MF.getFunction(); + BuildMI(MBB, I, DL, TII.get(Mips::LUi), V0) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI); + BuildMI(MBB, I, DL, TII.get(Mips::ADDu), V1).addReg(V0).addReg(Mips::T9); + BuildMI(MBB, I, DL, TII.get(Mips::ADDiu), GlobalBaseReg).addReg(V1) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO); + return; + } + + assert(Subtarget.isABI_O32()); + + // For O32 ABI, the following instruction sequence is emitted to initialize + // the global base register: + // + // 0. lui $2, %hi(_gp_disp) + // 1. addiu $2, $2, %lo(_gp_disp) + // 2. addu $globalbasereg, $2, $t9 + // + // We emit only the last instruction here. + // + // GNU linker requires that the first two instructions appear at the beginning + // of a function and no instructions be inserted before or between them. + // The two instructions are emitted during lowering to MC layer in order to + // avoid any reordering. + // + // Register $2 (Mips::V0) is added to the list of live-in registers to ensure + // the value instruction 1 (addiu) defines is valid when instruction 2 (addu) + // reads it. + MF.getRegInfo().addLiveIn(Mips::V0); + MBB.addLiveIn(Mips::V0); + BuildMI(MBB, I, DL, TII.get(Mips::ADDu), GlobalBaseReg) + .addReg(Mips::V0).addReg(Mips::T9); +} + +void MipsSEDAGToDAGISel::processFunctionAfterISel(MachineFunction &MF) { + initGlobalBaseReg(MF); + + MachineRegisterInfo *MRI = &MF.getRegInfo(); + + for (MachineFunction::iterator MFI = MF.begin(), MFE = MF.end(); MFI != MFE; + ++MFI) + for (MachineBasicBlock::iterator I = MFI->begin(); I != MFI->end(); ++I) { + if (I->getOpcode() == Mips::RDDSP) + addDSPCtrlRegOperands(false, *I, MF); + else if (I->getOpcode() == Mips::WRDSP) + addDSPCtrlRegOperands(true, *I, MF); + else + replaceUsesWithZeroReg(MRI, *I); + } +} + +SDNode *MipsSEDAGToDAGISel::selectAddESubE(unsigned MOp, SDValue InFlag, + SDValue CmpLHS, SDLoc DL, + SDNode *Node) const { + unsigned Opc = InFlag.getOpcode(); (void)Opc; + + assert(((Opc == ISD::ADDC || Opc == ISD::ADDE) || + (Opc == ISD::SUBC || Opc == ISD::SUBE)) && + "(ADD|SUB)E flag operand must come from (ADD|SUB)C/E insn"); + + SDValue Ops[] = { CmpLHS, InFlag.getOperand(1) }; + SDValue LHS = Node->getOperand(0), RHS = Node->getOperand(1); + EVT VT = LHS.getValueType(); + + SDNode *Carry = CurDAG->getMachineNode(Mips::SLTu, DL, VT, Ops); + SDNode *AddCarry = CurDAG->getMachineNode(Mips::ADDu, DL, VT, + SDValue(Carry, 0), RHS); + return CurDAG->SelectNodeTo(Node, MOp, VT, MVT::Glue, LHS, + SDValue(AddCarry, 0)); +} + +/// ComplexPattern used on MipsInstrInfo +/// Used on Mips Load/Store instructions +bool MipsSEDAGToDAGISel::selectAddrRegImm(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + EVT ValTy = Addr.getValueType(); + + // if Address is FI, get the TargetFrameIndex. + if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + Offset = CurDAG->getTargetConstant(0, ValTy); + return true; + } + + // on PIC code Load GA + if (Addr.getOpcode() == MipsISD::Wrapper) { + Base = Addr.getOperand(0); + Offset = Addr.getOperand(1); + return true; + } + + if (TM.getRelocationModel() != Reloc::PIC_) { + if ((Addr.getOpcode() == ISD::TargetExternalSymbol || + Addr.getOpcode() == ISD::TargetGlobalAddress)) + return false; + } + + // Addresses of the form FI+const or FI|const + if (CurDAG->isBaseWithConstantOffset(Addr)) { + ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)); + if (isInt<16>(CN->getSExtValue())) { + + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode> + (Addr.getOperand(0))) + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + else + Base = Addr.getOperand(0); + + Offset = CurDAG->getTargetConstant(CN->getZExtValue(), ValTy); + return true; + } + } + + // Operand is a result from an ADD. + if (Addr.getOpcode() == ISD::ADD) { + // When loading from constant pools, load the lower address part in + // the instruction itself. Example, instead of: + // lui $2, %hi($CPI1_0) + // addiu $2, $2, %lo($CPI1_0) + // lwc1 $f0, 0($2) + // Generate: + // lui $2, %hi($CPI1_0) + // lwc1 $f0, %lo($CPI1_0)($2) + if (Addr.getOperand(1).getOpcode() == MipsISD::Lo || + Addr.getOperand(1).getOpcode() == MipsISD::GPRel) { + SDValue Opnd0 = Addr.getOperand(1).getOperand(0); + if (isa<ConstantPoolSDNode>(Opnd0) || isa<GlobalAddressSDNode>(Opnd0) || + isa<JumpTableSDNode>(Opnd0)) { + Base = Addr.getOperand(0); + Offset = Opnd0; + return true; + } + } + } + + return false; +} + +/// ComplexPattern used on MipsInstrInfo +/// Used on Mips Load/Store instructions +bool MipsSEDAGToDAGISel::selectAddrRegReg(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + // Operand is a result from an ADD. + if (Addr.getOpcode() == ISD::ADD) { + Base = Addr.getOperand(0); + Offset = Addr.getOperand(1); + return true; + } + + return false; +} + +bool MipsSEDAGToDAGISel::selectAddrDefault(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + Base = Addr; + Offset = CurDAG->getTargetConstant(0, Addr.getValueType()); + return true; +} + +bool MipsSEDAGToDAGISel::selectIntAddr(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + return selectAddrRegImm(Addr, Base, Offset) || + selectAddrDefault(Addr, Base, Offset); +} + +/// Used on microMIPS Load/Store unaligned instructions (12-bit offset) +bool MipsSEDAGToDAGISel::selectAddrRegImm12(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + EVT ValTy = Addr.getValueType(); + + // Addresses of the form FI+const or FI|const + if (CurDAG->isBaseWithConstantOffset(Addr)) { + ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)); + if (isInt<12>(CN->getSExtValue())) { + + // If the first operand is a FI then get the TargetFI Node + if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode> + (Addr.getOperand(0))) + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + else + Base = Addr.getOperand(0); + + Offset = CurDAG->getTargetConstant(CN->getZExtValue(), ValTy); + return true; + } + } + + return false; +} + +bool MipsSEDAGToDAGISel::selectIntAddrMM(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + return selectAddrRegImm12(Addr, Base, Offset) || + selectAddrDefault(Addr, Base, Offset); +} + +// Select constant vector splats. +// +// Returns true and sets Imm if: +// * MSA is enabled +// * N is a ISD::BUILD_VECTOR representing a constant splat +bool MipsSEDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm) const { + if (!Subtarget.hasMSA()) + return false; + + BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N); + + if (Node == NULL) + return false; + + APInt SplatValue, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + + if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, + HasAnyUndefs, 8, + !Subtarget.isLittle())) + return false; + + Imm = SplatValue; + + return true; +} + +// Select constant vector splats. +// +// In addition to the requirements of selectVSplat(), this function returns +// true and sets Imm if: +// * The splat value is the same width as the elements of the vector +// * The splat value fits in an integer with the specified signed-ness and +// width. +// +// This function looks through ISD::BITCAST nodes. +// TODO: This might not be appropriate for big-endian MSA since BITCAST is +// sometimes a shuffle in big-endian mode. +// +// It's worth noting that this function is not used as part of the selection +// of ldi.[bhwd] since it does not permit using the wrong-typed ldi.[bhwd] +// instruction to achieve the desired bit pattern. ldi.[bhwd] is selected in +// MipsSEDAGToDAGISel::selectNode. +bool MipsSEDAGToDAGISel:: +selectVSplatCommon(SDValue N, SDValue &Imm, bool Signed, + unsigned ImmBitSize) const { + APInt ImmValue; + EVT EltTy = N->getValueType(0).getVectorElementType(); + + if (N->getOpcode() == ISD::BITCAST) + N = N->getOperand(0); + + if (selectVSplat (N.getNode(), ImmValue) && + ImmValue.getBitWidth() == EltTy.getSizeInBits()) { + if (( Signed && ImmValue.isSignedIntN(ImmBitSize)) || + (!Signed && ImmValue.isIntN(ImmBitSize))) { + Imm = CurDAG->getTargetConstant(ImmValue, EltTy); + return true; + } + } + + return false; +} + +// Select constant vector splats. +bool MipsSEDAGToDAGISel:: +selectVSplatUimm1(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 1); +} + +bool MipsSEDAGToDAGISel:: +selectVSplatUimm2(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 2); +} + +bool MipsSEDAGToDAGISel:: +selectVSplatUimm3(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 3); +} + +// Select constant vector splats. +bool MipsSEDAGToDAGISel:: +selectVSplatUimm4(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 4); +} + +// Select constant vector splats. +bool MipsSEDAGToDAGISel:: +selectVSplatUimm5(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 5); +} + +// Select constant vector splats. +bool MipsSEDAGToDAGISel:: +selectVSplatUimm6(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 6); +} + +// Select constant vector splats. +bool MipsSEDAGToDAGISel:: +selectVSplatUimm8(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, false, 8); +} + +// Select constant vector splats. +bool MipsSEDAGToDAGISel:: +selectVSplatSimm5(SDValue N, SDValue &Imm) const { + return selectVSplatCommon(N, Imm, true, 5); +} + +// Select constant vector splats whose value is a power of 2. +// +// In addition to the requirements of selectVSplat(), this function returns +// true and sets Imm if: +// * The splat value is the same width as the elements of the vector +// * The splat value is a power of two. +// +// This function looks through ISD::BITCAST nodes. +// TODO: This might not be appropriate for big-endian MSA since BITCAST is +// sometimes a shuffle in big-endian mode. +bool MipsSEDAGToDAGISel::selectVSplatUimmPow2(SDValue N, SDValue &Imm) const { + APInt ImmValue; + EVT EltTy = N->getValueType(0).getVectorElementType(); + + if (N->getOpcode() == ISD::BITCAST) + N = N->getOperand(0); + + if (selectVSplat (N.getNode(), ImmValue) && + ImmValue.getBitWidth() == EltTy.getSizeInBits()) { + int32_t Log2 = ImmValue.exactLogBase2(); + + if (Log2 != -1) { + Imm = CurDAG->getTargetConstant(Log2, EltTy); + return true; + } + } + + return false; +} + +// Select constant vector splats whose value only has a consecutive sequence +// of left-most bits set (e.g. 0b11...1100...00). +// +// In addition to the requirements of selectVSplat(), this function returns +// true and sets Imm if: +// * The splat value is the same width as the elements of the vector +// * The splat value is a consecutive sequence of left-most bits. +// +// This function looks through ISD::BITCAST nodes. +// TODO: This might not be appropriate for big-endian MSA since BITCAST is +// sometimes a shuffle in big-endian mode. +bool MipsSEDAGToDAGISel::selectVSplatMaskL(SDValue N, SDValue &Imm) const { + APInt ImmValue; + EVT EltTy = N->getValueType(0).getVectorElementType(); + + if (N->getOpcode() == ISD::BITCAST) + N = N->getOperand(0); + + if (selectVSplat(N.getNode(), ImmValue) && + ImmValue.getBitWidth() == EltTy.getSizeInBits()) { + // Extract the run of set bits starting with bit zero from the bitwise + // inverse of ImmValue, and test that the inverse of this is the same + // as the original value. + if (ImmValue == ~(~ImmValue & ~(~ImmValue + 1))) { + + Imm = CurDAG->getTargetConstant(ImmValue.countPopulation(), EltTy); + return true; + } + } + + return false; +} + +// Select constant vector splats whose value only has a consecutive sequence +// of right-most bits set (e.g. 0b00...0011...11). +// +// In addition to the requirements of selectVSplat(), this function returns +// true and sets Imm if: +// * The splat value is the same width as the elements of the vector +// * The splat value is a consecutive sequence of right-most bits. +// +// This function looks through ISD::BITCAST nodes. +// TODO: This might not be appropriate for big-endian MSA since BITCAST is +// sometimes a shuffle in big-endian mode. +bool MipsSEDAGToDAGISel::selectVSplatMaskR(SDValue N, SDValue &Imm) const { + APInt ImmValue; + EVT EltTy = N->getValueType(0).getVectorElementType(); + + if (N->getOpcode() == ISD::BITCAST) + N = N->getOperand(0); + + if (selectVSplat(N.getNode(), ImmValue) && + ImmValue.getBitWidth() == EltTy.getSizeInBits()) { + // Extract the run of set bits starting with bit zero, and test that the + // result is the same as the original value + if (ImmValue == (ImmValue & ~(ImmValue + 1))) { + Imm = CurDAG->getTargetConstant(ImmValue.countPopulation(), EltTy); + return true; + } + } + + return false; +} + +bool MipsSEDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N, + SDValue &Imm) const { + APInt ImmValue; + EVT EltTy = N->getValueType(0).getVectorElementType(); + + if (N->getOpcode() == ISD::BITCAST) + N = N->getOperand(0); + + if (selectVSplat(N.getNode(), ImmValue) && + ImmValue.getBitWidth() == EltTy.getSizeInBits()) { + int32_t Log2 = (~ImmValue).exactLogBase2(); + + if (Log2 != -1) { + Imm = CurDAG->getTargetConstant(Log2, EltTy); + return true; + } + } + + return false; +} + +std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) { + unsigned Opcode = Node->getOpcode(); + SDLoc DL(Node); + + /// + // Instruction Selection not handled by the auto-generated + // tablegen selection should be handled here. + /// + SDNode *Result; + + switch(Opcode) { + default: break; + + case ISD::SUBE: { + SDValue InFlag = Node->getOperand(2); + Result = selectAddESubE(Mips::SUBu, InFlag, InFlag.getOperand(0), DL, Node); + return std::make_pair(true, Result); + } + + case ISD::ADDE: { + if (Subtarget.hasDSP()) // Select DSP instructions, ADDSC and ADDWC. + break; + SDValue InFlag = Node->getOperand(2); + Result = selectAddESubE(Mips::ADDu, InFlag, InFlag.getValue(0), DL, Node); + return std::make_pair(true, Result); + } + + case ISD::ConstantFP: { + ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(Node); + if (Node->getValueType(0) == MVT::f64 && CN->isExactlyValue(+0.0)) { + if (Subtarget.hasMips64()) { + SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, + Mips::ZERO_64, MVT::i64); + Result = CurDAG->getMachineNode(Mips::DMTC1, DL, MVT::f64, Zero); + } else if (Subtarget.isFP64bit()) { + SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, + Mips::ZERO, MVT::i32); + Result = CurDAG->getMachineNode(Mips::BuildPairF64_64, DL, MVT::f64, + Zero, Zero); + } else { + SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, + Mips::ZERO, MVT::i32); + Result = CurDAG->getMachineNode(Mips::BuildPairF64, DL, MVT::f64, Zero, + Zero); + } + + return std::make_pair(true, Result); + } + break; + } + + case ISD::Constant: { + const ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Node); + unsigned Size = CN->getValueSizeInBits(0); + + if (Size == 32) + break; + + MipsAnalyzeImmediate AnalyzeImm; + int64_t Imm = CN->getSExtValue(); + + const MipsAnalyzeImmediate::InstSeq &Seq = + AnalyzeImm.Analyze(Imm, Size, false); + + MipsAnalyzeImmediate::InstSeq::const_iterator Inst = Seq.begin(); + SDLoc DL(CN); + SDNode *RegOpnd; + SDValue ImmOpnd = CurDAG->getTargetConstant(SignExtend64<16>(Inst->ImmOpnd), + MVT::i64); + + // The first instruction can be a LUi which is different from other + // instructions (ADDiu, ORI and SLL) in that it does not have a register + // operand. + if (Inst->Opc == Mips::LUi64) + RegOpnd = CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64, ImmOpnd); + else + RegOpnd = + CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64, + CurDAG->getRegister(Mips::ZERO_64, MVT::i64), + ImmOpnd); + + // The remaining instructions in the sequence are handled here. + for (++Inst; Inst != Seq.end(); ++Inst) { + ImmOpnd = CurDAG->getTargetConstant(SignExtend64<16>(Inst->ImmOpnd), + MVT::i64); + RegOpnd = CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64, + SDValue(RegOpnd, 0), ImmOpnd); + } + + return std::make_pair(true, RegOpnd); + } + + case ISD::INTRINSIC_W_CHAIN: { + switch (cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue()) { + default: + break; + + case Intrinsic::mips_cfcmsa: { + SDValue ChainIn = Node->getOperand(0); + SDValue RegIdx = Node->getOperand(2); + SDValue Reg = CurDAG->getCopyFromReg(ChainIn, DL, + getMSACtrlReg(RegIdx), MVT::i32); + return std::make_pair(true, Reg.getNode()); + } + } + break; + } + + case ISD::INTRINSIC_WO_CHAIN: { + switch (cast<ConstantSDNode>(Node->getOperand(0))->getZExtValue()) { + default: + break; + + case Intrinsic::mips_move_v: + // Like an assignment but will always produce a move.v even if + // unnecessary. + return std::make_pair(true, + CurDAG->getMachineNode(Mips::MOVE_V, DL, + Node->getValueType(0), + Node->getOperand(1))); + } + break; + } + + case ISD::INTRINSIC_VOID: { + switch (cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue()) { + default: + break; + + case Intrinsic::mips_ctcmsa: { + SDValue ChainIn = Node->getOperand(0); + SDValue RegIdx = Node->getOperand(2); + SDValue Value = Node->getOperand(3); + SDValue ChainOut = CurDAG->getCopyToReg(ChainIn, DL, + getMSACtrlReg(RegIdx), Value); + return std::make_pair(true, ChainOut.getNode()); + } + } + break; + } + + case MipsISD::ThreadPointer: { + EVT PtrVT = getTargetLowering()->getPointerTy(); + unsigned RdhwrOpc, DestReg; + + if (PtrVT == MVT::i32) { + RdhwrOpc = Mips::RDHWR; + DestReg = Mips::V1; + } else { + RdhwrOpc = Mips::RDHWR64; + DestReg = Mips::V1_64; + } + + SDNode *Rdhwr = + CurDAG->getMachineNode(RdhwrOpc, SDLoc(Node), + Node->getValueType(0), + CurDAG->getRegister(Mips::HWR29, MVT::i32)); + SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, DestReg, + SDValue(Rdhwr, 0)); + SDValue ResNode = CurDAG->getCopyFromReg(Chain, DL, DestReg, PtrVT); + ReplaceUses(SDValue(Node, 0), ResNode); + return std::make_pair(true, ResNode.getNode()); + } + + case ISD::BUILD_VECTOR: { + // Select appropriate ldi.[bhwd] instructions for constant splats of + // 128-bit when MSA is enabled. Fixup any register class mismatches that + // occur as a result. + // + // This allows the compiler to use a wider range of immediates than would + // otherwise be allowed. If, for example, v4i32 could only use ldi.h then + // it would not be possible to load { 0x01010101, 0x01010101, 0x01010101, + // 0x01010101 } without using a constant pool. This would be sub-optimal + // when // 'ldi.b wd, 1' is capable of producing that bit-pattern in the + // same set/ of registers. Similarly, ldi.h isn't capable of producing { + // 0x00000000, 0x00000001, 0x00000000, 0x00000001 } but 'ldi.d wd, 1' can. + + BuildVectorSDNode *BVN = cast<BuildVectorSDNode>(Node); + APInt SplatValue, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + unsigned LdiOp; + EVT ResVecTy = BVN->getValueType(0); + EVT ViaVecTy; + + if (!Subtarget.hasMSA() || !BVN->getValueType(0).is128BitVector()) + return std::make_pair(false, (SDNode*)NULL); + + if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, + HasAnyUndefs, 8, + !Subtarget.isLittle())) + return std::make_pair(false, (SDNode*)NULL); + + switch (SplatBitSize) { + default: + return std::make_pair(false, (SDNode*)NULL); + case 8: + LdiOp = Mips::LDI_B; + ViaVecTy = MVT::v16i8; + break; + case 16: + LdiOp = Mips::LDI_H; + ViaVecTy = MVT::v8i16; + break; + case 32: + LdiOp = Mips::LDI_W; + ViaVecTy = MVT::v4i32; + break; + case 64: + LdiOp = Mips::LDI_D; + ViaVecTy = MVT::v2i64; + break; + } + + if (!SplatValue.isSignedIntN(10)) + return std::make_pair(false, (SDNode*)NULL); + + SDValue Imm = CurDAG->getTargetConstant(SplatValue, + ViaVecTy.getVectorElementType()); + + SDNode *Res = CurDAG->getMachineNode(LdiOp, SDLoc(Node), ViaVecTy, Imm); + + if (ResVecTy != ViaVecTy) { + // If LdiOp is writing to a different register class to ResVecTy, then + // fix it up here. This COPY_TO_REGCLASS should never cause a move.v + // since the source and destination register sets contain the same + // registers. + const TargetLowering *TLI = getTargetLowering(); + MVT ResVecTySimple = ResVecTy.getSimpleVT(); + const TargetRegisterClass *RC = TLI->getRegClassFor(ResVecTySimple); + Res = CurDAG->getMachineNode(Mips::COPY_TO_REGCLASS, SDLoc(Node), + ResVecTy, SDValue(Res, 0), + CurDAG->getTargetConstant(RC->getID(), + MVT::i32)); + } + + return std::make_pair(true, Res); + } + + } + + return std::make_pair(false, (SDNode*)NULL); +} + +FunctionPass *llvm::createMipsSEISelDag(MipsTargetMachine &TM) { + return new MipsSEDAGToDAGISel(TM); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.h b/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.h new file mode 100644 index 000000000000..dc52064c9830 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEISelDAGToDAG.h @@ -0,0 +1,107 @@ +//===-- MipsSEISelDAGToDAG.h - A Dag to Dag Inst Selector for MipsSE -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsDAGToDAGISel specialized for mips32/64. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSSEISELDAGTODAG_H +#define MIPSSEISELDAGTODAG_H + +#include "MipsISelDAGToDAG.h" + +namespace llvm { + +class MipsSEDAGToDAGISel : public MipsDAGToDAGISel { + +public: + explicit MipsSEDAGToDAGISel(MipsTargetMachine &TM) : MipsDAGToDAGISel(TM) {} + +private: + + virtual bool runOnMachineFunction(MachineFunction &MF); + + void addDSPCtrlRegOperands(bool IsDef, MachineInstr &MI, + MachineFunction &MF); + + unsigned getMSACtrlReg(const SDValue RegIdx) const; + + bool replaceUsesWithZeroReg(MachineRegisterInfo *MRI, const MachineInstr&); + + std::pair<SDNode*, SDNode*> selectMULT(SDNode *N, unsigned Opc, SDLoc dl, + EVT Ty, bool HasLo, bool HasHi); + + SDNode *selectAddESubE(unsigned MOp, SDValue InFlag, SDValue CmpLHS, + SDLoc DL, SDNode *Node) const; + + virtual bool selectAddrRegImm(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + virtual bool selectAddrRegReg(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + virtual bool selectAddrDefault(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + virtual bool selectIntAddr(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + virtual bool selectAddrRegImm12(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + virtual bool selectIntAddrMM(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + /// \brief Select constant vector splats. + virtual bool selectVSplat(SDNode *N, APInt &Imm) const; + /// \brief Select constant vector splats whose value fits in a given integer. + virtual bool selectVSplatCommon(SDValue N, SDValue &Imm, bool Signed, + unsigned ImmBitSize) const; + /// \brief Select constant vector splats whose value fits in a uimm1. + virtual bool selectVSplatUimm1(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm2. + virtual bool selectVSplatUimm2(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm3. + virtual bool selectVSplatUimm3(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm4. + virtual bool selectVSplatUimm4(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm5. + virtual bool selectVSplatUimm5(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm6. + virtual bool selectVSplatUimm6(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a uimm8. + virtual bool selectVSplatUimm8(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value fits in a simm5. + virtual bool selectVSplatSimm5(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value is a power of 2. + virtual bool selectVSplatUimmPow2(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value is the inverse of a + /// power of 2. + virtual bool selectVSplatUimmInvPow2(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value is a run of set bits + /// ending at the most significant bit + virtual bool selectVSplatMaskL(SDValue N, SDValue &Imm) const; + /// \brief Select constant vector splats whose value is a run of set bits + /// starting at bit zero. + virtual bool selectVSplatMaskR(SDValue N, SDValue &Imm) const; + + virtual std::pair<bool, SDNode*> selectNode(SDNode *Node); + + virtual void processFunctionAfterISel(MachineFunction &MF); + + // Insert instructions to initialize the global base register in the + // first MBB of the function. + void initGlobalBaseReg(MachineFunction &MF); +}; + +FunctionPass *createMipsSEISelDag(MipsTargetMachine &TM); + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp new file mode 100644 index 000000000000..809adc03b151 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp @@ -0,0 +1,2975 @@ +//===-- MipsSEISelLowering.cpp - MipsSE 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. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsTargetLowering specialized for mips32/64. +// +//===----------------------------------------------------------------------===// +#define DEBUG_TYPE "mips-isel" +#include "MipsSEISelLowering.h" +#include "MipsRegisterInfo.h" +#include "MipsTargetMachine.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" + +using namespace llvm; + +static cl::opt<bool> +EnableMipsTailCalls("enable-mips-tail-calls", cl::Hidden, + cl::desc("MIPS: Enable tail calls."), cl::init(false)); + +static cl::opt<bool> NoDPLoadStore("mno-ldc1-sdc1", cl::init(false), + cl::desc("Expand double precision loads and " + "stores to their single precision " + "counterparts")); + +MipsSETargetLowering::MipsSETargetLowering(MipsTargetMachine &TM) + : MipsTargetLowering(TM) { + // Set up the register classes + addRegisterClass(MVT::i32, &Mips::GPR32RegClass); + + if (HasMips64) + addRegisterClass(MVT::i64, &Mips::GPR64RegClass); + + if (Subtarget->hasDSP() || Subtarget->hasMSA()) { + // Expand all truncating stores and extending loads. + unsigned FirstVT = (unsigned)MVT::FIRST_VECTOR_VALUETYPE; + unsigned LastVT = (unsigned)MVT::LAST_VECTOR_VALUETYPE; + + for (unsigned VT0 = FirstVT; VT0 <= LastVT; ++VT0) { + for (unsigned VT1 = FirstVT; VT1 <= LastVT; ++VT1) + setTruncStoreAction((MVT::SimpleValueType)VT0, + (MVT::SimpleValueType)VT1, Expand); + + setLoadExtAction(ISD::SEXTLOAD, (MVT::SimpleValueType)VT0, Expand); + setLoadExtAction(ISD::ZEXTLOAD, (MVT::SimpleValueType)VT0, Expand); + setLoadExtAction(ISD::EXTLOAD, (MVT::SimpleValueType)VT0, Expand); + } + } + + if (Subtarget->hasDSP()) { + MVT::SimpleValueType VecTys[2] = {MVT::v2i16, MVT::v4i8}; + + for (unsigned i = 0; i < array_lengthof(VecTys); ++i) { + addRegisterClass(VecTys[i], &Mips::DSPRRegClass); + + // Expand all builtin opcodes. + for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc) + setOperationAction(Opc, VecTys[i], Expand); + + setOperationAction(ISD::ADD, VecTys[i], Legal); + setOperationAction(ISD::SUB, VecTys[i], Legal); + setOperationAction(ISD::LOAD, VecTys[i], Legal); + setOperationAction(ISD::STORE, VecTys[i], Legal); + setOperationAction(ISD::BITCAST, VecTys[i], Legal); + } + + setTargetDAGCombine(ISD::SHL); + setTargetDAGCombine(ISD::SRA); + setTargetDAGCombine(ISD::SRL); + setTargetDAGCombine(ISD::SETCC); + setTargetDAGCombine(ISD::VSELECT); + } + + if (Subtarget->hasDSPR2()) + setOperationAction(ISD::MUL, MVT::v2i16, Legal); + + if (Subtarget->hasMSA()) { + addMSAIntType(MVT::v16i8, &Mips::MSA128BRegClass); + addMSAIntType(MVT::v8i16, &Mips::MSA128HRegClass); + addMSAIntType(MVT::v4i32, &Mips::MSA128WRegClass); + addMSAIntType(MVT::v2i64, &Mips::MSA128DRegClass); + addMSAFloatType(MVT::v8f16, &Mips::MSA128HRegClass); + addMSAFloatType(MVT::v4f32, &Mips::MSA128WRegClass); + addMSAFloatType(MVT::v2f64, &Mips::MSA128DRegClass); + + setTargetDAGCombine(ISD::AND); + setTargetDAGCombine(ISD::OR); + setTargetDAGCombine(ISD::SRA); + setTargetDAGCombine(ISD::VSELECT); + setTargetDAGCombine(ISD::XOR); + } + + if (!Subtarget->mipsSEUsesSoftFloat()) { + addRegisterClass(MVT::f32, &Mips::FGR32RegClass); + + // When dealing with single precision only, use libcalls + if (!Subtarget->isSingleFloat()) { + if (Subtarget->isFP64bit()) + addRegisterClass(MVT::f64, &Mips::FGR64RegClass); + else + addRegisterClass(MVT::f64, &Mips::AFGR64RegClass); + } + } + + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Custom); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Custom); + setOperationAction(ISD::MULHS, MVT::i32, Custom); + setOperationAction(ISD::MULHU, MVT::i32, Custom); + + if (HasMips64) { + setOperationAction(ISD::MULHS, MVT::i64, Custom); + setOperationAction(ISD::MULHU, MVT::i64, Custom); + setOperationAction(ISD::MUL, MVT::i64, Custom); + } + + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i64, Custom); + setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom); + + setOperationAction(ISD::SDIVREM, MVT::i32, Custom); + setOperationAction(ISD::UDIVREM, MVT::i32, Custom); + setOperationAction(ISD::SDIVREM, MVT::i64, Custom); + setOperationAction(ISD::UDIVREM, MVT::i64, Custom); + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); + setOperationAction(ISD::LOAD, MVT::i32, Custom); + setOperationAction(ISD::STORE, MVT::i32, Custom); + + setTargetDAGCombine(ISD::ADDE); + setTargetDAGCombine(ISD::SUBE); + setTargetDAGCombine(ISD::MUL); + + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); + setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); + setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); + + if (NoDPLoadStore) { + setOperationAction(ISD::LOAD, MVT::f64, Custom); + setOperationAction(ISD::STORE, MVT::f64, Custom); + } + + computeRegisterProperties(); +} + +const MipsTargetLowering * +llvm::createMipsSETargetLowering(MipsTargetMachine &TM) { + return new MipsSETargetLowering(TM); +} + +// Enable MSA support for the given integer type and Register class. +void MipsSETargetLowering:: +addMSAIntType(MVT::SimpleValueType Ty, const TargetRegisterClass *RC) { + addRegisterClass(Ty, RC); + + // Expand all builtin opcodes. + for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc) + setOperationAction(Opc, Ty, Expand); + + setOperationAction(ISD::BITCAST, Ty, Legal); + setOperationAction(ISD::LOAD, Ty, Legal); + setOperationAction(ISD::STORE, Ty, Legal); + setOperationAction(ISD::EXTRACT_VECTOR_ELT, Ty, Custom); + setOperationAction(ISD::INSERT_VECTOR_ELT, Ty, Legal); + setOperationAction(ISD::BUILD_VECTOR, Ty, Custom); + + setOperationAction(ISD::ADD, Ty, Legal); + setOperationAction(ISD::AND, Ty, Legal); + setOperationAction(ISD::CTLZ, Ty, Legal); + setOperationAction(ISD::CTPOP, Ty, Legal); + setOperationAction(ISD::MUL, Ty, Legal); + setOperationAction(ISD::OR, Ty, Legal); + setOperationAction(ISD::SDIV, Ty, Legal); + setOperationAction(ISD::SREM, Ty, Legal); + setOperationAction(ISD::SHL, Ty, Legal); + setOperationAction(ISD::SRA, Ty, Legal); + setOperationAction(ISD::SRL, Ty, Legal); + setOperationAction(ISD::SUB, Ty, Legal); + setOperationAction(ISD::UDIV, Ty, Legal); + setOperationAction(ISD::UREM, Ty, Legal); + setOperationAction(ISD::VECTOR_SHUFFLE, Ty, Custom); + setOperationAction(ISD::VSELECT, Ty, Legal); + setOperationAction(ISD::XOR, Ty, Legal); + + if (Ty == MVT::v4i32 || Ty == MVT::v2i64) { + setOperationAction(ISD::FP_TO_SINT, Ty, Legal); + setOperationAction(ISD::FP_TO_UINT, Ty, Legal); + setOperationAction(ISD::SINT_TO_FP, Ty, Legal); + setOperationAction(ISD::UINT_TO_FP, Ty, Legal); + } + + setOperationAction(ISD::SETCC, Ty, Legal); + setCondCodeAction(ISD::SETNE, Ty, Expand); + setCondCodeAction(ISD::SETGE, Ty, Expand); + setCondCodeAction(ISD::SETGT, Ty, Expand); + setCondCodeAction(ISD::SETUGE, Ty, Expand); + setCondCodeAction(ISD::SETUGT, Ty, Expand); +} + +// Enable MSA support for the given floating-point type and Register class. +void MipsSETargetLowering:: +addMSAFloatType(MVT::SimpleValueType Ty, const TargetRegisterClass *RC) { + addRegisterClass(Ty, RC); + + // Expand all builtin opcodes. + for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc) + setOperationAction(Opc, Ty, Expand); + + setOperationAction(ISD::LOAD, Ty, Legal); + setOperationAction(ISD::STORE, Ty, Legal); + setOperationAction(ISD::BITCAST, Ty, Legal); + setOperationAction(ISD::EXTRACT_VECTOR_ELT, Ty, Legal); + setOperationAction(ISD::INSERT_VECTOR_ELT, Ty, Legal); + setOperationAction(ISD::BUILD_VECTOR, Ty, Custom); + + if (Ty != MVT::v8f16) { + setOperationAction(ISD::FABS, Ty, Legal); + setOperationAction(ISD::FADD, Ty, Legal); + setOperationAction(ISD::FDIV, Ty, Legal); + setOperationAction(ISD::FEXP2, Ty, Legal); + setOperationAction(ISD::FLOG2, Ty, Legal); + setOperationAction(ISD::FMA, Ty, Legal); + setOperationAction(ISD::FMUL, Ty, Legal); + setOperationAction(ISD::FRINT, Ty, Legal); + setOperationAction(ISD::FSQRT, Ty, Legal); + setOperationAction(ISD::FSUB, Ty, Legal); + setOperationAction(ISD::VSELECT, Ty, Legal); + + setOperationAction(ISD::SETCC, Ty, Legal); + setCondCodeAction(ISD::SETOGE, Ty, Expand); + setCondCodeAction(ISD::SETOGT, Ty, Expand); + setCondCodeAction(ISD::SETUGE, Ty, Expand); + setCondCodeAction(ISD::SETUGT, Ty, Expand); + setCondCodeAction(ISD::SETGE, Ty, Expand); + setCondCodeAction(ISD::SETGT, Ty, Expand); + } +} + +bool +MipsSETargetLowering::allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const { + MVT::SimpleValueType SVT = VT.getSimpleVT().SimpleTy; + + switch (SVT) { + case MVT::i64: + case MVT::i32: + if (Fast) + *Fast = true; + return true; + default: + return false; + } +} + +SDValue MipsSETargetLowering::LowerOperation(SDValue Op, + SelectionDAG &DAG) const { + switch(Op.getOpcode()) { + case ISD::LOAD: return lowerLOAD(Op, DAG); + case ISD::STORE: return lowerSTORE(Op, DAG); + case ISD::SMUL_LOHI: return lowerMulDiv(Op, MipsISD::Mult, true, true, DAG); + case ISD::UMUL_LOHI: return lowerMulDiv(Op, MipsISD::Multu, true, true, DAG); + case ISD::MULHS: return lowerMulDiv(Op, MipsISD::Mult, false, true, DAG); + case ISD::MULHU: return lowerMulDiv(Op, MipsISD::Multu, false, true, DAG); + case ISD::MUL: return lowerMulDiv(Op, MipsISD::Mult, true, false, DAG); + case ISD::SDIVREM: return lowerMulDiv(Op, MipsISD::DivRem, true, true, DAG); + case ISD::UDIVREM: return lowerMulDiv(Op, MipsISD::DivRemU, true, true, + DAG); + case ISD::INTRINSIC_WO_CHAIN: return lowerINTRINSIC_WO_CHAIN(Op, DAG); + case ISD::INTRINSIC_W_CHAIN: return lowerINTRINSIC_W_CHAIN(Op, DAG); + case ISD::INTRINSIC_VOID: return lowerINTRINSIC_VOID(Op, DAG); + case ISD::EXTRACT_VECTOR_ELT: return lowerEXTRACT_VECTOR_ELT(Op, DAG); + case ISD::BUILD_VECTOR: return lowerBUILD_VECTOR(Op, DAG); + case ISD::VECTOR_SHUFFLE: return lowerVECTOR_SHUFFLE(Op, DAG); + } + + return MipsTargetLowering::LowerOperation(Op, DAG); +} + +// selectMADD - +// Transforms a subgraph in CurDAG if the following pattern is found: +// (addc multLo, Lo0), (adde multHi, Hi0), +// where, +// multHi/Lo: product of multiplication +// Lo0: initial value of Lo register +// Hi0: initial value of Hi register +// Return true if pattern matching was successful. +static bool selectMADD(SDNode *ADDENode, SelectionDAG *CurDAG) { + // ADDENode's second operand must be a flag output of an ADDC node in order + // for the matching to be successful. + SDNode *ADDCNode = ADDENode->getOperand(2).getNode(); + + if (ADDCNode->getOpcode() != ISD::ADDC) + return false; + + SDValue MultHi = ADDENode->getOperand(0); + SDValue MultLo = ADDCNode->getOperand(0); + SDNode *MultNode = MultHi.getNode(); + unsigned MultOpc = MultHi.getOpcode(); + + // MultHi and MultLo must be generated by the same node, + if (MultLo.getNode() != MultNode) + return false; + + // and it must be a multiplication. + if (MultOpc != ISD::SMUL_LOHI && MultOpc != ISD::UMUL_LOHI) + return false; + + // MultLo amd MultHi must be the first and second output of MultNode + // respectively. + if (MultHi.getResNo() != 1 || MultLo.getResNo() != 0) + return false; + + // Transform this to a MADD only if ADDENode and ADDCNode are the only users + // of the values of MultNode, in which case MultNode will be removed in later + // phases. + // If there exist users other than ADDENode or ADDCNode, this function returns + // here, which will result in MultNode being mapped to a single MULT + // instruction node rather than a pair of MULT and MADD instructions being + // produced. + if (!MultHi.hasOneUse() || !MultLo.hasOneUse()) + return false; + + SDLoc DL(ADDENode); + + // Initialize accumulator. + SDValue ACCIn = CurDAG->getNode(MipsISD::MTLOHI, DL, MVT::Untyped, + ADDCNode->getOperand(1), + ADDENode->getOperand(1)); + + // create MipsMAdd(u) node + MultOpc = MultOpc == ISD::UMUL_LOHI ? MipsISD::MAddu : MipsISD::MAdd; + + SDValue MAdd = CurDAG->getNode(MultOpc, DL, MVT::Untyped, + MultNode->getOperand(0),// Factor 0 + MultNode->getOperand(1),// Factor 1 + ACCIn); + + // replace uses of adde and addc here + if (!SDValue(ADDCNode, 0).use_empty()) { + SDValue LoOut = CurDAG->getNode(MipsISD::MFLO, DL, MVT::i32, MAdd); + CurDAG->ReplaceAllUsesOfValueWith(SDValue(ADDCNode, 0), LoOut); + } + if (!SDValue(ADDENode, 0).use_empty()) { + SDValue HiOut = CurDAG->getNode(MipsISD::MFHI, DL, MVT::i32, MAdd); + CurDAG->ReplaceAllUsesOfValueWith(SDValue(ADDENode, 0), HiOut); + } + + return true; +} + +// selectMSUB - +// Transforms a subgraph in CurDAG if the following pattern is found: +// (addc Lo0, multLo), (sube Hi0, multHi), +// where, +// multHi/Lo: product of multiplication +// Lo0: initial value of Lo register +// Hi0: initial value of Hi register +// Return true if pattern matching was successful. +static bool selectMSUB(SDNode *SUBENode, SelectionDAG *CurDAG) { + // SUBENode's second operand must be a flag output of an SUBC node in order + // for the matching to be successful. + SDNode *SUBCNode = SUBENode->getOperand(2).getNode(); + + if (SUBCNode->getOpcode() != ISD::SUBC) + return false; + + SDValue MultHi = SUBENode->getOperand(1); + SDValue MultLo = SUBCNode->getOperand(1); + SDNode *MultNode = MultHi.getNode(); + unsigned MultOpc = MultHi.getOpcode(); + + // MultHi and MultLo must be generated by the same node, + if (MultLo.getNode() != MultNode) + return false; + + // and it must be a multiplication. + if (MultOpc != ISD::SMUL_LOHI && MultOpc != ISD::UMUL_LOHI) + return false; + + // MultLo amd MultHi must be the first and second output of MultNode + // respectively. + if (MultHi.getResNo() != 1 || MultLo.getResNo() != 0) + return false; + + // Transform this to a MSUB only if SUBENode and SUBCNode are the only users + // of the values of MultNode, in which case MultNode will be removed in later + // phases. + // If there exist users other than SUBENode or SUBCNode, this function returns + // here, which will result in MultNode being mapped to a single MULT + // instruction node rather than a pair of MULT and MSUB instructions being + // produced. + if (!MultHi.hasOneUse() || !MultLo.hasOneUse()) + return false; + + SDLoc DL(SUBENode); + + // Initialize accumulator. + SDValue ACCIn = CurDAG->getNode(MipsISD::MTLOHI, DL, MVT::Untyped, + SUBCNode->getOperand(0), + SUBENode->getOperand(0)); + + // create MipsSub(u) node + MultOpc = MultOpc == ISD::UMUL_LOHI ? MipsISD::MSubu : MipsISD::MSub; + + SDValue MSub = CurDAG->getNode(MultOpc, DL, MVT::Glue, + MultNode->getOperand(0),// Factor 0 + MultNode->getOperand(1),// Factor 1 + ACCIn); + + // replace uses of sube and subc here + if (!SDValue(SUBCNode, 0).use_empty()) { + SDValue LoOut = CurDAG->getNode(MipsISD::MFLO, DL, MVT::i32, MSub); + CurDAG->ReplaceAllUsesOfValueWith(SDValue(SUBCNode, 0), LoOut); + } + if (!SDValue(SUBENode, 0).use_empty()) { + SDValue HiOut = CurDAG->getNode(MipsISD::MFHI, DL, MVT::i32, MSub); + CurDAG->ReplaceAllUsesOfValueWith(SDValue(SUBENode, 0), HiOut); + } + + return true; +} + +static SDValue performADDECombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget *Subtarget) { + if (DCI.isBeforeLegalize()) + return SDValue(); + + if (Subtarget->hasMips32() && N->getValueType(0) == MVT::i32 && + selectMADD(N, &DAG)) + return SDValue(N, 0); + + return SDValue(); +} + +// Fold zero extensions into MipsISD::VEXTRACT_[SZ]EXT_ELT +// +// Performs the following transformations: +// - Changes MipsISD::VEXTRACT_[SZ]EXT_ELT to zero extension if its +// sign/zero-extension is completely overwritten by the new one performed by +// the ISD::AND. +// - Removes redundant zero extensions performed by an ISD::AND. +static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget *Subtarget) { + if (!Subtarget->hasMSA()) + return SDValue(); + + SDValue Op0 = N->getOperand(0); + SDValue Op1 = N->getOperand(1); + unsigned Op0Opcode = Op0->getOpcode(); + + // (and (MipsVExtract[SZ]Ext $a, $b, $c), imm:$d) + // where $d + 1 == 2^n and n == 32 + // or $d + 1 == 2^n and n <= 32 and ZExt + // -> (MipsVExtractZExt $a, $b, $c) + if (Op0Opcode == MipsISD::VEXTRACT_SEXT_ELT || + Op0Opcode == MipsISD::VEXTRACT_ZEXT_ELT) { + ConstantSDNode *Mask = dyn_cast<ConstantSDNode>(Op1); + + if (!Mask) + return SDValue(); + + int32_t Log2IfPositive = (Mask->getAPIntValue() + 1).exactLogBase2(); + + if (Log2IfPositive <= 0) + return SDValue(); // Mask+1 is not a power of 2 + + SDValue Op0Op2 = Op0->getOperand(2); + EVT ExtendTy = cast<VTSDNode>(Op0Op2)->getVT(); + unsigned ExtendTySize = ExtendTy.getSizeInBits(); + unsigned Log2 = Log2IfPositive; + + if ((Op0Opcode == MipsISD::VEXTRACT_ZEXT_ELT && Log2 >= ExtendTySize) || + Log2 == ExtendTySize) { + SDValue Ops[] = { Op0->getOperand(0), Op0->getOperand(1), Op0Op2 }; + DAG.MorphNodeTo(Op0.getNode(), MipsISD::VEXTRACT_ZEXT_ELT, + Op0->getVTList(), Ops, Op0->getNumOperands()); + return Op0; + } + } + + return SDValue(); +} + +// Determine if the specified node is a constant vector splat. +// +// Returns true and sets Imm if: +// * N is a ISD::BUILD_VECTOR representing a constant splat +// +// This function is quite similar to MipsSEDAGToDAGISel::selectVSplat. The +// differences are that it assumes the MSA has already been checked and the +// arbitrary requirement for a maximum of 32-bit integers isn't applied (and +// must not be in order for binsri.d to be selectable). +static bool isVSplat(SDValue N, APInt &Imm, bool IsLittleEndian) { + BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N.getNode()); + + if (Node == NULL) + return false; + + APInt SplatValue, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + + if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, + 8, !IsLittleEndian)) + return false; + + Imm = SplatValue; + + return true; +} + +// Test whether the given node is an all-ones build_vector. +static bool isVectorAllOnes(SDValue N) { + // Look through bitcasts. Endianness doesn't matter because we are looking + // for an all-ones value. + if (N->getOpcode() == ISD::BITCAST) + N = N->getOperand(0); + + BuildVectorSDNode *BVN = dyn_cast<BuildVectorSDNode>(N); + + if (!BVN) + return false; + + APInt SplatValue, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + + // Endianness doesn't matter in this context because we are looking for + // an all-ones value. + if (BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs)) + return SplatValue.isAllOnesValue(); + + return false; +} + +// Test whether N is the bitwise inverse of OfNode. +static bool isBitwiseInverse(SDValue N, SDValue OfNode) { + if (N->getOpcode() != ISD::XOR) + return false; + + if (isVectorAllOnes(N->getOperand(0))) + return N->getOperand(1) == OfNode; + + if (isVectorAllOnes(N->getOperand(1))) + return N->getOperand(0) == OfNode; + + return false; +} + +// Perform combines where ISD::OR is the root node. +// +// Performs the following transformations: +// - (or (and $a, $mask), (and $b, $inv_mask)) => (vselect $mask, $a, $b) +// where $inv_mask is the bitwise inverse of $mask and the 'or' has a 128-bit +// vector type. +static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget *Subtarget) { + if (!Subtarget->hasMSA()) + return SDValue(); + + EVT Ty = N->getValueType(0); + + if (!Ty.is128BitVector()) + return SDValue(); + + SDValue Op0 = N->getOperand(0); + SDValue Op1 = N->getOperand(1); + + if (Op0->getOpcode() == ISD::AND && Op1->getOpcode() == ISD::AND) { + SDValue Op0Op0 = Op0->getOperand(0); + SDValue Op0Op1 = Op0->getOperand(1); + SDValue Op1Op0 = Op1->getOperand(0); + SDValue Op1Op1 = Op1->getOperand(1); + bool IsLittleEndian = !Subtarget->isLittle(); + + SDValue IfSet, IfClr, Cond; + bool IsConstantMask = false; + APInt Mask, InvMask; + + // If Op0Op0 is an appropriate mask, try to find it's inverse in either + // Op1Op0, or Op1Op1. Keep track of the Cond, IfSet, and IfClr nodes, while + // looking. + // IfClr will be set if we find a valid match. + if (isVSplat(Op0Op0, Mask, IsLittleEndian)) { + Cond = Op0Op0; + IfSet = Op0Op1; + + if (isVSplat(Op1Op0, InvMask, IsLittleEndian) && + Mask.getBitWidth() == InvMask.getBitWidth() && Mask == ~InvMask) + IfClr = Op1Op1; + else if (isVSplat(Op1Op1, InvMask, IsLittleEndian) && + Mask.getBitWidth() == InvMask.getBitWidth() && Mask == ~InvMask) + IfClr = Op1Op0; + + IsConstantMask = true; + } + + // If IfClr is not yet set, and Op0Op1 is an appropriate mask, try the same + // thing again using this mask. + // IfClr will be set if we find a valid match. + if (!IfClr.getNode() && isVSplat(Op0Op1, Mask, IsLittleEndian)) { + Cond = Op0Op1; + IfSet = Op0Op0; + + if (isVSplat(Op1Op0, InvMask, IsLittleEndian) && + Mask.getBitWidth() == InvMask.getBitWidth() && Mask == ~InvMask) + IfClr = Op1Op1; + else if (isVSplat(Op1Op1, InvMask, IsLittleEndian) && + Mask.getBitWidth() == InvMask.getBitWidth() && Mask == ~InvMask) + IfClr = Op1Op0; + + IsConstantMask = true; + } + + // If IfClr is not yet set, try looking for a non-constant match. + // IfClr will be set if we find a valid match amongst the eight + // possibilities. + if (!IfClr.getNode()) { + if (isBitwiseInverse(Op0Op0, Op1Op0)) { + Cond = Op1Op0; + IfSet = Op1Op1; + IfClr = Op0Op1; + } else if (isBitwiseInverse(Op0Op1, Op1Op0)) { + Cond = Op1Op0; + IfSet = Op1Op1; + IfClr = Op0Op0; + } else if (isBitwiseInverse(Op0Op0, Op1Op1)) { + Cond = Op1Op1; + IfSet = Op1Op0; + IfClr = Op0Op1; + } else if (isBitwiseInverse(Op0Op1, Op1Op1)) { + Cond = Op1Op1; + IfSet = Op1Op0; + IfClr = Op0Op0; + } else if (isBitwiseInverse(Op1Op0, Op0Op0)) { + Cond = Op0Op0; + IfSet = Op0Op1; + IfClr = Op1Op1; + } else if (isBitwiseInverse(Op1Op1, Op0Op0)) { + Cond = Op0Op0; + IfSet = Op0Op1; + IfClr = Op1Op0; + } else if (isBitwiseInverse(Op1Op0, Op0Op1)) { + Cond = Op0Op1; + IfSet = Op0Op0; + IfClr = Op1Op1; + } else if (isBitwiseInverse(Op1Op1, Op0Op1)) { + Cond = Op0Op1; + IfSet = Op0Op0; + IfClr = Op1Op0; + } + } + + // At this point, IfClr will be set if we have a valid match. + if (!IfClr.getNode()) + return SDValue(); + + assert(Cond.getNode() && IfSet.getNode()); + + // Fold degenerate cases. + if (IsConstantMask) { + if (Mask.isAllOnesValue()) + return IfSet; + else if (Mask == 0) + return IfClr; + } + + // Transform the DAG into an equivalent VSELECT. + return DAG.getNode(ISD::VSELECT, SDLoc(N), Ty, Cond, IfClr, IfSet); + } + + return SDValue(); +} + +static SDValue performSUBECombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget *Subtarget) { + if (DCI.isBeforeLegalize()) + return SDValue(); + + if (Subtarget->hasMips32() && N->getValueType(0) == MVT::i32 && + selectMSUB(N, &DAG)) + return SDValue(N, 0); + + return SDValue(); +} + +static SDValue genConstMult(SDValue X, uint64_t C, SDLoc DL, EVT VT, + EVT ShiftTy, SelectionDAG &DAG) { + // Clear the upper (64 - VT.sizeInBits) bits. + C &= ((uint64_t)-1) >> (64 - VT.getSizeInBits()); + + // Return 0. + if (C == 0) + return DAG.getConstant(0, VT); + + // Return x. + if (C == 1) + return X; + + // If c is power of 2, return (shl x, log2(c)). + if (isPowerOf2_64(C)) + return DAG.getNode(ISD::SHL, DL, VT, X, + DAG.getConstant(Log2_64(C), ShiftTy)); + + unsigned Log2Ceil = Log2_64_Ceil(C); + uint64_t Floor = 1LL << Log2_64(C); + uint64_t Ceil = Log2Ceil == 64 ? 0LL : 1LL << Log2Ceil; + + // If |c - floor_c| <= |c - ceil_c|, + // where floor_c = pow(2, floor(log2(c))) and ceil_c = pow(2, ceil(log2(c))), + // return (add constMult(x, floor_c), constMult(x, c - floor_c)). + if (C - Floor <= Ceil - C) { + SDValue Op0 = genConstMult(X, Floor, DL, VT, ShiftTy, DAG); + SDValue Op1 = genConstMult(X, C - Floor, DL, VT, ShiftTy, DAG); + return DAG.getNode(ISD::ADD, DL, VT, Op0, Op1); + } + + // If |c - floor_c| > |c - ceil_c|, + // return (sub constMult(x, ceil_c), constMult(x, ceil_c - c)). + SDValue Op0 = genConstMult(X, Ceil, DL, VT, ShiftTy, DAG); + SDValue Op1 = genConstMult(X, Ceil - C, DL, VT, ShiftTy, DAG); + return DAG.getNode(ISD::SUB, DL, VT, Op0, Op1); +} + +static SDValue performMULCombine(SDNode *N, SelectionDAG &DAG, + const TargetLowering::DAGCombinerInfo &DCI, + const MipsSETargetLowering *TL) { + EVT VT = N->getValueType(0); + + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) + if (!VT.isVector()) + return genConstMult(N->getOperand(0), C->getZExtValue(), SDLoc(N), + VT, TL->getScalarShiftAmountTy(VT), DAG); + + return SDValue(N, 0); +} + +static SDValue performDSPShiftCombine(unsigned Opc, SDNode *N, EVT Ty, + SelectionDAG &DAG, + const MipsSubtarget *Subtarget) { + // See if this is a vector splat immediate node. + APInt SplatValue, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + unsigned EltSize = Ty.getVectorElementType().getSizeInBits(); + BuildVectorSDNode *BV = dyn_cast<BuildVectorSDNode>(N->getOperand(1)); + + if (!Subtarget->hasDSP()) + return SDValue(); + + if (!BV || + !BV->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, + EltSize, !Subtarget->isLittle()) || + (SplatBitSize != EltSize) || + (SplatValue.getZExtValue() >= EltSize)) + return SDValue(); + + return DAG.getNode(Opc, SDLoc(N), Ty, N->getOperand(0), + DAG.getConstant(SplatValue.getZExtValue(), MVT::i32)); +} + +static SDValue performSHLCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget *Subtarget) { + EVT Ty = N->getValueType(0); + + if ((Ty != MVT::v2i16) && (Ty != MVT::v4i8)) + return SDValue(); + + return performDSPShiftCombine(MipsISD::SHLL_DSP, N, Ty, DAG, Subtarget); +} + +// Fold sign-extensions into MipsISD::VEXTRACT_[SZ]EXT_ELT for MSA and fold +// constant splats into MipsISD::SHRA_DSP for DSPr2. +// +// Performs the following transformations: +// - Changes MipsISD::VEXTRACT_[SZ]EXT_ELT to sign extension if its +// sign/zero-extension is completely overwritten by the new one performed by +// the ISD::SRA and ISD::SHL nodes. +// - Removes redundant sign extensions performed by an ISD::SRA and ISD::SHL +// sequence. +// +// See performDSPShiftCombine for more information about the transformation +// used for DSPr2. +static SDValue performSRACombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget *Subtarget) { + EVT Ty = N->getValueType(0); + + if (Subtarget->hasMSA()) { + SDValue Op0 = N->getOperand(0); + SDValue Op1 = N->getOperand(1); + + // (sra (shl (MipsVExtract[SZ]Ext $a, $b, $c), imm:$d), imm:$d) + // where $d + sizeof($c) == 32 + // or $d + sizeof($c) <= 32 and SExt + // -> (MipsVExtractSExt $a, $b, $c) + if (Op0->getOpcode() == ISD::SHL && Op1 == Op0->getOperand(1)) { + SDValue Op0Op0 = Op0->getOperand(0); + ConstantSDNode *ShAmount = dyn_cast<ConstantSDNode>(Op1); + + if (!ShAmount) + return SDValue(); + + if (Op0Op0->getOpcode() != MipsISD::VEXTRACT_SEXT_ELT && + Op0Op0->getOpcode() != MipsISD::VEXTRACT_ZEXT_ELT) + return SDValue(); + + EVT ExtendTy = cast<VTSDNode>(Op0Op0->getOperand(2))->getVT(); + unsigned TotalBits = ShAmount->getZExtValue() + ExtendTy.getSizeInBits(); + + if (TotalBits == 32 || + (Op0Op0->getOpcode() == MipsISD::VEXTRACT_SEXT_ELT && + TotalBits <= 32)) { + SDValue Ops[] = { Op0Op0->getOperand(0), Op0Op0->getOperand(1), + Op0Op0->getOperand(2) }; + DAG.MorphNodeTo(Op0Op0.getNode(), MipsISD::VEXTRACT_SEXT_ELT, + Op0Op0->getVTList(), Ops, Op0Op0->getNumOperands()); + return Op0Op0; + } + } + } + + if ((Ty != MVT::v2i16) && ((Ty != MVT::v4i8) || !Subtarget->hasDSPR2())) + return SDValue(); + + return performDSPShiftCombine(MipsISD::SHRA_DSP, N, Ty, DAG, Subtarget); +} + + +static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG, + TargetLowering::DAGCombinerInfo &DCI, + const MipsSubtarget *Subtarget) { + EVT Ty = N->getValueType(0); + + if (((Ty != MVT::v2i16) || !Subtarget->hasDSPR2()) && (Ty != MVT::v4i8)) + return SDValue(); + + return performDSPShiftCombine(MipsISD::SHRL_DSP, N, Ty, DAG, Subtarget); +} + +static bool isLegalDSPCondCode(EVT Ty, ISD::CondCode CC) { + bool IsV216 = (Ty == MVT::v2i16); + + switch (CC) { + case ISD::SETEQ: + case ISD::SETNE: return true; + case ISD::SETLT: + case ISD::SETLE: + case ISD::SETGT: + case ISD::SETGE: return IsV216; + case ISD::SETULT: + case ISD::SETULE: + case ISD::SETUGT: + case ISD::SETUGE: return !IsV216; + default: return false; + } +} + +static SDValue performSETCCCombine(SDNode *N, SelectionDAG &DAG) { + EVT Ty = N->getValueType(0); + + if ((Ty != MVT::v2i16) && (Ty != MVT::v4i8)) + return SDValue(); + + if (!isLegalDSPCondCode(Ty, cast<CondCodeSDNode>(N->getOperand(2))->get())) + return SDValue(); + + return DAG.getNode(MipsISD::SETCC_DSP, SDLoc(N), Ty, N->getOperand(0), + N->getOperand(1), N->getOperand(2)); +} + +static SDValue performVSELECTCombine(SDNode *N, SelectionDAG &DAG) { + EVT Ty = N->getValueType(0); + + if (Ty.is128BitVector() && Ty.isInteger()) { + // Try the following combines: + // (vselect (setcc $a, $b, SETLT), $b, $a)) -> (vsmax $a, $b) + // (vselect (setcc $a, $b, SETLE), $b, $a)) -> (vsmax $a, $b) + // (vselect (setcc $a, $b, SETLT), $a, $b)) -> (vsmin $a, $b) + // (vselect (setcc $a, $b, SETLE), $a, $b)) -> (vsmin $a, $b) + // (vselect (setcc $a, $b, SETULT), $b, $a)) -> (vumax $a, $b) + // (vselect (setcc $a, $b, SETULE), $b, $a)) -> (vumax $a, $b) + // (vselect (setcc $a, $b, SETULT), $a, $b)) -> (vumin $a, $b) + // (vselect (setcc $a, $b, SETULE), $a, $b)) -> (vumin $a, $b) + // SETGT/SETGE/SETUGT/SETUGE variants of these will show up initially but + // will be expanded to equivalent SETLT/SETLE/SETULT/SETULE versions by the + // legalizer. + SDValue Op0 = N->getOperand(0); + + if (Op0->getOpcode() != ISD::SETCC) + return SDValue(); + + ISD::CondCode CondCode = cast<CondCodeSDNode>(Op0->getOperand(2))->get(); + bool Signed; + + if (CondCode == ISD::SETLT || CondCode == ISD::SETLE) + Signed = true; + else if (CondCode == ISD::SETULT || CondCode == ISD::SETULE) + Signed = false; + else + return SDValue(); + + SDValue Op1 = N->getOperand(1); + SDValue Op2 = N->getOperand(2); + SDValue Op0Op0 = Op0->getOperand(0); + SDValue Op0Op1 = Op0->getOperand(1); + + if (Op1 == Op0Op0 && Op2 == Op0Op1) + return DAG.getNode(Signed ? MipsISD::VSMIN : MipsISD::VUMIN, SDLoc(N), + Ty, Op1, Op2); + else if (Op1 == Op0Op1 && Op2 == Op0Op0) + return DAG.getNode(Signed ? MipsISD::VSMAX : MipsISD::VUMAX, SDLoc(N), + Ty, Op1, Op2); + } else if ((Ty == MVT::v2i16) || (Ty == MVT::v4i8)) { + SDValue SetCC = N->getOperand(0); + + if (SetCC.getOpcode() != MipsISD::SETCC_DSP) + return SDValue(); + + return DAG.getNode(MipsISD::SELECT_CC_DSP, SDLoc(N), Ty, + SetCC.getOperand(0), SetCC.getOperand(1), + N->getOperand(1), N->getOperand(2), SetCC.getOperand(2)); + } + + return SDValue(); +} + +static SDValue performXORCombine(SDNode *N, SelectionDAG &DAG, + const MipsSubtarget *Subtarget) { + EVT Ty = N->getValueType(0); + + if (Subtarget->hasMSA() && Ty.is128BitVector() && Ty.isInteger()) { + // Try the following combines: + // (xor (or $a, $b), (build_vector allones)) + // (xor (or $a, $b), (bitcast (build_vector allones))) + SDValue Op0 = N->getOperand(0); + SDValue Op1 = N->getOperand(1); + SDValue NotOp; + + if (ISD::isBuildVectorAllOnes(Op0.getNode())) + NotOp = Op1; + else if (ISD::isBuildVectorAllOnes(Op1.getNode())) + NotOp = Op0; + else + return SDValue(); + + if (NotOp->getOpcode() == ISD::OR) + return DAG.getNode(MipsISD::VNOR, SDLoc(N), Ty, NotOp->getOperand(0), + NotOp->getOperand(1)); + } + + return SDValue(); +} + +SDValue +MipsSETargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { + SelectionDAG &DAG = DCI.DAG; + SDValue Val; + + switch (N->getOpcode()) { + case ISD::ADDE: + return performADDECombine(N, DAG, DCI, Subtarget); + case ISD::AND: + Val = performANDCombine(N, DAG, DCI, Subtarget); + break; + case ISD::OR: + Val = performORCombine(N, DAG, DCI, Subtarget); + break; + case ISD::SUBE: + return performSUBECombine(N, DAG, DCI, Subtarget); + case ISD::MUL: + return performMULCombine(N, DAG, DCI, this); + case ISD::SHL: + return performSHLCombine(N, DAG, DCI, Subtarget); + case ISD::SRA: + return performSRACombine(N, DAG, DCI, Subtarget); + case ISD::SRL: + return performSRLCombine(N, DAG, DCI, Subtarget); + case ISD::VSELECT: + return performVSELECTCombine(N, DAG); + case ISD::XOR: + Val = performXORCombine(N, DAG, Subtarget); + break; + case ISD::SETCC: + Val = performSETCCCombine(N, DAG); + break; + } + + if (Val.getNode()) { + DEBUG(dbgs() << "\nMipsSE DAG Combine:\n"; + N->printrWithDepth(dbgs(), &DAG); + dbgs() << "\n=> \n"; + Val.getNode()->printrWithDepth(dbgs(), &DAG); + dbgs() << "\n"); + return Val; + } + + return MipsTargetLowering::PerformDAGCombine(N, DCI); +} + +MachineBasicBlock * +MipsSETargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + switch (MI->getOpcode()) { + default: + return MipsTargetLowering::EmitInstrWithCustomInserter(MI, BB); + case Mips::BPOSGE32_PSEUDO: + return emitBPOSGE32(MI, BB); + case Mips::SNZ_B_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BNZ_B); + case Mips::SNZ_H_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BNZ_H); + case Mips::SNZ_W_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BNZ_W); + case Mips::SNZ_D_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BNZ_D); + case Mips::SNZ_V_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BNZ_V); + case Mips::SZ_B_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BZ_B); + case Mips::SZ_H_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BZ_H); + case Mips::SZ_W_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BZ_W); + case Mips::SZ_D_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BZ_D); + case Mips::SZ_V_PSEUDO: + return emitMSACBranchPseudo(MI, BB, Mips::BZ_V); + case Mips::COPY_FW_PSEUDO: + return emitCOPY_FW(MI, BB); + case Mips::COPY_FD_PSEUDO: + return emitCOPY_FD(MI, BB); + case Mips::INSERT_FW_PSEUDO: + return emitINSERT_FW(MI, BB); + case Mips::INSERT_FD_PSEUDO: + return emitINSERT_FD(MI, BB); + case Mips::FILL_FW_PSEUDO: + return emitFILL_FW(MI, BB); + case Mips::FILL_FD_PSEUDO: + return emitFILL_FD(MI, BB); + case Mips::FEXP2_W_1_PSEUDO: + return emitFEXP2_W_1(MI, BB); + case Mips::FEXP2_D_1_PSEUDO: + return emitFEXP2_D_1(MI, BB); + } +} + +bool MipsSETargetLowering:: +isEligibleForTailCallOptimization(const MipsCC &MipsCCInfo, + unsigned NextStackOffset, + const MipsFunctionInfo& FI) const { + if (!EnableMipsTailCalls) + return false; + + // Return false if either the callee or caller has a byval argument. + if (MipsCCInfo.hasByValArg() || FI.hasByvalArg()) + return false; + + // Return true if the callee's argument area is no larger than the + // caller's. + return NextStackOffset <= FI.getIncomingArgSize(); +} + +void MipsSETargetLowering:: +getOpndList(SmallVectorImpl<SDValue> &Ops, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage, + CallLoweringInfo &CLI, SDValue Callee, SDValue Chain) const { + // T9 should contain the address of the callee function if + // -reloction-model=pic or it is an indirect call. + if (IsPICCall || !GlobalOrExternal) { + unsigned T9Reg = IsN64 ? Mips::T9_64 : Mips::T9; + RegsToPass.push_front(std::make_pair(T9Reg, Callee)); + } else + Ops.push_back(Callee); + + MipsTargetLowering::getOpndList(Ops, RegsToPass, IsPICCall, GlobalOrExternal, + InternalLinkage, CLI, Callee, Chain); +} + +SDValue MipsSETargetLowering::lowerLOAD(SDValue Op, SelectionDAG &DAG) const { + LoadSDNode &Nd = *cast<LoadSDNode>(Op); + + if (Nd.getMemoryVT() != MVT::f64 || !NoDPLoadStore) + return MipsTargetLowering::lowerLOAD(Op, DAG); + + // Replace a double precision load with two i32 loads and a buildpair64. + SDLoc DL(Op); + SDValue Ptr = Nd.getBasePtr(), Chain = Nd.getChain(); + EVT PtrVT = Ptr.getValueType(); + + // i32 load from lower address. + SDValue Lo = DAG.getLoad(MVT::i32, DL, Chain, Ptr, + MachinePointerInfo(), Nd.isVolatile(), + Nd.isNonTemporal(), Nd.isInvariant(), + Nd.getAlignment()); + + // i32 load from higher address. + Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Ptr, DAG.getConstant(4, PtrVT)); + SDValue Hi = DAG.getLoad(MVT::i32, DL, Lo.getValue(1), Ptr, + MachinePointerInfo(), Nd.isVolatile(), + Nd.isNonTemporal(), Nd.isInvariant(), + std::min(Nd.getAlignment(), 4U)); + + if (!Subtarget->isLittle()) + std::swap(Lo, Hi); + + SDValue BP = DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, Lo, Hi); + SDValue Ops[2] = {BP, Hi.getValue(1)}; + return DAG.getMergeValues(Ops, 2, DL); +} + +SDValue MipsSETargetLowering::lowerSTORE(SDValue Op, SelectionDAG &DAG) const { + StoreSDNode &Nd = *cast<StoreSDNode>(Op); + + if (Nd.getMemoryVT() != MVT::f64 || !NoDPLoadStore) + return MipsTargetLowering::lowerSTORE(Op, DAG); + + // Replace a double precision store with two extractelement64s and i32 stores. + SDLoc DL(Op); + SDValue Val = Nd.getValue(), Ptr = Nd.getBasePtr(), Chain = Nd.getChain(); + EVT PtrVT = Ptr.getValueType(); + SDValue Lo = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Val, DAG.getConstant(0, MVT::i32)); + SDValue Hi = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, + Val, DAG.getConstant(1, MVT::i32)); + + if (!Subtarget->isLittle()) + std::swap(Lo, Hi); + + // i32 store to lower address. + Chain = DAG.getStore(Chain, DL, Lo, Ptr, MachinePointerInfo(), + Nd.isVolatile(), Nd.isNonTemporal(), Nd.getAlignment(), + Nd.getTBAAInfo()); + + // i32 store to higher address. + Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Ptr, DAG.getConstant(4, PtrVT)); + return DAG.getStore(Chain, DL, Hi, Ptr, MachinePointerInfo(), + Nd.isVolatile(), Nd.isNonTemporal(), + std::min(Nd.getAlignment(), 4U), Nd.getTBAAInfo()); +} + +SDValue MipsSETargetLowering::lowerMulDiv(SDValue Op, unsigned NewOpc, + bool HasLo, bool HasHi, + SelectionDAG &DAG) const { + EVT Ty = Op.getOperand(0).getValueType(); + SDLoc DL(Op); + SDValue Mult = DAG.getNode(NewOpc, DL, MVT::Untyped, + Op.getOperand(0), Op.getOperand(1)); + SDValue Lo, Hi; + + if (HasLo) + Lo = DAG.getNode(MipsISD::MFLO, DL, Ty, Mult); + if (HasHi) + Hi = DAG.getNode(MipsISD::MFHI, DL, Ty, Mult); + + if (!HasLo || !HasHi) + return HasLo ? Lo : Hi; + + SDValue Vals[] = { Lo, Hi }; + return DAG.getMergeValues(Vals, 2, DL); +} + + +static SDValue initAccumulator(SDValue In, SDLoc DL, SelectionDAG &DAG) { + SDValue InLo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, In, + DAG.getConstant(0, MVT::i32)); + SDValue InHi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, In, + DAG.getConstant(1, MVT::i32)); + return DAG.getNode(MipsISD::MTLOHI, DL, MVT::Untyped, InLo, InHi); +} + +static SDValue extractLOHI(SDValue Op, SDLoc DL, SelectionDAG &DAG) { + SDValue Lo = DAG.getNode(MipsISD::MFLO, DL, MVT::i32, Op); + SDValue Hi = DAG.getNode(MipsISD::MFHI, DL, MVT::i32, Op); + return DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Lo, Hi); +} + +// This function expands mips intrinsic nodes which have 64-bit input operands +// or output values. +// +// out64 = intrinsic-node in64 +// => +// lo = copy (extract-element (in64, 0)) +// hi = copy (extract-element (in64, 1)) +// mips-specific-node +// v0 = copy lo +// v1 = copy hi +// out64 = merge-values (v0, v1) +// +static SDValue lowerDSPIntr(SDValue Op, SelectionDAG &DAG, unsigned Opc) { + SDLoc DL(Op); + bool HasChainIn = Op->getOperand(0).getValueType() == MVT::Other; + SmallVector<SDValue, 3> Ops; + unsigned OpNo = 0; + + // See if Op has a chain input. + if (HasChainIn) + Ops.push_back(Op->getOperand(OpNo++)); + + // The next operand is the intrinsic opcode. + assert(Op->getOperand(OpNo).getOpcode() == ISD::TargetConstant); + + // See if the next operand has type i64. + SDValue Opnd = Op->getOperand(++OpNo), In64; + + if (Opnd.getValueType() == MVT::i64) + In64 = initAccumulator(Opnd, DL, DAG); + else + Ops.push_back(Opnd); + + // Push the remaining operands. + for (++OpNo ; OpNo < Op->getNumOperands(); ++OpNo) + Ops.push_back(Op->getOperand(OpNo)); + + // Add In64 to the end of the list. + if (In64.getNode()) + Ops.push_back(In64); + + // Scan output. + SmallVector<EVT, 2> ResTys; + + for (SDNode::value_iterator I = Op->value_begin(), E = Op->value_end(); + I != E; ++I) + ResTys.push_back((*I == MVT::i64) ? MVT::Untyped : *I); + + // Create node. + SDValue Val = DAG.getNode(Opc, DL, ResTys, &Ops[0], Ops.size()); + SDValue Out = (ResTys[0] == MVT::Untyped) ? extractLOHI(Val, DL, DAG) : Val; + + if (!HasChainIn) + return Out; + + assert(Val->getValueType(1) == MVT::Other); + SDValue Vals[] = { Out, SDValue(Val.getNode(), 1) }; + return DAG.getMergeValues(Vals, 2, DL); +} + +// Lower an MSA copy intrinsic into the specified SelectionDAG node +static SDValue lowerMSACopyIntr(SDValue Op, SelectionDAG &DAG, unsigned Opc) { + SDLoc DL(Op); + SDValue Vec = Op->getOperand(1); + SDValue Idx = Op->getOperand(2); + EVT ResTy = Op->getValueType(0); + EVT EltTy = Vec->getValueType(0).getVectorElementType(); + + SDValue Result = DAG.getNode(Opc, DL, ResTy, Vec, Idx, + DAG.getValueType(EltTy)); + + return Result; +} + +static SDValue lowerMSASplatZExt(SDValue Op, unsigned OpNr, SelectionDAG &DAG) { + EVT ResVecTy = Op->getValueType(0); + EVT ViaVecTy = ResVecTy; + SDLoc DL(Op); + + // When ResVecTy == MVT::v2i64, LaneA is the upper 32 bits of the lane and + // LaneB is the lower 32-bits. Otherwise LaneA and LaneB are alternating + // lanes. + SDValue LaneA; + SDValue LaneB = Op->getOperand(2); + + if (ResVecTy == MVT::v2i64) { + LaneA = DAG.getConstant(0, MVT::i32); + ViaVecTy = MVT::v4i32; + } else + LaneA = LaneB; + + SDValue Ops[16] = { LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, + LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, LaneA, LaneB }; + + SDValue Result = DAG.getNode(ISD::BUILD_VECTOR, DL, ViaVecTy, Ops, + ViaVecTy.getVectorNumElements()); + + if (ViaVecTy != ResVecTy) + Result = DAG.getNode(ISD::BITCAST, DL, ResVecTy, Result); + + return Result; +} + +static SDValue lowerMSASplatImm(SDValue Op, unsigned ImmOp, SelectionDAG &DAG) { + return DAG.getConstant(Op->getConstantOperandVal(ImmOp), Op->getValueType(0)); +} + +static SDValue getBuildVectorSplat(EVT VecTy, SDValue SplatValue, + bool BigEndian, SelectionDAG &DAG) { + EVT ViaVecTy = VecTy; + SDValue SplatValueA = SplatValue; + SDValue SplatValueB = SplatValue; + SDLoc DL(SplatValue); + + if (VecTy == MVT::v2i64) { + // v2i64 BUILD_VECTOR must be performed via v4i32 so split into i32's. + ViaVecTy = MVT::v4i32; + + SplatValueA = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, SplatValue); + SplatValueB = DAG.getNode(ISD::SRL, DL, MVT::i64, SplatValue, + DAG.getConstant(32, MVT::i32)); + SplatValueB = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, SplatValueB); + } + + // We currently hold the parts in little endian order. Swap them if + // necessary. + if (BigEndian) + std::swap(SplatValueA, SplatValueB); + + SDValue Ops[16] = { SplatValueA, SplatValueB, SplatValueA, SplatValueB, + SplatValueA, SplatValueB, SplatValueA, SplatValueB, + SplatValueA, SplatValueB, SplatValueA, SplatValueB, + SplatValueA, SplatValueB, SplatValueA, SplatValueB }; + + SDValue Result = DAG.getNode(ISD::BUILD_VECTOR, DL, ViaVecTy, Ops, + ViaVecTy.getVectorNumElements()); + + if (VecTy != ViaVecTy) + Result = DAG.getNode(ISD::BITCAST, DL, VecTy, Result); + + return Result; +} + +static SDValue lowerMSABinaryBitImmIntr(SDValue Op, SelectionDAG &DAG, + unsigned Opc, SDValue Imm, + bool BigEndian) { + EVT VecTy = Op->getValueType(0); + SDValue Exp2Imm; + SDLoc DL(Op); + + // The DAG Combiner can't constant fold bitcasted vectors yet so we must do it + // here for now. + if (VecTy == MVT::v2i64) { + if (ConstantSDNode *CImm = dyn_cast<ConstantSDNode>(Imm)) { + APInt BitImm = APInt(64, 1) << CImm->getAPIntValue(); + + SDValue BitImmHiOp = DAG.getConstant(BitImm.lshr(32).trunc(32), MVT::i32); + SDValue BitImmLoOp = DAG.getConstant(BitImm.trunc(32), MVT::i32); + + if (BigEndian) + std::swap(BitImmLoOp, BitImmHiOp); + + Exp2Imm = + DAG.getNode(ISD::BITCAST, DL, MVT::v2i64, + DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v4i32, BitImmLoOp, + BitImmHiOp, BitImmLoOp, BitImmHiOp)); + } + } + + if (Exp2Imm.getNode() == NULL) { + // We couldnt constant fold, do a vector shift instead + + // Extend i32 to i64 if necessary. Sign or zero extend doesn't matter since + // only values 0-63 are valid. + if (VecTy == MVT::v2i64) + Imm = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, Imm); + + Exp2Imm = getBuildVectorSplat(VecTy, Imm, BigEndian, DAG); + + Exp2Imm = + DAG.getNode(ISD::SHL, DL, VecTy, DAG.getConstant(1, VecTy), Exp2Imm); + } + + return DAG.getNode(Opc, DL, VecTy, Op->getOperand(1), Exp2Imm); +} + +static SDValue lowerMSABitClear(SDValue Op, SelectionDAG &DAG) { + EVT ResTy = Op->getValueType(0); + SDLoc DL(Op); + SDValue One = DAG.getConstant(1, ResTy); + SDValue Bit = DAG.getNode(ISD::SHL, DL, ResTy, One, Op->getOperand(2)); + + return DAG.getNode(ISD::AND, DL, ResTy, Op->getOperand(1), + DAG.getNOT(DL, Bit, ResTy)); +} + +static SDValue lowerMSABitClearImm(SDValue Op, SelectionDAG &DAG) { + SDLoc DL(Op); + EVT ResTy = Op->getValueType(0); + APInt BitImm = APInt(ResTy.getVectorElementType().getSizeInBits(), 1) + << cast<ConstantSDNode>(Op->getOperand(2))->getAPIntValue(); + SDValue BitMask = DAG.getConstant(~BitImm, ResTy); + + return DAG.getNode(ISD::AND, DL, ResTy, Op->getOperand(1), BitMask); +} + +SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + + switch (cast<ConstantSDNode>(Op->getOperand(0))->getZExtValue()) { + default: + return SDValue(); + case Intrinsic::mips_shilo: + return lowerDSPIntr(Op, DAG, MipsISD::SHILO); + case Intrinsic::mips_dpau_h_qbl: + return lowerDSPIntr(Op, DAG, MipsISD::DPAU_H_QBL); + case Intrinsic::mips_dpau_h_qbr: + return lowerDSPIntr(Op, DAG, MipsISD::DPAU_H_QBR); + case Intrinsic::mips_dpsu_h_qbl: + return lowerDSPIntr(Op, DAG, MipsISD::DPSU_H_QBL); + case Intrinsic::mips_dpsu_h_qbr: + return lowerDSPIntr(Op, DAG, MipsISD::DPSU_H_QBR); + case Intrinsic::mips_dpa_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPA_W_PH); + case Intrinsic::mips_dps_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPS_W_PH); + case Intrinsic::mips_dpax_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPAX_W_PH); + case Intrinsic::mips_dpsx_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPSX_W_PH); + case Intrinsic::mips_mulsa_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::MULSA_W_PH); + case Intrinsic::mips_mult: + return lowerDSPIntr(Op, DAG, MipsISD::Mult); + case Intrinsic::mips_multu: + return lowerDSPIntr(Op, DAG, MipsISD::Multu); + case Intrinsic::mips_madd: + return lowerDSPIntr(Op, DAG, MipsISD::MAdd); + case Intrinsic::mips_maddu: + return lowerDSPIntr(Op, DAG, MipsISD::MAddu); + case Intrinsic::mips_msub: + return lowerDSPIntr(Op, DAG, MipsISD::MSub); + case Intrinsic::mips_msubu: + return lowerDSPIntr(Op, DAG, MipsISD::MSubu); + case Intrinsic::mips_addv_b: + case Intrinsic::mips_addv_h: + case Intrinsic::mips_addv_w: + case Intrinsic::mips_addv_d: + return DAG.getNode(ISD::ADD, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_addvi_b: + case Intrinsic::mips_addvi_h: + case Intrinsic::mips_addvi_w: + case Intrinsic::mips_addvi_d: + return DAG.getNode(ISD::ADD, DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_and_v: + return DAG.getNode(ISD::AND, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_andi_b: + return DAG.getNode(ISD::AND, DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_bclr_b: + case Intrinsic::mips_bclr_h: + case Intrinsic::mips_bclr_w: + case Intrinsic::mips_bclr_d: + return lowerMSABitClear(Op, DAG); + case Intrinsic::mips_bclri_b: + case Intrinsic::mips_bclri_h: + case Intrinsic::mips_bclri_w: + case Intrinsic::mips_bclri_d: + return lowerMSABitClearImm(Op, DAG); + case Intrinsic::mips_binsli_b: + case Intrinsic::mips_binsli_h: + case Intrinsic::mips_binsli_w: + case Intrinsic::mips_binsli_d: { + EVT VecTy = Op->getValueType(0); + EVT EltTy = VecTy.getVectorElementType(); + APInt Mask = APInt::getHighBitsSet(EltTy.getSizeInBits(), + Op->getConstantOperandVal(3)); + return DAG.getNode(ISD::VSELECT, DL, VecTy, + DAG.getConstant(Mask, VecTy, true), Op->getOperand(1), + Op->getOperand(2)); + } + case Intrinsic::mips_binsri_b: + case Intrinsic::mips_binsri_h: + case Intrinsic::mips_binsri_w: + case Intrinsic::mips_binsri_d: { + EVT VecTy = Op->getValueType(0); + EVT EltTy = VecTy.getVectorElementType(); + APInt Mask = APInt::getLowBitsSet(EltTy.getSizeInBits(), + Op->getConstantOperandVal(3)); + return DAG.getNode(ISD::VSELECT, DL, VecTy, + DAG.getConstant(Mask, VecTy, true), Op->getOperand(1), + Op->getOperand(2)); + } + case Intrinsic::mips_bmnz_v: + return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), Op->getOperand(3), + Op->getOperand(2), Op->getOperand(1)); + case Intrinsic::mips_bmnzi_b: + return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), + lowerMSASplatImm(Op, 3, DAG), Op->getOperand(2), + Op->getOperand(1)); + case Intrinsic::mips_bmz_v: + return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), Op->getOperand(3), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_bmzi_b: + return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), + lowerMSASplatImm(Op, 3, DAG), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_bneg_b: + case Intrinsic::mips_bneg_h: + case Intrinsic::mips_bneg_w: + case Intrinsic::mips_bneg_d: { + EVT VecTy = Op->getValueType(0); + SDValue One = DAG.getConstant(1, VecTy); + + return DAG.getNode(ISD::XOR, DL, VecTy, Op->getOperand(1), + DAG.getNode(ISD::SHL, DL, VecTy, One, + Op->getOperand(2))); + } + case Intrinsic::mips_bnegi_b: + case Intrinsic::mips_bnegi_h: + case Intrinsic::mips_bnegi_w: + case Intrinsic::mips_bnegi_d: + return lowerMSABinaryBitImmIntr(Op, DAG, ISD::XOR, Op->getOperand(2), + !Subtarget->isLittle()); + case Intrinsic::mips_bnz_b: + case Intrinsic::mips_bnz_h: + case Intrinsic::mips_bnz_w: + case Intrinsic::mips_bnz_d: + return DAG.getNode(MipsISD::VALL_NONZERO, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_bnz_v: + return DAG.getNode(MipsISD::VANY_NONZERO, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_bsel_v: + return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2), + Op->getOperand(3)); + case Intrinsic::mips_bseli_b: + return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2), + lowerMSASplatImm(Op, 3, DAG)); + case Intrinsic::mips_bset_b: + case Intrinsic::mips_bset_h: + case Intrinsic::mips_bset_w: + case Intrinsic::mips_bset_d: { + EVT VecTy = Op->getValueType(0); + SDValue One = DAG.getConstant(1, VecTy); + + return DAG.getNode(ISD::OR, DL, VecTy, Op->getOperand(1), + DAG.getNode(ISD::SHL, DL, VecTy, One, + Op->getOperand(2))); + } + case Intrinsic::mips_bseti_b: + case Intrinsic::mips_bseti_h: + case Intrinsic::mips_bseti_w: + case Intrinsic::mips_bseti_d: + return lowerMSABinaryBitImmIntr(Op, DAG, ISD::OR, Op->getOperand(2), + !Subtarget->isLittle()); + case Intrinsic::mips_bz_b: + case Intrinsic::mips_bz_h: + case Intrinsic::mips_bz_w: + case Intrinsic::mips_bz_d: + return DAG.getNode(MipsISD::VALL_ZERO, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_bz_v: + return DAG.getNode(MipsISD::VANY_ZERO, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_ceq_b: + case Intrinsic::mips_ceq_h: + case Intrinsic::mips_ceq_w: + case Intrinsic::mips_ceq_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETEQ); + case Intrinsic::mips_ceqi_b: + case Intrinsic::mips_ceqi_h: + case Intrinsic::mips_ceqi_w: + case Intrinsic::mips_ceqi_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG), ISD::SETEQ); + case Intrinsic::mips_cle_s_b: + case Intrinsic::mips_cle_s_h: + case Intrinsic::mips_cle_s_w: + case Intrinsic::mips_cle_s_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETLE); + case Intrinsic::mips_clei_s_b: + case Intrinsic::mips_clei_s_h: + case Intrinsic::mips_clei_s_w: + case Intrinsic::mips_clei_s_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG), ISD::SETLE); + case Intrinsic::mips_cle_u_b: + case Intrinsic::mips_cle_u_h: + case Intrinsic::mips_cle_u_w: + case Intrinsic::mips_cle_u_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETULE); + case Intrinsic::mips_clei_u_b: + case Intrinsic::mips_clei_u_h: + case Intrinsic::mips_clei_u_w: + case Intrinsic::mips_clei_u_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG), ISD::SETULE); + case Intrinsic::mips_clt_s_b: + case Intrinsic::mips_clt_s_h: + case Intrinsic::mips_clt_s_w: + case Intrinsic::mips_clt_s_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETLT); + case Intrinsic::mips_clti_s_b: + case Intrinsic::mips_clti_s_h: + case Intrinsic::mips_clti_s_w: + case Intrinsic::mips_clti_s_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG), ISD::SETLT); + case Intrinsic::mips_clt_u_b: + case Intrinsic::mips_clt_u_h: + case Intrinsic::mips_clt_u_w: + case Intrinsic::mips_clt_u_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETULT); + case Intrinsic::mips_clti_u_b: + case Intrinsic::mips_clti_u_h: + case Intrinsic::mips_clti_u_w: + case Intrinsic::mips_clti_u_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG), ISD::SETULT); + case Intrinsic::mips_copy_s_b: + case Intrinsic::mips_copy_s_h: + case Intrinsic::mips_copy_s_w: + return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_SEXT_ELT); + case Intrinsic::mips_copy_s_d: + // Don't lower directly into VEXTRACT_SEXT_ELT since i64 might be illegal. + // Instead lower to the generic EXTRACT_VECTOR_ELT node and let the type + // legalizer and EXTRACT_VECTOR_ELT lowering sort it out. + return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SDLoc(Op), Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_copy_u_b: + case Intrinsic::mips_copy_u_h: + case Intrinsic::mips_copy_u_w: + return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_ZEXT_ELT); + case Intrinsic::mips_copy_u_d: + // Don't lower directly into VEXTRACT_ZEXT_ELT since i64 might be illegal. + // Instead lower to the generic EXTRACT_VECTOR_ELT node and let the type + // legalizer and EXTRACT_VECTOR_ELT lowering sort it out. + // + // Note: When i64 is illegal, this results in copy_s.w instructions instead + // of copy_u.w instructions. This makes no difference to the behaviour + // since i64 is only illegal when the register file is 32-bit. + return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SDLoc(Op), Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_div_s_b: + case Intrinsic::mips_div_s_h: + case Intrinsic::mips_div_s_w: + case Intrinsic::mips_div_s_d: + return DAG.getNode(ISD::SDIV, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_div_u_b: + case Intrinsic::mips_div_u_h: + case Intrinsic::mips_div_u_w: + case Intrinsic::mips_div_u_d: + return DAG.getNode(ISD::UDIV, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_fadd_w: + case Intrinsic::mips_fadd_d: + return DAG.getNode(ISD::FADD, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + // Don't lower mips_fcaf_[wd] since LLVM folds SETFALSE condcodes away + case Intrinsic::mips_fceq_w: + case Intrinsic::mips_fceq_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETOEQ); + case Intrinsic::mips_fcle_w: + case Intrinsic::mips_fcle_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETOLE); + case Intrinsic::mips_fclt_w: + case Intrinsic::mips_fclt_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETOLT); + case Intrinsic::mips_fcne_w: + case Intrinsic::mips_fcne_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETONE); + case Intrinsic::mips_fcor_w: + case Intrinsic::mips_fcor_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETO); + case Intrinsic::mips_fcueq_w: + case Intrinsic::mips_fcueq_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETUEQ); + case Intrinsic::mips_fcule_w: + case Intrinsic::mips_fcule_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETULE); + case Intrinsic::mips_fcult_w: + case Intrinsic::mips_fcult_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETULT); + case Intrinsic::mips_fcun_w: + case Intrinsic::mips_fcun_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETUO); + case Intrinsic::mips_fcune_w: + case Intrinsic::mips_fcune_d: + return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2), ISD::SETUNE); + case Intrinsic::mips_fdiv_w: + case Intrinsic::mips_fdiv_d: + return DAG.getNode(ISD::FDIV, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_ffint_u_w: + case Intrinsic::mips_ffint_u_d: + return DAG.getNode(ISD::UINT_TO_FP, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_ffint_s_w: + case Intrinsic::mips_ffint_s_d: + return DAG.getNode(ISD::SINT_TO_FP, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_fill_b: + case Intrinsic::mips_fill_h: + case Intrinsic::mips_fill_w: + case Intrinsic::mips_fill_d: { + SmallVector<SDValue, 16> Ops; + EVT ResTy = Op->getValueType(0); + + for (unsigned i = 0; i < ResTy.getVectorNumElements(); ++i) + Ops.push_back(Op->getOperand(1)); + + // If ResTy is v2i64 then the type legalizer will break this node down into + // an equivalent v4i32. + return DAG.getNode(ISD::BUILD_VECTOR, DL, ResTy, &Ops[0], Ops.size()); + } + case Intrinsic::mips_fexp2_w: + case Intrinsic::mips_fexp2_d: { + EVT ResTy = Op->getValueType(0); + return DAG.getNode( + ISD::FMUL, SDLoc(Op), ResTy, Op->getOperand(1), + DAG.getNode(ISD::FEXP2, SDLoc(Op), ResTy, Op->getOperand(2))); + } + case Intrinsic::mips_flog2_w: + case Intrinsic::mips_flog2_d: + return DAG.getNode(ISD::FLOG2, DL, Op->getValueType(0), Op->getOperand(1)); + case Intrinsic::mips_fmadd_w: + case Intrinsic::mips_fmadd_d: + return DAG.getNode(ISD::FMA, SDLoc(Op), Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2), Op->getOperand(3)); + case Intrinsic::mips_fmul_w: + case Intrinsic::mips_fmul_d: + return DAG.getNode(ISD::FMUL, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_fmsub_w: + case Intrinsic::mips_fmsub_d: { + EVT ResTy = Op->getValueType(0); + return DAG.getNode(ISD::FSUB, SDLoc(Op), ResTy, Op->getOperand(1), + DAG.getNode(ISD::FMUL, SDLoc(Op), ResTy, + Op->getOperand(2), Op->getOperand(3))); + } + case Intrinsic::mips_frint_w: + case Intrinsic::mips_frint_d: + return DAG.getNode(ISD::FRINT, DL, Op->getValueType(0), Op->getOperand(1)); + case Intrinsic::mips_fsqrt_w: + case Intrinsic::mips_fsqrt_d: + return DAG.getNode(ISD::FSQRT, DL, Op->getValueType(0), Op->getOperand(1)); + case Intrinsic::mips_fsub_w: + case Intrinsic::mips_fsub_d: + return DAG.getNode(ISD::FSUB, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_ftrunc_u_w: + case Intrinsic::mips_ftrunc_u_d: + return DAG.getNode(ISD::FP_TO_UINT, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_ftrunc_s_w: + case Intrinsic::mips_ftrunc_s_d: + return DAG.getNode(ISD::FP_TO_SINT, DL, Op->getValueType(0), + Op->getOperand(1)); + case Intrinsic::mips_ilvev_b: + case Intrinsic::mips_ilvev_h: + case Intrinsic::mips_ilvev_w: + case Intrinsic::mips_ilvev_d: + return DAG.getNode(MipsISD::ILVEV, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_ilvl_b: + case Intrinsic::mips_ilvl_h: + case Intrinsic::mips_ilvl_w: + case Intrinsic::mips_ilvl_d: + return DAG.getNode(MipsISD::ILVL, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_ilvod_b: + case Intrinsic::mips_ilvod_h: + case Intrinsic::mips_ilvod_w: + case Intrinsic::mips_ilvod_d: + return DAG.getNode(MipsISD::ILVOD, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_ilvr_b: + case Intrinsic::mips_ilvr_h: + case Intrinsic::mips_ilvr_w: + case Intrinsic::mips_ilvr_d: + return DAG.getNode(MipsISD::ILVR, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_insert_b: + case Intrinsic::mips_insert_h: + case Intrinsic::mips_insert_w: + case Intrinsic::mips_insert_d: + return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(Op), Op->getValueType(0), + Op->getOperand(1), Op->getOperand(3), Op->getOperand(2)); + case Intrinsic::mips_ldi_b: + case Intrinsic::mips_ldi_h: + case Intrinsic::mips_ldi_w: + case Intrinsic::mips_ldi_d: + return lowerMSASplatImm(Op, 1, DAG); + case Intrinsic::mips_lsa: { + EVT ResTy = Op->getValueType(0); + return DAG.getNode(ISD::ADD, SDLoc(Op), ResTy, Op->getOperand(1), + DAG.getNode(ISD::SHL, SDLoc(Op), ResTy, + Op->getOperand(2), Op->getOperand(3))); + } + case Intrinsic::mips_maddv_b: + case Intrinsic::mips_maddv_h: + case Intrinsic::mips_maddv_w: + case Intrinsic::mips_maddv_d: { + EVT ResTy = Op->getValueType(0); + return DAG.getNode(ISD::ADD, SDLoc(Op), ResTy, Op->getOperand(1), + DAG.getNode(ISD::MUL, SDLoc(Op), ResTy, + Op->getOperand(2), Op->getOperand(3))); + } + case Intrinsic::mips_max_s_b: + case Intrinsic::mips_max_s_h: + case Intrinsic::mips_max_s_w: + case Intrinsic::mips_max_s_d: + return DAG.getNode(MipsISD::VSMAX, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_max_u_b: + case Intrinsic::mips_max_u_h: + case Intrinsic::mips_max_u_w: + case Intrinsic::mips_max_u_d: + return DAG.getNode(MipsISD::VUMAX, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_maxi_s_b: + case Intrinsic::mips_maxi_s_h: + case Intrinsic::mips_maxi_s_w: + case Intrinsic::mips_maxi_s_d: + return DAG.getNode(MipsISD::VSMAX, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_maxi_u_b: + case Intrinsic::mips_maxi_u_h: + case Intrinsic::mips_maxi_u_w: + case Intrinsic::mips_maxi_u_d: + return DAG.getNode(MipsISD::VUMAX, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_min_s_b: + case Intrinsic::mips_min_s_h: + case Intrinsic::mips_min_s_w: + case Intrinsic::mips_min_s_d: + return DAG.getNode(MipsISD::VSMIN, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_min_u_b: + case Intrinsic::mips_min_u_h: + case Intrinsic::mips_min_u_w: + case Intrinsic::mips_min_u_d: + return DAG.getNode(MipsISD::VUMIN, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_mini_s_b: + case Intrinsic::mips_mini_s_h: + case Intrinsic::mips_mini_s_w: + case Intrinsic::mips_mini_s_d: + return DAG.getNode(MipsISD::VSMIN, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_mini_u_b: + case Intrinsic::mips_mini_u_h: + case Intrinsic::mips_mini_u_w: + case Intrinsic::mips_mini_u_d: + return DAG.getNode(MipsISD::VUMIN, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_mod_s_b: + case Intrinsic::mips_mod_s_h: + case Intrinsic::mips_mod_s_w: + case Intrinsic::mips_mod_s_d: + return DAG.getNode(ISD::SREM, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_mod_u_b: + case Intrinsic::mips_mod_u_h: + case Intrinsic::mips_mod_u_w: + case Intrinsic::mips_mod_u_d: + return DAG.getNode(ISD::UREM, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_mulv_b: + case Intrinsic::mips_mulv_h: + case Intrinsic::mips_mulv_w: + case Intrinsic::mips_mulv_d: + return DAG.getNode(ISD::MUL, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_msubv_b: + case Intrinsic::mips_msubv_h: + case Intrinsic::mips_msubv_w: + case Intrinsic::mips_msubv_d: { + EVT ResTy = Op->getValueType(0); + return DAG.getNode(ISD::SUB, SDLoc(Op), ResTy, Op->getOperand(1), + DAG.getNode(ISD::MUL, SDLoc(Op), ResTy, + Op->getOperand(2), Op->getOperand(3))); + } + case Intrinsic::mips_nlzc_b: + case Intrinsic::mips_nlzc_h: + case Intrinsic::mips_nlzc_w: + case Intrinsic::mips_nlzc_d: + return DAG.getNode(ISD::CTLZ, DL, Op->getValueType(0), Op->getOperand(1)); + case Intrinsic::mips_nor_v: { + SDValue Res = DAG.getNode(ISD::OR, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + return DAG.getNOT(DL, Res, Res->getValueType(0)); + } + case Intrinsic::mips_nori_b: { + SDValue Res = DAG.getNode(ISD::OR, DL, Op->getValueType(0), + Op->getOperand(1), + lowerMSASplatImm(Op, 2, DAG)); + return DAG.getNOT(DL, Res, Res->getValueType(0)); + } + case Intrinsic::mips_or_v: + return DAG.getNode(ISD::OR, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_ori_b: + return DAG.getNode(ISD::OR, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_pckev_b: + case Intrinsic::mips_pckev_h: + case Intrinsic::mips_pckev_w: + case Intrinsic::mips_pckev_d: + return DAG.getNode(MipsISD::PCKEV, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_pckod_b: + case Intrinsic::mips_pckod_h: + case Intrinsic::mips_pckod_w: + case Intrinsic::mips_pckod_d: + return DAG.getNode(MipsISD::PCKOD, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2)); + case Intrinsic::mips_pcnt_b: + case Intrinsic::mips_pcnt_h: + case Intrinsic::mips_pcnt_w: + case Intrinsic::mips_pcnt_d: + return DAG.getNode(ISD::CTPOP, DL, Op->getValueType(0), Op->getOperand(1)); + case Intrinsic::mips_shf_b: + case Intrinsic::mips_shf_h: + case Intrinsic::mips_shf_w: + return DAG.getNode(MipsISD::SHF, DL, Op->getValueType(0), + Op->getOperand(2), Op->getOperand(1)); + case Intrinsic::mips_sll_b: + case Intrinsic::mips_sll_h: + case Intrinsic::mips_sll_w: + case Intrinsic::mips_sll_d: + return DAG.getNode(ISD::SHL, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_slli_b: + case Intrinsic::mips_slli_h: + case Intrinsic::mips_slli_w: + case Intrinsic::mips_slli_d: + return DAG.getNode(ISD::SHL, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_splat_b: + case Intrinsic::mips_splat_h: + case Intrinsic::mips_splat_w: + case Intrinsic::mips_splat_d: + // We can't lower via VECTOR_SHUFFLE because it requires constant shuffle + // masks, nor can we lower via BUILD_VECTOR & EXTRACT_VECTOR_ELT because + // EXTRACT_VECTOR_ELT can't extract i64's on MIPS32. + // Instead we lower to MipsISD::VSHF and match from there. + return DAG.getNode(MipsISD::VSHF, DL, Op->getValueType(0), + lowerMSASplatZExt(Op, 2, DAG), Op->getOperand(1), + Op->getOperand(1)); + case Intrinsic::mips_splati_b: + case Intrinsic::mips_splati_h: + case Intrinsic::mips_splati_w: + case Intrinsic::mips_splati_d: + return DAG.getNode(MipsISD::VSHF, DL, Op->getValueType(0), + lowerMSASplatImm(Op, 2, DAG), Op->getOperand(1), + Op->getOperand(1)); + case Intrinsic::mips_sra_b: + case Intrinsic::mips_sra_h: + case Intrinsic::mips_sra_w: + case Intrinsic::mips_sra_d: + return DAG.getNode(ISD::SRA, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_srai_b: + case Intrinsic::mips_srai_h: + case Intrinsic::mips_srai_w: + case Intrinsic::mips_srai_d: + return DAG.getNode(ISD::SRA, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_srl_b: + case Intrinsic::mips_srl_h: + case Intrinsic::mips_srl_w: + case Intrinsic::mips_srl_d: + return DAG.getNode(ISD::SRL, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_srli_b: + case Intrinsic::mips_srli_h: + case Intrinsic::mips_srli_w: + case Intrinsic::mips_srli_d: + return DAG.getNode(ISD::SRL, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_subv_b: + case Intrinsic::mips_subv_h: + case Intrinsic::mips_subv_w: + case Intrinsic::mips_subv_d: + return DAG.getNode(ISD::SUB, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_subvi_b: + case Intrinsic::mips_subvi_h: + case Intrinsic::mips_subvi_w: + case Intrinsic::mips_subvi_d: + return DAG.getNode(ISD::SUB, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + case Intrinsic::mips_vshf_b: + case Intrinsic::mips_vshf_h: + case Intrinsic::mips_vshf_w: + case Intrinsic::mips_vshf_d: + return DAG.getNode(MipsISD::VSHF, DL, Op->getValueType(0), + Op->getOperand(1), Op->getOperand(2), Op->getOperand(3)); + case Intrinsic::mips_xor_v: + return DAG.getNode(ISD::XOR, DL, Op->getValueType(0), Op->getOperand(1), + Op->getOperand(2)); + case Intrinsic::mips_xori_b: + return DAG.getNode(ISD::XOR, DL, Op->getValueType(0), + Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG)); + } +} + +static SDValue lowerMSALoadIntr(SDValue Op, SelectionDAG &DAG, unsigned Intr) { + SDLoc DL(Op); + SDValue ChainIn = Op->getOperand(0); + SDValue Address = Op->getOperand(2); + SDValue Offset = Op->getOperand(3); + EVT ResTy = Op->getValueType(0); + EVT PtrTy = Address->getValueType(0); + + Address = DAG.getNode(ISD::ADD, DL, PtrTy, Address, Offset); + + return DAG.getLoad(ResTy, DL, ChainIn, Address, MachinePointerInfo(), false, + false, false, 16); +} + +SDValue MipsSETargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op, + SelectionDAG &DAG) const { + unsigned Intr = cast<ConstantSDNode>(Op->getOperand(1))->getZExtValue(); + switch (Intr) { + default: + return SDValue(); + case Intrinsic::mips_extp: + return lowerDSPIntr(Op, DAG, MipsISD::EXTP); + case Intrinsic::mips_extpdp: + return lowerDSPIntr(Op, DAG, MipsISD::EXTPDP); + case Intrinsic::mips_extr_w: + return lowerDSPIntr(Op, DAG, MipsISD::EXTR_W); + case Intrinsic::mips_extr_r_w: + return lowerDSPIntr(Op, DAG, MipsISD::EXTR_R_W); + case Intrinsic::mips_extr_rs_w: + return lowerDSPIntr(Op, DAG, MipsISD::EXTR_RS_W); + case Intrinsic::mips_extr_s_h: + return lowerDSPIntr(Op, DAG, MipsISD::EXTR_S_H); + case Intrinsic::mips_mthlip: + return lowerDSPIntr(Op, DAG, MipsISD::MTHLIP); + case Intrinsic::mips_mulsaq_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::MULSAQ_S_W_PH); + case Intrinsic::mips_maq_s_w_phl: + return lowerDSPIntr(Op, DAG, MipsISD::MAQ_S_W_PHL); + case Intrinsic::mips_maq_s_w_phr: + return lowerDSPIntr(Op, DAG, MipsISD::MAQ_S_W_PHR); + case Intrinsic::mips_maq_sa_w_phl: + return lowerDSPIntr(Op, DAG, MipsISD::MAQ_SA_W_PHL); + case Intrinsic::mips_maq_sa_w_phr: + return lowerDSPIntr(Op, DAG, MipsISD::MAQ_SA_W_PHR); + case Intrinsic::mips_dpaq_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPAQ_S_W_PH); + case Intrinsic::mips_dpsq_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPSQ_S_W_PH); + case Intrinsic::mips_dpaq_sa_l_w: + return lowerDSPIntr(Op, DAG, MipsISD::DPAQ_SA_L_W); + case Intrinsic::mips_dpsq_sa_l_w: + return lowerDSPIntr(Op, DAG, MipsISD::DPSQ_SA_L_W); + case Intrinsic::mips_dpaqx_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPAQX_S_W_PH); + case Intrinsic::mips_dpaqx_sa_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPAQX_SA_W_PH); + case Intrinsic::mips_dpsqx_s_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPSQX_S_W_PH); + case Intrinsic::mips_dpsqx_sa_w_ph: + return lowerDSPIntr(Op, DAG, MipsISD::DPSQX_SA_W_PH); + case Intrinsic::mips_ld_b: + case Intrinsic::mips_ld_h: + case Intrinsic::mips_ld_w: + case Intrinsic::mips_ld_d: + return lowerMSALoadIntr(Op, DAG, Intr); + } +} + +static SDValue lowerMSAStoreIntr(SDValue Op, SelectionDAG &DAG, unsigned Intr) { + SDLoc DL(Op); + SDValue ChainIn = Op->getOperand(0); + SDValue Value = Op->getOperand(2); + SDValue Address = Op->getOperand(3); + SDValue Offset = Op->getOperand(4); + EVT PtrTy = Address->getValueType(0); + + Address = DAG.getNode(ISD::ADD, DL, PtrTy, Address, Offset); + + return DAG.getStore(ChainIn, DL, Value, Address, MachinePointerInfo(), false, + false, 16); +} + +SDValue MipsSETargetLowering::lowerINTRINSIC_VOID(SDValue Op, + SelectionDAG &DAG) const { + unsigned Intr = cast<ConstantSDNode>(Op->getOperand(1))->getZExtValue(); + switch (Intr) { + default: + return SDValue(); + case Intrinsic::mips_st_b: + case Intrinsic::mips_st_h: + case Intrinsic::mips_st_w: + case Intrinsic::mips_st_d: + return lowerMSAStoreIntr(Op, DAG, Intr); + } +} + +/// \brief Check if the given BuildVectorSDNode is a splat. +/// This method currently relies on DAG nodes being reused when equivalent, +/// so it's possible for this to return false even when isConstantSplat returns +/// true. +static bool isSplatVector(const BuildVectorSDNode *N) { + unsigned int nOps = N->getNumOperands(); + assert(nOps > 1 && "isSplatVector has 0 or 1 sized build vector"); + + SDValue Operand0 = N->getOperand(0); + + for (unsigned int i = 1; i < nOps; ++i) { + if (N->getOperand(i) != Operand0) + return false; + } + + return true; +} + +// Lower ISD::EXTRACT_VECTOR_ELT into MipsISD::VEXTRACT_SEXT_ELT. +// +// The non-value bits resulting from ISD::EXTRACT_VECTOR_ELT are undefined. We +// choose to sign-extend but we could have equally chosen zero-extend. The +// DAGCombiner will fold any sign/zero extension of the ISD::EXTRACT_VECTOR_ELT +// result into this node later (possibly changing it to a zero-extend in the +// process). +SDValue MipsSETargetLowering:: +lowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const { + SDLoc DL(Op); + EVT ResTy = Op->getValueType(0); + SDValue Op0 = Op->getOperand(0); + EVT VecTy = Op0->getValueType(0); + + if (!VecTy.is128BitVector()) + return SDValue(); + + if (ResTy.isInteger()) { + SDValue Op1 = Op->getOperand(1); + EVT EltTy = VecTy.getVectorElementType(); + return DAG.getNode(MipsISD::VEXTRACT_SEXT_ELT, DL, ResTy, Op0, Op1, + DAG.getValueType(EltTy)); + } + + return Op; +} + +static bool isConstantOrUndef(const SDValue Op) { + if (Op->getOpcode() == ISD::UNDEF) + return true; + if (dyn_cast<ConstantSDNode>(Op)) + return true; + if (dyn_cast<ConstantFPSDNode>(Op)) + return true; + return false; +} + +static bool isConstantOrUndefBUILD_VECTOR(const BuildVectorSDNode *Op) { + for (unsigned i = 0; i < Op->getNumOperands(); ++i) + if (isConstantOrUndef(Op->getOperand(i))) + return true; + return false; +} + +// Lowers ISD::BUILD_VECTOR into appropriate SelectionDAG nodes for the +// backend. +// +// Lowers according to the following rules: +// - Constant splats are legal as-is as long as the SplatBitSize is a power of +// 2 less than or equal to 64 and the value fits into a signed 10-bit +// immediate +// - Constant splats are lowered to bitconverted BUILD_VECTORs if SplatBitSize +// is a power of 2 less than or equal to 64 and the value does not fit into a +// signed 10-bit immediate +// - Non-constant splats are legal as-is. +// - Non-constant non-splats are lowered to sequences of INSERT_VECTOR_ELT. +// - All others are illegal and must be expanded. +SDValue MipsSETargetLowering::lowerBUILD_VECTOR(SDValue Op, + SelectionDAG &DAG) const { + BuildVectorSDNode *Node = cast<BuildVectorSDNode>(Op); + EVT ResTy = Op->getValueType(0); + SDLoc DL(Op); + APInt SplatValue, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + + if (!Subtarget->hasMSA() || !ResTy.is128BitVector()) + return SDValue(); + + if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, + HasAnyUndefs, 8, + !Subtarget->isLittle()) && SplatBitSize <= 64) { + // We can only cope with 8, 16, 32, or 64-bit elements + if (SplatBitSize != 8 && SplatBitSize != 16 && SplatBitSize != 32 && + SplatBitSize != 64) + return SDValue(); + + // If the value fits into a simm10 then we can use ldi.[bhwd] + // However, if it isn't an integer type we will have to bitcast from an + // integer type first. Also, if there are any undefs, we must lower them + // to defined values first. + if (ResTy.isInteger() && !HasAnyUndefs && SplatValue.isSignedIntN(10)) + return Op; + + EVT ViaVecTy; + + switch (SplatBitSize) { + default: + return SDValue(); + case 8: + ViaVecTy = MVT::v16i8; + break; + case 16: + ViaVecTy = MVT::v8i16; + break; + case 32: + ViaVecTy = MVT::v4i32; + break; + case 64: + // There's no fill.d to fall back on for 64-bit values + return SDValue(); + } + + // SelectionDAG::getConstant will promote SplatValue appropriately. + SDValue Result = DAG.getConstant(SplatValue, ViaVecTy); + + // Bitcast to the type we originally wanted + if (ViaVecTy != ResTy) + Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result); + + return Result; + } else if (isSplatVector(Node)) + return Op; + else if (!isConstantOrUndefBUILD_VECTOR(Node)) { + // Use INSERT_VECTOR_ELT operations rather than expand to stores. + // The resulting code is the same length as the expansion, but it doesn't + // use memory operations + EVT ResTy = Node->getValueType(0); + + assert(ResTy.isVector()); + + unsigned NumElts = ResTy.getVectorNumElements(); + SDValue Vector = DAG.getUNDEF(ResTy); + for (unsigned i = 0; i < NumElts; ++i) { + Vector = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Vector, + Node->getOperand(i), + DAG.getConstant(i, MVT::i32)); + } + return Vector; + } + + return SDValue(); +} + +// Lower VECTOR_SHUFFLE into SHF (if possible). +// +// SHF splits the vector into blocks of four elements, then shuffles these +// elements according to a <4 x i2> constant (encoded as an integer immediate). +// +// It is therefore possible to lower into SHF when the mask takes the form: +// <a, b, c, d, a+4, b+4, c+4, d+4, a+8, b+8, c+8, d+8, ...> +// When undef's appear they are treated as if they were whatever value is +// necessary in order to fit the above form. +// +// For example: +// %2 = shufflevector <8 x i16> %0, <8 x i16> undef, +// <8 x i32> <i32 3, i32 2, i32 1, i32 0, +// i32 7, i32 6, i32 5, i32 4> +// is lowered to: +// (SHF_H $w0, $w1, 27) +// where the 27 comes from: +// 3 + (2 << 2) + (1 << 4) + (0 << 6) +static SDValue lowerVECTOR_SHUFFLE_SHF(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + int SHFIndices[4] = { -1, -1, -1, -1 }; + + if (Indices.size() < 4) + return SDValue(); + + for (unsigned i = 0; i < 4; ++i) { + for (unsigned j = i; j < Indices.size(); j += 4) { + int Idx = Indices[j]; + + // Convert from vector index to 4-element subvector index + // If an index refers to an element outside of the subvector then give up + if (Idx != -1) { + Idx -= 4 * (j / 4); + if (Idx < 0 || Idx >= 4) + return SDValue(); + } + + // If the mask has an undef, replace it with the current index. + // Note that it might still be undef if the current index is also undef + if (SHFIndices[i] == -1) + SHFIndices[i] = Idx; + + // Check that non-undef values are the same as in the mask. If they + // aren't then give up + if (!(Idx == -1 || Idx == SHFIndices[i])) + return SDValue(); + } + } + + // Calculate the immediate. Replace any remaining undefs with zero + APInt Imm(32, 0); + for (int i = 3; i >= 0; --i) { + int Idx = SHFIndices[i]; + + if (Idx == -1) + Idx = 0; + + Imm <<= 2; + Imm |= Idx & 0x3; + } + + return DAG.getNode(MipsISD::SHF, SDLoc(Op), ResTy, + DAG.getConstant(Imm, MVT::i32), Op->getOperand(0)); +} + +// Lower VECTOR_SHUFFLE into ILVEV (if possible). +// +// ILVEV interleaves the even elements from each vector. +// +// It is possible to lower into ILVEV when the mask takes the form: +// <0, n, 2, n+2, 4, n+4, ...> +// where n is the number of elements in the vector. +// +// When undef's appear in the mask they are treated as if they were whatever +// value is necessary in order to fit the above form. +static SDValue lowerVECTOR_SHUFFLE_ILVEV(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + assert ((Indices.size() % 2) == 0); + int WsIdx = 0; + int WtIdx = ResTy.getVectorNumElements(); + + for (unsigned i = 0; i < Indices.size(); i += 2) { + if (Indices[i] != -1 && Indices[i] != WsIdx) + return SDValue(); + if (Indices[i+1] != -1 && Indices[i+1] != WtIdx) + return SDValue(); + WsIdx += 2; + WtIdx += 2; + } + + return DAG.getNode(MipsISD::ILVEV, SDLoc(Op), ResTy, Op->getOperand(0), + Op->getOperand(1)); +} + +// Lower VECTOR_SHUFFLE into ILVOD (if possible). +// +// ILVOD interleaves the odd elements from each vector. +// +// It is possible to lower into ILVOD when the mask takes the form: +// <1, n+1, 3, n+3, 5, n+5, ...> +// where n is the number of elements in the vector. +// +// When undef's appear in the mask they are treated as if they were whatever +// value is necessary in order to fit the above form. +static SDValue lowerVECTOR_SHUFFLE_ILVOD(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + assert ((Indices.size() % 2) == 0); + int WsIdx = 1; + int WtIdx = ResTy.getVectorNumElements() + 1; + + for (unsigned i = 0; i < Indices.size(); i += 2) { + if (Indices[i] != -1 && Indices[i] != WsIdx) + return SDValue(); + if (Indices[i+1] != -1 && Indices[i+1] != WtIdx) + return SDValue(); + WsIdx += 2; + WtIdx += 2; + } + + return DAG.getNode(MipsISD::ILVOD, SDLoc(Op), ResTy, Op->getOperand(0), + Op->getOperand(1)); +} + +// Lower VECTOR_SHUFFLE into ILVL (if possible). +// +// ILVL interleaves consecutive elements from the left half of each vector. +// +// It is possible to lower into ILVL when the mask takes the form: +// <0, n, 1, n+1, 2, n+2, ...> +// where n is the number of elements in the vector. +// +// When undef's appear in the mask they are treated as if they were whatever +// value is necessary in order to fit the above form. +static SDValue lowerVECTOR_SHUFFLE_ILVL(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + assert ((Indices.size() % 2) == 0); + int WsIdx = 0; + int WtIdx = ResTy.getVectorNumElements(); + + for (unsigned i = 0; i < Indices.size(); i += 2) { + if (Indices[i] != -1 && Indices[i] != WsIdx) + return SDValue(); + if (Indices[i+1] != -1 && Indices[i+1] != WtIdx) + return SDValue(); + WsIdx ++; + WtIdx ++; + } + + return DAG.getNode(MipsISD::ILVL, SDLoc(Op), ResTy, Op->getOperand(0), + Op->getOperand(1)); +} + +// Lower VECTOR_SHUFFLE into ILVR (if possible). +// +// ILVR interleaves consecutive elements from the right half of each vector. +// +// It is possible to lower into ILVR when the mask takes the form: +// <x, n+x, x+1, n+x+1, x+2, n+x+2, ...> +// where n is the number of elements in the vector and x is half n. +// +// When undef's appear in the mask they are treated as if they were whatever +// value is necessary in order to fit the above form. +static SDValue lowerVECTOR_SHUFFLE_ILVR(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + assert ((Indices.size() % 2) == 0); + unsigned NumElts = ResTy.getVectorNumElements(); + int WsIdx = NumElts / 2; + int WtIdx = NumElts + NumElts / 2; + + for (unsigned i = 0; i < Indices.size(); i += 2) { + if (Indices[i] != -1 && Indices[i] != WsIdx) + return SDValue(); + if (Indices[i+1] != -1 && Indices[i+1] != WtIdx) + return SDValue(); + WsIdx ++; + WtIdx ++; + } + + return DAG.getNode(MipsISD::ILVR, SDLoc(Op), ResTy, Op->getOperand(0), + Op->getOperand(1)); +} + +// Lower VECTOR_SHUFFLE into PCKEV (if possible). +// +// PCKEV copies the even elements of each vector into the result vector. +// +// It is possible to lower into PCKEV when the mask takes the form: +// <0, 2, 4, ..., n, n+2, n+4, ...> +// where n is the number of elements in the vector. +// +// When undef's appear in the mask they are treated as if they were whatever +// value is necessary in order to fit the above form. +static SDValue lowerVECTOR_SHUFFLE_PCKEV(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + assert ((Indices.size() % 2) == 0); + int Idx = 0; + + for (unsigned i = 0; i < Indices.size(); ++i) { + if (Indices[i] != -1 && Indices[i] != Idx) + return SDValue(); + Idx += 2; + } + + return DAG.getNode(MipsISD::PCKEV, SDLoc(Op), ResTy, Op->getOperand(0), + Op->getOperand(1)); +} + +// Lower VECTOR_SHUFFLE into PCKOD (if possible). +// +// PCKOD copies the odd elements of each vector into the result vector. +// +// It is possible to lower into PCKOD when the mask takes the form: +// <1, 3, 5, ..., n+1, n+3, n+5, ...> +// where n is the number of elements in the vector. +// +// When undef's appear in the mask they are treated as if they were whatever +// value is necessary in order to fit the above form. +static SDValue lowerVECTOR_SHUFFLE_PCKOD(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + assert ((Indices.size() % 2) == 0); + int Idx = 1; + + for (unsigned i = 0; i < Indices.size(); ++i) { + if (Indices[i] != -1 && Indices[i] != Idx) + return SDValue(); + Idx += 2; + } + + return DAG.getNode(MipsISD::PCKOD, SDLoc(Op), ResTy, Op->getOperand(0), + Op->getOperand(1)); +} + +// Lower VECTOR_SHUFFLE into VSHF. +// +// This mostly consists of converting the shuffle indices in Indices into a +// BUILD_VECTOR and adding it as an operand to the resulting VSHF. There is +// also code to eliminate unused operands of the VECTOR_SHUFFLE. For example, +// if the type is v8i16 and all the indices are less than 8 then the second +// operand is unused and can be replaced with anything. We choose to replace it +// with the used operand since this reduces the number of instructions overall. +static SDValue lowerVECTOR_SHUFFLE_VSHF(SDValue Op, EVT ResTy, + SmallVector<int, 16> Indices, + SelectionDAG &DAG) { + SmallVector<SDValue, 16> Ops; + SDValue Op0; + SDValue Op1; + EVT MaskVecTy = ResTy.changeVectorElementTypeToInteger(); + EVT MaskEltTy = MaskVecTy.getVectorElementType(); + bool Using1stVec = false; + bool Using2ndVec = false; + SDLoc DL(Op); + int ResTyNumElts = ResTy.getVectorNumElements(); + + for (int i = 0; i < ResTyNumElts; ++i) { + // Idx == -1 means UNDEF + int Idx = Indices[i]; + + if (0 <= Idx && Idx < ResTyNumElts) + Using1stVec = true; + if (ResTyNumElts <= Idx && Idx < ResTyNumElts * 2) + Using2ndVec = true; + } + + for (SmallVector<int, 16>::iterator I = Indices.begin(); I != Indices.end(); + ++I) + Ops.push_back(DAG.getTargetConstant(*I, MaskEltTy)); + + SDValue MaskVec = DAG.getNode(ISD::BUILD_VECTOR, DL, MaskVecTy, &Ops[0], + Ops.size()); + + if (Using1stVec && Using2ndVec) { + Op0 = Op->getOperand(0); + Op1 = Op->getOperand(1); + } else if (Using1stVec) + Op0 = Op1 = Op->getOperand(0); + else if (Using2ndVec) + Op0 = Op1 = Op->getOperand(1); + else + llvm_unreachable("shuffle vector mask references neither vector operand?"); + + return DAG.getNode(MipsISD::VSHF, DL, ResTy, MaskVec, Op0, Op1); +} + +// Lower VECTOR_SHUFFLE into one of a number of instructions depending on the +// indices in the shuffle. +SDValue MipsSETargetLowering::lowerVECTOR_SHUFFLE(SDValue Op, + SelectionDAG &DAG) const { + ShuffleVectorSDNode *Node = cast<ShuffleVectorSDNode>(Op); + EVT ResTy = Op->getValueType(0); + + if (!ResTy.is128BitVector()) + return SDValue(); + + int ResTyNumElts = ResTy.getVectorNumElements(); + SmallVector<int, 16> Indices; + + for (int i = 0; i < ResTyNumElts; ++i) + Indices.push_back(Node->getMaskElt(i)); + + SDValue Result = lowerVECTOR_SHUFFLE_SHF(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + Result = lowerVECTOR_SHUFFLE_ILVEV(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + Result = lowerVECTOR_SHUFFLE_ILVOD(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + Result = lowerVECTOR_SHUFFLE_ILVL(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + Result = lowerVECTOR_SHUFFLE_ILVR(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + Result = lowerVECTOR_SHUFFLE_PCKEV(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + Result = lowerVECTOR_SHUFFLE_PCKOD(Op, ResTy, Indices, DAG); + if (Result.getNode()) + return Result; + return lowerVECTOR_SHUFFLE_VSHF(Op, ResTy, Indices, DAG); +} + +MachineBasicBlock * MipsSETargetLowering:: +emitBPOSGE32(MachineInstr *MI, MachineBasicBlock *BB) const{ + // $bb: + // bposge32_pseudo $vr0 + // => + // $bb: + // bposge32 $tbb + // $fbb: + // li $vr2, 0 + // b $sink + // $tbb: + // li $vr1, 1 + // $sink: + // $vr0 = phi($vr2, $fbb, $vr1, $tbb) + + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + DebugLoc DL = MI->getDebugLoc(); + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = llvm::next(MachineFunction::iterator(BB)); + MachineFunction *F = BB->getParent(); + MachineBasicBlock *FBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *TBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *Sink = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, FBB); + F->insert(It, TBB); + F->insert(It, Sink); + + // Transfer the remainder of BB and its successor edges to Sink. + Sink->splice(Sink->begin(), BB, llvm::next(MachineBasicBlock::iterator(MI)), + BB->end()); + Sink->transferSuccessorsAndUpdatePHIs(BB); + + // Add successors. + BB->addSuccessor(FBB); + BB->addSuccessor(TBB); + FBB->addSuccessor(Sink); + TBB->addSuccessor(Sink); + + // Insert the real bposge32 instruction to $BB. + BuildMI(BB, DL, TII->get(Mips::BPOSGE32)).addMBB(TBB); + + // Fill $FBB. + unsigned VR2 = RegInfo.createVirtualRegister(RC); + BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::ADDiu), VR2) + .addReg(Mips::ZERO).addImm(0); + BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::B)).addMBB(Sink); + + // Fill $TBB. + unsigned VR1 = RegInfo.createVirtualRegister(RC); + BuildMI(*TBB, TBB->end(), DL, TII->get(Mips::ADDiu), VR1) + .addReg(Mips::ZERO).addImm(1); + + // Insert phi function to $Sink. + BuildMI(*Sink, Sink->begin(), DL, TII->get(Mips::PHI), + MI->getOperand(0).getReg()) + .addReg(VR2).addMBB(FBB).addReg(VR1).addMBB(TBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return Sink; +} + +MachineBasicBlock * MipsSETargetLowering:: +emitMSACBranchPseudo(MachineInstr *MI, MachineBasicBlock *BB, + unsigned BranchOp) const{ + // $bb: + // vany_nonzero $rd, $ws + // => + // $bb: + // bnz.b $ws, $tbb + // b $fbb + // $fbb: + // li $rd1, 0 + // b $sink + // $tbb: + // li $rd2, 1 + // $sink: + // $rd = phi($rd1, $fbb, $rd2, $tbb) + + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + const TargetRegisterClass *RC = &Mips::GPR32RegClass; + DebugLoc DL = MI->getDebugLoc(); + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = llvm::next(MachineFunction::iterator(BB)); + MachineFunction *F = BB->getParent(); + MachineBasicBlock *FBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *TBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *Sink = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, FBB); + F->insert(It, TBB); + F->insert(It, Sink); + + // Transfer the remainder of BB and its successor edges to Sink. + Sink->splice(Sink->begin(), BB, llvm::next(MachineBasicBlock::iterator(MI)), + BB->end()); + Sink->transferSuccessorsAndUpdatePHIs(BB); + + // Add successors. + BB->addSuccessor(FBB); + BB->addSuccessor(TBB); + FBB->addSuccessor(Sink); + TBB->addSuccessor(Sink); + + // Insert the real bnz.b instruction to $BB. + BuildMI(BB, DL, TII->get(BranchOp)) + .addReg(MI->getOperand(1).getReg()) + .addMBB(TBB); + + // Fill $FBB. + unsigned RD1 = RegInfo.createVirtualRegister(RC); + BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::ADDiu), RD1) + .addReg(Mips::ZERO).addImm(0); + BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::B)).addMBB(Sink); + + // Fill $TBB. + unsigned RD2 = RegInfo.createVirtualRegister(RC); + BuildMI(*TBB, TBB->end(), DL, TII->get(Mips::ADDiu), RD2) + .addReg(Mips::ZERO).addImm(1); + + // Insert phi function to $Sink. + BuildMI(*Sink, Sink->begin(), DL, TII->get(Mips::PHI), + MI->getOperand(0).getReg()) + .addReg(RD1).addMBB(FBB).addReg(RD2).addMBB(TBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return Sink; +} + +// Emit the COPY_FW pseudo instruction. +// +// copy_fw_pseudo $fd, $ws, n +// => +// copy_u_w $rt, $ws, $n +// mtc1 $rt, $fd +// +// When n is zero, the equivalent operation can be performed with (potentially) +// zero instructions due to register overlaps. This optimization is never valid +// for lane 1 because it would require FR=0 mode which isn't supported by MSA. +MachineBasicBlock * MipsSETargetLowering:: +emitCOPY_FW(MachineInstr *MI, MachineBasicBlock *BB) const{ + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned Fd = MI->getOperand(0).getReg(); + unsigned Ws = MI->getOperand(1).getReg(); + unsigned Lane = MI->getOperand(2).getImm(); + + if (Lane == 0) + BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Fd).addReg(Ws, 0, Mips::sub_lo); + else { + unsigned Wt = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass); + + BuildMI(*BB, MI, DL, TII->get(Mips::SPLATI_W), Wt).addReg(Ws).addImm(1); + BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Fd).addReg(Wt, 0, Mips::sub_lo); + } + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the COPY_FD pseudo instruction. +// +// copy_fd_pseudo $fd, $ws, n +// => +// splati.d $wt, $ws, $n +// copy $fd, $wt:sub_64 +// +// When n is zero, the equivalent operation can be performed with (potentially) +// zero instructions due to register overlaps. This optimization is always +// valid because FR=1 mode which is the only supported mode in MSA. +MachineBasicBlock * MipsSETargetLowering:: +emitCOPY_FD(MachineInstr *MI, MachineBasicBlock *BB) const{ + assert(Subtarget->isFP64bit()); + + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + unsigned Fd = MI->getOperand(0).getReg(); + unsigned Ws = MI->getOperand(1).getReg(); + unsigned Lane = MI->getOperand(2).getImm() * 2; + DebugLoc DL = MI->getDebugLoc(); + + if (Lane == 0) + BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Fd).addReg(Ws, 0, Mips::sub_64); + else { + unsigned Wt = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass); + + BuildMI(*BB, MI, DL, TII->get(Mips::SPLATI_D), Wt).addReg(Ws).addImm(1); + BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Fd).addReg(Wt, 0, Mips::sub_64); + } + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the INSERT_FW pseudo instruction. +// +// insert_fw_pseudo $wd, $wd_in, $n, $fs +// => +// subreg_to_reg $wt:sub_lo, $fs +// insve_w $wd[$n], $wd_in, $wt[0] +MachineBasicBlock * +MipsSETargetLowering::emitINSERT_FW(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned Wd = MI->getOperand(0).getReg(); + unsigned Wd_in = MI->getOperand(1).getReg(); + unsigned Lane = MI->getOperand(2).getImm(); + unsigned Fs = MI->getOperand(3).getReg(); + unsigned Wt = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass); + + BuildMI(*BB, MI, DL, TII->get(Mips::SUBREG_TO_REG), Wt) + .addImm(0) + .addReg(Fs) + .addImm(Mips::sub_lo); + BuildMI(*BB, MI, DL, TII->get(Mips::INSVE_W), Wd) + .addReg(Wd_in) + .addImm(Lane) + .addReg(Wt); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the INSERT_FD pseudo instruction. +// +// insert_fd_pseudo $wd, $fs, n +// => +// subreg_to_reg $wt:sub_64, $fs +// insve_d $wd[$n], $wd_in, $wt[0] +MachineBasicBlock * +MipsSETargetLowering::emitINSERT_FD(MachineInstr *MI, + MachineBasicBlock *BB) const { + assert(Subtarget->isFP64bit()); + + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned Wd = MI->getOperand(0).getReg(); + unsigned Wd_in = MI->getOperand(1).getReg(); + unsigned Lane = MI->getOperand(2).getImm(); + unsigned Fs = MI->getOperand(3).getReg(); + unsigned Wt = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass); + + BuildMI(*BB, MI, DL, TII->get(Mips::SUBREG_TO_REG), Wt) + .addImm(0) + .addReg(Fs) + .addImm(Mips::sub_64); + BuildMI(*BB, MI, DL, TII->get(Mips::INSVE_D), Wd) + .addReg(Wd_in) + .addImm(Lane) + .addReg(Wt); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the FILL_FW pseudo instruction. +// +// fill_fw_pseudo $wd, $fs +// => +// implicit_def $wt1 +// insert_subreg $wt2:subreg_lo, $wt1, $fs +// splati.w $wd, $wt2[0] +MachineBasicBlock * +MipsSETargetLowering::emitFILL_FW(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned Wd = MI->getOperand(0).getReg(); + unsigned Fs = MI->getOperand(1).getReg(); + unsigned Wt1 = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass); + unsigned Wt2 = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass); + + BuildMI(*BB, MI, DL, TII->get(Mips::IMPLICIT_DEF), Wt1); + BuildMI(*BB, MI, DL, TII->get(Mips::INSERT_SUBREG), Wt2) + .addReg(Wt1) + .addReg(Fs) + .addImm(Mips::sub_lo); + BuildMI(*BB, MI, DL, TII->get(Mips::SPLATI_W), Wd).addReg(Wt2).addImm(0); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the FILL_FD pseudo instruction. +// +// fill_fd_pseudo $wd, $fs +// => +// implicit_def $wt1 +// insert_subreg $wt2:subreg_64, $wt1, $fs +// splati.d $wd, $wt2[0] +MachineBasicBlock * +MipsSETargetLowering::emitFILL_FD(MachineInstr *MI, + MachineBasicBlock *BB) const { + assert(Subtarget->isFP64bit()); + + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned Wd = MI->getOperand(0).getReg(); + unsigned Fs = MI->getOperand(1).getReg(); + unsigned Wt1 = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass); + unsigned Wt2 = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass); + + BuildMI(*BB, MI, DL, TII->get(Mips::IMPLICIT_DEF), Wt1); + BuildMI(*BB, MI, DL, TII->get(Mips::INSERT_SUBREG), Wt2) + .addReg(Wt1) + .addReg(Fs) + .addImm(Mips::sub_64); + BuildMI(*BB, MI, DL, TII->get(Mips::SPLATI_D), Wd).addReg(Wt2).addImm(0); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the FEXP2_W_1 pseudo instructions. +// +// fexp2_w_1_pseudo $wd, $wt +// => +// ldi.w $ws, 1 +// fexp2.w $wd, $ws, $wt +MachineBasicBlock * +MipsSETargetLowering::emitFEXP2_W_1(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + const TargetRegisterClass *RC = &Mips::MSA128WRegClass; + unsigned Ws1 = RegInfo.createVirtualRegister(RC); + unsigned Ws2 = RegInfo.createVirtualRegister(RC); + DebugLoc DL = MI->getDebugLoc(); + + // Splat 1.0 into a vector + BuildMI(*BB, MI, DL, TII->get(Mips::LDI_W), Ws1).addImm(1); + BuildMI(*BB, MI, DL, TII->get(Mips::FFINT_U_W), Ws2).addReg(Ws1); + + // Emit 1.0 * fexp2(Wt) + BuildMI(*BB, MI, DL, TII->get(Mips::FEXP2_W), MI->getOperand(0).getReg()) + .addReg(Ws2) + .addReg(MI->getOperand(1).getReg()); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +// Emit the FEXP2_D_1 pseudo instructions. +// +// fexp2_d_1_pseudo $wd, $wt +// => +// ldi.d $ws, 1 +// fexp2.d $wd, $ws, $wt +MachineBasicBlock * +MipsSETargetLowering::emitFEXP2_D_1(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + const TargetRegisterClass *RC = &Mips::MSA128DRegClass; + unsigned Ws1 = RegInfo.createVirtualRegister(RC); + unsigned Ws2 = RegInfo.createVirtualRegister(RC); + DebugLoc DL = MI->getDebugLoc(); + + // Splat 1.0 into a vector + BuildMI(*BB, MI, DL, TII->get(Mips::LDI_D), Ws1).addImm(1); + BuildMI(*BB, MI, DL, TII->get(Mips::FFINT_U_D), Ws2).addReg(Ws1); + + // Emit 1.0 * fexp2(Wt) + BuildMI(*BB, MI, DL, TII->get(Mips::FEXP2_D), MI->getOperand(0).getReg()) + .addReg(Ws2) + .addReg(MI->getOperand(1).getReg()); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.h b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.h new file mode 100644 index 000000000000..c5210d94b34d --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.h @@ -0,0 +1,114 @@ +//===-- MipsSEISelLowering.h - MipsSE 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. +// +//===----------------------------------------------------------------------===// +// +// Subclass of MipsTargetLowering specialized for mips32/64. +// +//===----------------------------------------------------------------------===// + +#ifndef MipsSEISELLOWERING_H +#define MipsSEISELLOWERING_H + +#include "MipsISelLowering.h" +#include "MipsRegisterInfo.h" + +namespace llvm { + class MipsSETargetLowering : public MipsTargetLowering { + public: + explicit MipsSETargetLowering(MipsTargetMachine &TM); + + /// \brief Enable MSA support for the given integer type and Register + /// class. + void addMSAIntType(MVT::SimpleValueType Ty, const TargetRegisterClass *RC); + /// \brief Enable MSA support for the given floating-point type and + /// Register class. + void addMSAFloatType(MVT::SimpleValueType Ty, + const TargetRegisterClass *RC); + + virtual bool allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const; + + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const; + + virtual SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const; + + virtual MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const; + + virtual bool isShuffleMaskLegal(const SmallVectorImpl<int> &Mask, + EVT VT) const { + return false; + } + + virtual const TargetRegisterClass *getRepRegClassFor(MVT VT) const { + if (VT == MVT::Untyped) + return Subtarget->hasDSP() ? &Mips::ACC64DSPRegClass : + &Mips::ACC64RegClass; + + return TargetLowering::getRepRegClassFor(VT); + } + + private: + virtual bool + isEligibleForTailCallOptimization(const MipsCC &MipsCCInfo, + unsigned NextStackOffset, + const MipsFunctionInfo& FI) const; + + virtual void + getOpndList(SmallVectorImpl<SDValue> &Ops, + std::deque< std::pair<unsigned, SDValue> > &RegsToPass, + bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage, + CallLoweringInfo &CLI, SDValue Callee, SDValue Chain) const; + + SDValue lowerLOAD(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerSTORE(SDValue Op, SelectionDAG &DAG) const; + + SDValue lowerMulDiv(SDValue Op, unsigned NewOpc, bool HasLo, bool HasHi, + SelectionDAG &DAG) const; + + SDValue lowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const; + /// \brief Lower VECTOR_SHUFFLE into one of a number of instructions + /// depending on the indices in the shuffle. + SDValue lowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const; + + MachineBasicBlock *emitBPOSGE32(MachineInstr *MI, + MachineBasicBlock *BB) const; + MachineBasicBlock *emitMSACBranchPseudo(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned BranchOp) const; + /// \brief Emit the COPY_FW pseudo instruction + MachineBasicBlock *emitCOPY_FW(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the COPY_FD pseudo instruction + MachineBasicBlock *emitCOPY_FD(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the INSERT_FW pseudo instruction + MachineBasicBlock *emitINSERT_FW(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the INSERT_FD pseudo instruction + MachineBasicBlock *emitINSERT_FD(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the FILL_FW pseudo instruction + MachineBasicBlock *emitFILL_FW(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the FILL_FD pseudo instruction + MachineBasicBlock *emitFILL_FD(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the FEXP2_W_1 pseudo instructions. + MachineBasicBlock *emitFEXP2_W_1(MachineInstr *MI, + MachineBasicBlock *BB) const; + /// \brief Emit the FEXP2_D_1 pseudo instructions. + MachineBasicBlock *emitFEXP2_D_1(MachineInstr *MI, + MachineBasicBlock *BB) const; + }; +} + +#endif // MipsSEISELLOWERING_H diff --git a/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp new file mode 100644 index 000000000000..02931a3e39ee --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp @@ -0,0 +1,571 @@ +//===-- MipsSEInstrInfo.cpp - Mips32/64 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 Mips32/64 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "MipsSEInstrInfo.h" +#include "InstPrinter/MipsInstPrinter.h" +#include "MipsMachineFunction.h" +#include "MipsTargetMachine.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +MipsSEInstrInfo::MipsSEInstrInfo(MipsTargetMachine &tm) + : MipsInstrInfo(tm, + tm.getRelocationModel() == Reloc::PIC_ ? Mips::B : Mips::J), + RI(*tm.getSubtargetImpl()), + IsN64(tm.getSubtarget<MipsSubtarget>().isABI_N64()) {} + +const MipsRegisterInfo &MipsSEInstrInfo::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. +unsigned MipsSEInstrInfo:: +isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const +{ + unsigned Opc = MI->getOpcode(); + + if ((Opc == Mips::LW) || (Opc == Mips::LD) || + (Opc == Mips::LWC1) || (Opc == Mips::LDC1) || (Opc == Mips::LDC164)) { + 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 MipsSEInstrInfo:: +isStoreToStackSlot(const MachineInstr *MI, int &FrameIndex) const +{ + unsigned Opc = MI->getOpcode(); + + if ((Opc == Mips::SW) || (Opc == Mips::SD) || + (Opc == Mips::SWC1) || (Opc == Mips::SDC1) || (Opc == Mips::SDC164)) { + 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; +} + +void MipsSEInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const { + unsigned Opc = 0, ZeroReg = 0; + + if (Mips::GPR32RegClass.contains(DestReg)) { // Copy to CPU Reg. + if (Mips::GPR32RegClass.contains(SrcReg)) + Opc = Mips::ADDu, ZeroReg = Mips::ZERO; + else if (Mips::CCRRegClass.contains(SrcReg)) + Opc = Mips::CFC1; + else if (Mips::FGR32RegClass.contains(SrcReg)) + Opc = Mips::MFC1; + else if (Mips::HI32RegClass.contains(SrcReg)) + Opc = Mips::MFHI, SrcReg = 0; + else if (Mips::LO32RegClass.contains(SrcReg)) + Opc = Mips::MFLO, SrcReg = 0; + else if (Mips::HI32DSPRegClass.contains(SrcReg)) + Opc = Mips::MFHI_DSP; + else if (Mips::LO32DSPRegClass.contains(SrcReg)) + Opc = Mips::MFLO_DSP; + else if (Mips::DSPCCRegClass.contains(SrcReg)) { + BuildMI(MBB, I, DL, get(Mips::RDDSP), DestReg).addImm(1 << 4) + .addReg(SrcReg, RegState::Implicit | getKillRegState(KillSrc)); + return; + } + else if (Mips::MSACtrlRegClass.contains(SrcReg)) + Opc = Mips::CFCMSA; + } + else if (Mips::GPR32RegClass.contains(SrcReg)) { // Copy from CPU Reg. + if (Mips::CCRRegClass.contains(DestReg)) + Opc = Mips::CTC1; + else if (Mips::FGR32RegClass.contains(DestReg)) + Opc = Mips::MTC1; + else if (Mips::HI32RegClass.contains(DestReg)) + Opc = Mips::MTHI, DestReg = 0; + else if (Mips::LO32RegClass.contains(DestReg)) + Opc = Mips::MTLO, DestReg = 0; + else if (Mips::HI32DSPRegClass.contains(DestReg)) + Opc = Mips::MTHI_DSP; + else if (Mips::LO32DSPRegClass.contains(DestReg)) + Opc = Mips::MTLO_DSP; + else if (Mips::DSPCCRegClass.contains(DestReg)) { + BuildMI(MBB, I, DL, get(Mips::WRDSP)) + .addReg(SrcReg, getKillRegState(KillSrc)).addImm(1 << 4) + .addReg(DestReg, RegState::ImplicitDefine); + return; + } + else if (Mips::MSACtrlRegClass.contains(DestReg)) + Opc = Mips::CTCMSA; + } + else if (Mips::FGR32RegClass.contains(DestReg, SrcReg)) + Opc = Mips::FMOV_S; + else if (Mips::AFGR64RegClass.contains(DestReg, SrcReg)) + Opc = Mips::FMOV_D32; + else if (Mips::FGR64RegClass.contains(DestReg, SrcReg)) + Opc = Mips::FMOV_D64; + else if (Mips::GPR64RegClass.contains(DestReg)) { // Copy to CPU64 Reg. + if (Mips::GPR64RegClass.contains(SrcReg)) + Opc = Mips::DADDu, ZeroReg = Mips::ZERO_64; + else if (Mips::HI64RegClass.contains(SrcReg)) + Opc = Mips::MFHI64, SrcReg = 0; + else if (Mips::LO64RegClass.contains(SrcReg)) + Opc = Mips::MFLO64, SrcReg = 0; + else if (Mips::FGR64RegClass.contains(SrcReg)) + Opc = Mips::DMFC1; + } + else if (Mips::GPR64RegClass.contains(SrcReg)) { // Copy from CPU64 Reg. + if (Mips::HI64RegClass.contains(DestReg)) + Opc = Mips::MTHI64, DestReg = 0; + else if (Mips::LO64RegClass.contains(DestReg)) + Opc = Mips::MTLO64, DestReg = 0; + else if (Mips::FGR64RegClass.contains(DestReg)) + Opc = Mips::DMTC1; + } + else if (Mips::MSA128BRegClass.contains(DestReg)) { // Copy to MSA reg + if (Mips::MSA128BRegClass.contains(SrcReg)) + Opc = Mips::MOVE_V; + } + + assert(Opc && "Cannot copy registers"); + + MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(Opc)); + + if (DestReg) + MIB.addReg(DestReg, RegState::Define); + + if (SrcReg) + MIB.addReg(SrcReg, getKillRegState(KillSrc)); + + if (ZeroReg) + MIB.addReg(ZeroReg); +} + +void MipsSEInstrInfo:: +storeRegToStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned SrcReg, bool isKill, int FI, + const TargetRegisterClass *RC, const TargetRegisterInfo *TRI, + int64_t Offset) const { + DebugLoc DL; + if (I != MBB.end()) DL = I->getDebugLoc(); + MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOStore); + + unsigned Opc = 0; + + if (Mips::GPR32RegClass.hasSubClassEq(RC)) + Opc = Mips::SW; + else if (Mips::GPR64RegClass.hasSubClassEq(RC)) + Opc = Mips::SD; + else if (Mips::ACC64RegClass.hasSubClassEq(RC)) + Opc = Mips::STORE_ACC64; + else if (Mips::ACC64DSPRegClass.hasSubClassEq(RC)) + Opc = Mips::STORE_ACC64DSP; + else if (Mips::ACC128RegClass.hasSubClassEq(RC)) + Opc = Mips::STORE_ACC128; + else if (Mips::DSPCCRegClass.hasSubClassEq(RC)) + Opc = Mips::STORE_CCOND_DSP; + else if (Mips::FGR32RegClass.hasSubClassEq(RC)) + Opc = Mips::SWC1; + else if (Mips::AFGR64RegClass.hasSubClassEq(RC)) + Opc = Mips::SDC1; + else if (Mips::FGR64RegClass.hasSubClassEq(RC)) + Opc = Mips::SDC164; + else if (RC->hasType(MVT::v16i8)) + Opc = Mips::ST_B; + else if (RC->hasType(MVT::v8i16) || RC->hasType(MVT::v8f16)) + Opc = Mips::ST_H; + else if (RC->hasType(MVT::v4i32) || RC->hasType(MVT::v4f32)) + Opc = Mips::ST_W; + else if (RC->hasType(MVT::v2i64) || RC->hasType(MVT::v2f64)) + Opc = Mips::ST_D; + + assert(Opc && "Register class not handled!"); + BuildMI(MBB, I, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill)) + .addFrameIndex(FI).addImm(Offset).addMemOperand(MMO); +} + +void MipsSEInstrInfo:: +loadRegFromStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned DestReg, int FI, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, int64_t Offset) const { + DebugLoc DL; + if (I != MBB.end()) DL = I->getDebugLoc(); + MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOLoad); + unsigned Opc = 0; + + if (Mips::GPR32RegClass.hasSubClassEq(RC)) + Opc = Mips::LW; + else if (Mips::GPR64RegClass.hasSubClassEq(RC)) + Opc = Mips::LD; + else if (Mips::ACC64RegClass.hasSubClassEq(RC)) + Opc = Mips::LOAD_ACC64; + else if (Mips::ACC64DSPRegClass.hasSubClassEq(RC)) + Opc = Mips::LOAD_ACC64DSP; + else if (Mips::ACC128RegClass.hasSubClassEq(RC)) + Opc = Mips::LOAD_ACC128; + else if (Mips::DSPCCRegClass.hasSubClassEq(RC)) + Opc = Mips::LOAD_CCOND_DSP; + else if (Mips::FGR32RegClass.hasSubClassEq(RC)) + Opc = Mips::LWC1; + else if (Mips::AFGR64RegClass.hasSubClassEq(RC)) + Opc = Mips::LDC1; + else if (Mips::FGR64RegClass.hasSubClassEq(RC)) + Opc = Mips::LDC164; + else if (RC->hasType(MVT::v16i8)) + Opc = Mips::LD_B; + else if (RC->hasType(MVT::v8i16) || RC->hasType(MVT::v8f16)) + Opc = Mips::LD_H; + else if (RC->hasType(MVT::v4i32) || RC->hasType(MVT::v4f32)) + Opc = Mips::LD_W; + else if (RC->hasType(MVT::v2i64) || RC->hasType(MVT::v2f64)) + Opc = Mips::LD_D; + + assert(Opc && "Register class not handled!"); + BuildMI(MBB, I, DL, get(Opc), DestReg).addFrameIndex(FI).addImm(Offset) + .addMemOperand(MMO); +} + +bool MipsSEInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { + MachineBasicBlock &MBB = *MI->getParent(); + + switch(MI->getDesc().getOpcode()) { + default: + return false; + case Mips::RetRA: + expandRetRA(MBB, MI, Mips::RET); + break; + case Mips::PseudoMFHI: + expandPseudoMFHiLo(MBB, MI, Mips::MFHI); + break; + case Mips::PseudoMFLO: + expandPseudoMFHiLo(MBB, MI, Mips::MFLO); + break; + case Mips::PseudoMFHI64: + expandPseudoMFHiLo(MBB, MI, Mips::MFHI64); + break; + case Mips::PseudoMFLO64: + expandPseudoMFHiLo(MBB, MI, Mips::MFLO64); + break; + case Mips::PseudoMTLOHI: + expandPseudoMTLoHi(MBB, MI, Mips::MTLO, Mips::MTHI, false); + break; + case Mips::PseudoMTLOHI64: + expandPseudoMTLoHi(MBB, MI, Mips::MTLO64, Mips::MTHI64, false); + break; + case Mips::PseudoMTLOHI_DSP: + expandPseudoMTLoHi(MBB, MI, Mips::MTLO_DSP, Mips::MTHI_DSP, true); + break; + case Mips::PseudoCVT_S_W: + expandCvtFPInt(MBB, MI, Mips::CVT_S_W, Mips::MTC1, false); + break; + case Mips::PseudoCVT_D32_W: + expandCvtFPInt(MBB, MI, Mips::CVT_D32_W, Mips::MTC1, false); + break; + case Mips::PseudoCVT_S_L: + expandCvtFPInt(MBB, MI, Mips::CVT_S_L, Mips::DMTC1, true); + break; + case Mips::PseudoCVT_D64_W: + expandCvtFPInt(MBB, MI, Mips::CVT_D64_W, Mips::MTC1, true); + break; + case Mips::PseudoCVT_D64_L: + expandCvtFPInt(MBB, MI, Mips::CVT_D64_L, Mips::DMTC1, true); + break; + case Mips::BuildPairF64: + expandBuildPairF64(MBB, MI, false); + break; + case Mips::BuildPairF64_64: + expandBuildPairF64(MBB, MI, true); + break; + case Mips::ExtractElementF64: + expandExtractElementF64(MBB, MI, false); + break; + case Mips::ExtractElementF64_64: + expandExtractElementF64(MBB, MI, true); + break; + case Mips::MIPSeh_return32: + case Mips::MIPSeh_return64: + expandEhReturn(MBB, MI); + break; + } + + MBB.erase(MI); + return true; +} + +/// getOppositeBranchOpc - Return the inverse of the specified +/// opcode, e.g. turning BEQ to BNE. +unsigned MipsSEInstrInfo::getOppositeBranchOpc(unsigned Opc) const { + switch (Opc) { + default: llvm_unreachable("Illegal opcode!"); + case Mips::BEQ: return Mips::BNE; + case Mips::BNE: return Mips::BEQ; + case Mips::BGTZ: return Mips::BLEZ; + case Mips::BGEZ: return Mips::BLTZ; + case Mips::BLTZ: return Mips::BGEZ; + case Mips::BLEZ: return Mips::BGTZ; + case Mips::BEQ64: return Mips::BNE64; + case Mips::BNE64: return Mips::BEQ64; + case Mips::BGTZ64: return Mips::BLEZ64; + case Mips::BGEZ64: return Mips::BLTZ64; + case Mips::BLTZ64: return Mips::BGEZ64; + case Mips::BLEZ64: return Mips::BGTZ64; + case Mips::BC1T: return Mips::BC1F; + case Mips::BC1F: return Mips::BC1T; + } +} + +/// Adjust SP by Amount bytes. +void MipsSEInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + const MipsSubtarget &STI = TM.getSubtarget<MipsSubtarget>(); + DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); + unsigned ADDu = STI.isABI_N64() ? Mips::DADDu : Mips::ADDu; + unsigned ADDiu = STI.isABI_N64() ? Mips::DADDiu : Mips::ADDiu; + + if (isInt<16>(Amount))// addi sp, sp, amount + BuildMI(MBB, I, DL, get(ADDiu), SP).addReg(SP).addImm(Amount); + else { // Expand immediate that doesn't fit in 16-bit. + unsigned Reg = loadImmediate(Amount, MBB, I, DL, 0); + BuildMI(MBB, I, DL, get(ADDu), SP).addReg(SP).addReg(Reg, RegState::Kill); + } +} + +/// This function generates the sequence of instructions needed to get the +/// result of adding register REG and immediate IMM. +unsigned +MipsSEInstrInfo::loadImmediate(int64_t Imm, MachineBasicBlock &MBB, + MachineBasicBlock::iterator II, DebugLoc DL, + unsigned *NewImm) const { + MipsAnalyzeImmediate AnalyzeImm; + const MipsSubtarget &STI = TM.getSubtarget<MipsSubtarget>(); + MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); + unsigned Size = STI.isABI_N64() ? 64 : 32; + unsigned LUi = STI.isABI_N64() ? Mips::LUi64 : Mips::LUi; + unsigned ZEROReg = STI.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO; + const TargetRegisterClass *RC = STI.isABI_N64() ? + &Mips::GPR64RegClass : &Mips::GPR32RegClass; + bool LastInstrIsADDiu = NewImm; + + const MipsAnalyzeImmediate::InstSeq &Seq = + AnalyzeImm.Analyze(Imm, Size, LastInstrIsADDiu); + MipsAnalyzeImmediate::InstSeq::const_iterator Inst = Seq.begin(); + + assert(Seq.size() && (!LastInstrIsADDiu || (Seq.size() > 1))); + + // The first instruction can be a LUi, which is different from other + // instructions (ADDiu, ORI and SLL) in that it does not have a register + // operand. + unsigned Reg = RegInfo.createVirtualRegister(RC); + + if (Inst->Opc == LUi) + BuildMI(MBB, II, DL, get(LUi), Reg).addImm(SignExtend64<16>(Inst->ImmOpnd)); + else + BuildMI(MBB, II, DL, get(Inst->Opc), Reg).addReg(ZEROReg) + .addImm(SignExtend64<16>(Inst->ImmOpnd)); + + // Build the remaining instructions in Seq. + for (++Inst; Inst != Seq.end() - LastInstrIsADDiu; ++Inst) + BuildMI(MBB, II, DL, get(Inst->Opc), Reg).addReg(Reg, RegState::Kill) + .addImm(SignExtend64<16>(Inst->ImmOpnd)); + + if (LastInstrIsADDiu) + *NewImm = Inst->ImmOpnd; + + return Reg; +} + +unsigned MipsSEInstrInfo::getAnalyzableBrOpc(unsigned Opc) const { + return (Opc == Mips::BEQ || Opc == Mips::BNE || Opc == Mips::BGTZ || + Opc == Mips::BGEZ || Opc == Mips::BLTZ || Opc == Mips::BLEZ || + Opc == Mips::BEQ64 || Opc == Mips::BNE64 || Opc == Mips::BGTZ64 || + Opc == Mips::BGEZ64 || Opc == Mips::BLTZ64 || Opc == Mips::BLEZ64 || + Opc == Mips::BC1T || Opc == Mips::BC1F || Opc == Mips::B || + Opc == Mips::J) ? + Opc : 0; +} + +void MipsSEInstrInfo::expandRetRA(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned Opc) const { + BuildMI(MBB, I, I->getDebugLoc(), get(Opc)).addReg(Mips::RA); +} + +std::pair<bool, bool> +MipsSEInstrInfo::compareOpndSize(unsigned Opc, + const MachineFunction &MF) const { + const MCInstrDesc &Desc = get(Opc); + assert(Desc.NumOperands == 2 && "Unary instruction expected."); + const MipsRegisterInfo *RI = &getRegisterInfo(); + unsigned DstRegSize = getRegClass(Desc, 0, RI, MF)->getSize(); + unsigned SrcRegSize = getRegClass(Desc, 1, RI, MF)->getSize(); + + return std::make_pair(DstRegSize > SrcRegSize, DstRegSize < SrcRegSize); +} + +void MipsSEInstrInfo::expandPseudoMFHiLo(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned NewOpc) const { + BuildMI(MBB, I, I->getDebugLoc(), get(NewOpc), I->getOperand(0).getReg()); +} + +void MipsSEInstrInfo::expandPseudoMTLoHi(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned LoOpc, + unsigned HiOpc, + bool HasExplicitDef) const { + // Expand + // lo_hi pseudomtlohi $gpr0, $gpr1 + // to these two instructions: + // mtlo $gpr0 + // mthi $gpr1 + + DebugLoc DL = I->getDebugLoc(); + const MachineOperand &SrcLo = I->getOperand(1), &SrcHi = I->getOperand(2); + MachineInstrBuilder LoInst = BuildMI(MBB, I, DL, get(LoOpc)); + MachineInstrBuilder HiInst = BuildMI(MBB, I, DL, get(HiOpc)); + LoInst.addReg(SrcLo.getReg(), getKillRegState(SrcLo.isKill())); + HiInst.addReg(SrcHi.getReg(), getKillRegState(SrcHi.isKill())); + + // Add lo/hi registers if the mtlo/hi instructions created have explicit + // def registers. + if (HasExplicitDef) { + unsigned DstReg = I->getOperand(0).getReg(); + unsigned DstLo = getRegisterInfo().getSubReg(DstReg, Mips::sub_lo); + unsigned DstHi = getRegisterInfo().getSubReg(DstReg, Mips::sub_hi); + LoInst.addReg(DstLo, RegState::Define); + HiInst.addReg(DstHi, RegState::Define); + } +} + +void MipsSEInstrInfo::expandCvtFPInt(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned CvtOpc, unsigned MovOpc, + bool IsI64) const { + const MCInstrDesc &CvtDesc = get(CvtOpc), &MovDesc = get(MovOpc); + const MachineOperand &Dst = I->getOperand(0), &Src = I->getOperand(1); + unsigned DstReg = Dst.getReg(), SrcReg = Src.getReg(), TmpReg = DstReg; + unsigned KillSrc = getKillRegState(Src.isKill()); + DebugLoc DL = I->getDebugLoc(); + bool DstIsLarger, SrcIsLarger; + + tie(DstIsLarger, SrcIsLarger) = compareOpndSize(CvtOpc, *MBB.getParent()); + + if (DstIsLarger) + TmpReg = getRegisterInfo().getSubReg(DstReg, Mips::sub_lo); + + if (SrcIsLarger) + DstReg = getRegisterInfo().getSubReg(DstReg, Mips::sub_lo); + + BuildMI(MBB, I, DL, MovDesc, TmpReg).addReg(SrcReg, KillSrc); + BuildMI(MBB, I, DL, CvtDesc, DstReg).addReg(TmpReg, RegState::Kill); +} + +void MipsSEInstrInfo::expandExtractElementF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + bool FP64) const { + unsigned DstReg = I->getOperand(0).getReg(); + unsigned SrcReg = I->getOperand(1).getReg(); + unsigned N = I->getOperand(2).getImm(); + DebugLoc dl = I->getDebugLoc(); + + assert(N < 2 && "Invalid immediate"); + unsigned SubIdx = N ? Mips::sub_hi : Mips::sub_lo; + unsigned SubReg = getRegisterInfo().getSubReg(SrcReg, SubIdx); + + if (SubIdx == Mips::sub_hi && FP64) + BuildMI(MBB, I, dl, get(Mips::MFHC1), DstReg).addReg(SubReg); + else + BuildMI(MBB, I, dl, get(Mips::MFC1), DstReg).addReg(SubReg); +} + +void MipsSEInstrInfo::expandBuildPairF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + bool FP64) const { + unsigned DstReg = I->getOperand(0).getReg(); + unsigned LoReg = I->getOperand(1).getReg(), HiReg = I->getOperand(2).getReg(); + const MCInstrDesc& Mtc1Tdd = get(Mips::MTC1); + DebugLoc dl = I->getDebugLoc(); + const TargetRegisterInfo &TRI = getRegisterInfo(); + + // For FP32 mode: + // mtc1 Lo, $fp + // mtc1 Hi, $fp + 1 + // For FP64 mode: + // mtc1 Lo, $fp + // mthc1 Hi, $fp + + BuildMI(MBB, I, dl, Mtc1Tdd, TRI.getSubReg(DstReg, Mips::sub_lo)) + .addReg(LoReg); + + if (FP64) + BuildMI(MBB, I, dl, get(Mips::MTHC1), TRI.getSubReg(DstReg, Mips::sub_hi)) + .addReg(HiReg); + else + BuildMI(MBB, I, dl, Mtc1Tdd, TRI.getSubReg(DstReg, Mips::sub_hi)) + .addReg(HiReg); +} + +void MipsSEInstrInfo::expandEhReturn(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + // This pseudo instruction is generated as part of the lowering of + // ISD::EH_RETURN. We convert it to a stack increment by OffsetReg, and + // indirect jump to TargetReg + const MipsSubtarget &STI = TM.getSubtarget<MipsSubtarget>(); + unsigned ADDU = STI.isABI_N64() ? Mips::DADDu : Mips::ADDu; + unsigned JR = STI.isABI_N64() ? Mips::JR64 : Mips::JR; + unsigned SP = STI.isABI_N64() ? Mips::SP_64 : Mips::SP; + unsigned RA = STI.isABI_N64() ? Mips::RA_64 : Mips::RA; + unsigned T9 = STI.isABI_N64() ? Mips::T9_64 : Mips::T9; + unsigned ZERO = STI.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO; + unsigned OffsetReg = I->getOperand(0).getReg(); + unsigned TargetReg = I->getOperand(1).getReg(); + + // addu $ra, $v0, $zero + // addu $sp, $sp, $v1 + // jr $ra + if (TM.getRelocationModel() == Reloc::PIC_) + BuildMI(MBB, I, I->getDebugLoc(), TM.getInstrInfo()->get(ADDU), T9) + .addReg(TargetReg).addReg(ZERO); + BuildMI(MBB, I, I->getDebugLoc(), TM.getInstrInfo()->get(ADDU), RA) + .addReg(TargetReg).addReg(ZERO); + BuildMI(MBB, I, I->getDebugLoc(), TM.getInstrInfo()->get(ADDU), SP) + .addReg(SP).addReg(OffsetReg); + BuildMI(MBB, I, I->getDebugLoc(), TM.getInstrInfo()->get(JR)).addReg(RA); +} + +const MipsInstrInfo *llvm::createMipsSEInstrInfo(MipsTargetMachine &TM) { + return new MipsSEInstrInfo(TM); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.h b/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.h new file mode 100644 index 000000000000..6d2dd901f33b --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSEInstrInfo.h @@ -0,0 +1,120 @@ +//===-- MipsSEInstrInfo.h - Mips32/64 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 Mips32/64 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSSEINSTRUCTIONINFO_H +#define MIPSSEINSTRUCTIONINFO_H + +#include "MipsInstrInfo.h" +#include "MipsSERegisterInfo.h" + +namespace llvm { + +class MipsSEInstrInfo : public MipsInstrInfo { + const MipsSERegisterInfo RI; + bool IsN64; + +public: + explicit MipsSEInstrInfo(MipsTargetMachine &TM); + + virtual const MipsRegisterInfo &getRegisterInfo() const; + + /// 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; + + virtual void copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const; + + virtual void storeRegToStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const; + + virtual void loadRegFromStack(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + int64_t Offset) const; + + virtual bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const; + + virtual unsigned getOppositeBranchOpc(unsigned Opc) const; + + /// Adjust SP by Amount bytes. + void adjustStackPtr(unsigned SP, int64_t Amount, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + /// Emit a series of instructions to load an immediate. If NewImm is a + /// non-NULL parameter, the last instruction is not emitted, but instead + /// its immediate operand is returned in NewImm. + unsigned loadImmediate(int64_t Imm, MachineBasicBlock &MBB, + MachineBasicBlock::iterator II, DebugLoc DL, + unsigned *NewImm) const; + +private: + virtual unsigned getAnalyzableBrOpc(unsigned Opc) const; + + void expandRetRA(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned Opc) const; + + std::pair<bool, bool> compareOpndSize(unsigned Opc, + const MachineFunction &MF) const; + + void expandPseudoMFHiLo(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned NewOpc) const; + + void expandPseudoMTLoHi(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned LoOpc, unsigned HiOpc, + bool HasExplicitDef) const; + + /// Expand pseudo Int-to-FP conversion instructions. + /// + /// For example, the following pseudo instruction + /// PseudoCVT_D32_W D2, A5 + /// gets expanded into these two instructions: + /// MTC1 F4, A5 + /// CVT_D32_W D2, F4 + /// + /// We do this expansion post-RA to avoid inserting a floating point copy + /// instruction between MTC1 and CVT_D32_W. + void expandCvtFPInt(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned CvtOpc, unsigned MovOpc, bool IsI64) const; + + void expandExtractElementF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, bool FP64) const; + void expandBuildPairF64(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, bool FP64) const; + void expandEhReturn(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.cpp new file mode 100644 index 000000000000..2d440840aaff --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.cpp @@ -0,0 +1,179 @@ +//===-- MipsSERegisterInfo.cpp - MIPS32/64 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 MIPS32/64 implementation of the TargetRegisterInfo +// class. +// +//===----------------------------------------------------------------------===// + +#include "MipsSERegisterInfo.h" +#include "Mips.h" +#include "MipsAnalyzeImmediate.h" +#include "MipsMachineFunction.h" +#include "MipsSEInstrInfo.h" +#include "MipsSubtarget.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/DebugInfo.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +MipsSERegisterInfo::MipsSERegisterInfo(const MipsSubtarget &ST) + : MipsRegisterInfo(ST) {} + +bool MipsSERegisterInfo:: +requiresRegisterScavenging(const MachineFunction &MF) const { + return true; +} + +bool MipsSERegisterInfo:: +requiresFrameIndexScavenging(const MachineFunction &MF) const { + return true; +} + +const TargetRegisterClass * +MipsSERegisterInfo::intRegClass(unsigned Size) const { + if (Size == 4) + return &Mips::GPR32RegClass; + + assert(Size == 8); + return &Mips::GPR64RegClass; +} + +/// Determine whether a given opcode is an MSA load/store (supporting 10-bit +/// offsets) or a non-MSA load/store (supporting 16-bit offsets). +static inline bool isMSALoadOrStore(const unsigned Opcode) { + switch (Opcode) { + case Mips::LD_B: + case Mips::LD_H: + case Mips::LD_W: + case Mips::LD_D: + case Mips::ST_B: + case Mips::ST_H: + case Mips::ST_W: + case Mips::ST_D: + return true; + default: + return false; + } +} + +void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II, + unsigned OpNo, int FrameIndex, + uint64_t StackSize, + int64_t SPOffset) const { + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); + + const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); + int MinCSFI = 0; + int MaxCSFI = -1; + + if (CSI.size()) { + MinCSFI = CSI[0].getFrameIdx(); + MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); + } + + bool EhDataRegFI = MipsFI->isEhDataRegFI(FrameIndex); + + // The following stack frame objects are always referenced relative to $sp: + // 1. Outgoing arguments. + // 2. Pointer to dynamically allocated stack space. + // 3. Locations for callee-saved registers. + // 4. Locations for eh data registers. + // Everything else is referenced relative to whatever register + // getFrameRegister() returns. + unsigned FrameReg; + + if ((FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI) || EhDataRegFI) + FrameReg = Subtarget.isABI_N64() ? Mips::SP_64 : Mips::SP; + else + FrameReg = getFrameRegister(MF); + + // Calculate final offset. + // - There is no need to change the offset if the frame object is one of the + // following: an outgoing argument, pointer to a dynamically allocated + // stack space or a $gp restore location, + // - If the frame object is any of the following, its offset must be adjusted + // by adding the size of the stack: + // incoming argument, callee-saved register location or local variable. + bool IsKill = false; + int64_t Offset; + + Offset = SPOffset + (int64_t)StackSize; + Offset += MI.getOperand(OpNo + 1).getImm(); + + DEBUG(errs() << "Offset : " << Offset << "\n" << "<--------->\n"); + + if (!MI.isDebugValue()) { + // Make sure Offset fits within the field available. + // For MSA instructions, this is a 10-bit signed immediate, otherwise it is + // a 16-bit signed immediate. + unsigned OffsetBitSize = isMSALoadOrStore(MI.getOpcode()) ? 10 : 16; + + if (OffsetBitSize == 10 && !isInt<10>(Offset) && isInt<16>(Offset)) { + // If we have an offset that needs to fit into a signed 10-bit immediate + // and doesn't, but does fit into 16-bits then use an ADDiu + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc DL = II->getDebugLoc(); + unsigned ADDiu = Subtarget.isABI_N64() ? Mips::DADDiu : Mips::ADDiu; + const TargetRegisterClass *RC = + Subtarget.isABI_N64() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; + MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); + unsigned Reg = RegInfo.createVirtualRegister(RC); + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo *>( + MBB.getParent()->getTarget().getInstrInfo()); + BuildMI(MBB, II, DL, TII.get(ADDiu), Reg).addReg(FrameReg).addImm(Offset); + + FrameReg = Reg; + Offset = 0; + IsKill = true; + } else if (!isInt<16>(Offset)) { + // Otherwise split the offset into 16-bit pieces and add it in multiple + // instructions. + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc DL = II->getDebugLoc(); + unsigned ADDu = Subtarget.isABI_N64() ? Mips::DADDu : Mips::ADDu; + unsigned NewImm = 0; + const MipsSEInstrInfo &TII = + *static_cast<const MipsSEInstrInfo *>( + MBB.getParent()->getTarget().getInstrInfo()); + unsigned Reg = TII.loadImmediate(Offset, MBB, II, DL, + OffsetBitSize == 16 ? &NewImm : NULL); + BuildMI(MBB, II, DL, TII.get(ADDu), Reg).addReg(FrameReg) + .addReg(Reg, RegState::Kill); + + FrameReg = Reg; + Offset = SignExtend64<16>(NewImm); + IsKill = true; + } + } + + MI.getOperand(OpNo).ChangeToRegister(FrameReg, false, false, IsKill); + MI.getOperand(OpNo + 1).ChangeToImmediate(Offset); +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.h b/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.h new file mode 100644 index 000000000000..76cdd9d230d3 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSERegisterInfo.h @@ -0,0 +1,41 @@ +//===-- MipsSERegisterInfo.h - Mips32/64 Register 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 Mips32/64 implementation of the TargetRegisterInfo +// class. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSSEREGISTERINFO_H +#define MIPSSEREGISTERINFO_H + +#include "MipsRegisterInfo.h" + +namespace llvm { +class MipsSEInstrInfo; + +class MipsSERegisterInfo : public MipsRegisterInfo { +public: + MipsSERegisterInfo(const MipsSubtarget &Subtarget); + + bool requiresRegisterScavenging(const MachineFunction &MF) const; + + bool requiresFrameIndexScavenging(const MachineFunction &MF) const; + + virtual const TargetRegisterClass *intRegClass(unsigned Size) const; + +private: + virtual void eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo, + int FrameIndex, uint64_t StackSize, + int64_t SPOffset) const; +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsSchedule.td b/contrib/llvm/lib/Target/Mips/MipsSchedule.td new file mode 100644 index 000000000000..2779064c4149 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSchedule.td @@ -0,0 +1,76 @@ +//===-- MipsSchedule.td - Mips Scheduling Definitions ------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Functional units across Mips chips sets. Based on GCC/Mips backend files. +//===----------------------------------------------------------------------===// +def ALU : FuncUnit; +def IMULDIV : FuncUnit; + +//===----------------------------------------------------------------------===// +// Instruction Itinerary classes used for Mips +//===----------------------------------------------------------------------===// +def IIAlu : InstrItinClass; +def IIArith : InstrItinClass; +def IILogic : InstrItinClass; +def IILoad : InstrItinClass; +def IIStore : InstrItinClass; +def IIXfer : InstrItinClass; +def IIBranch : InstrItinClass; +def IIHiLo : InstrItinClass; +def IIImul : InstrItinClass; +def IIImult : InstrItinClass; +def IIIdiv : InstrItinClass; +def IIseb : InstrItinClass; +def IIslt : InstrItinClass; +def IIFcvt : InstrItinClass; +def IIFmove : InstrItinClass; +def IIFcmp : InstrItinClass; +def IIFadd : InstrItinClass; +def IIFmulSingle : InstrItinClass; +def IIFmulDouble : InstrItinClass; +def IIFdivSingle : InstrItinClass; +def IIFdivDouble : InstrItinClass; +def IIFsqrtSingle : InstrItinClass; +def IIFsqrtDouble : InstrItinClass; +def IIFrecipFsqrtStep : InstrItinClass; +def IIFLoad : InstrItinClass; +def IIFStore : InstrItinClass; +def IIFmoveC1 : InstrItinClass; +def IIPseudo : InstrItinClass; + +//===----------------------------------------------------------------------===// +// Mips Generic instruction itineraries. +//===----------------------------------------------------------------------===// +def MipsGenericItineraries : ProcessorItineraries<[ALU, IMULDIV], [], [ + InstrItinData<IIAlu , [InstrStage<1, [ALU]>]>, + InstrItinData<IIArith , [InstrStage<1, [ALU]>]>, + InstrItinData<IILogic , [InstrStage<1, [ALU]>]>, + InstrItinData<IILoad , [InstrStage<3, [ALU]>]>, + InstrItinData<IIStore , [InstrStage<1, [ALU]>]>, + InstrItinData<IIXfer , [InstrStage<2, [ALU]>]>, + InstrItinData<IIBranch , [InstrStage<1, [ALU]>]>, + InstrItinData<IIHiLo , [InstrStage<1, [IMULDIV]>]>, + InstrItinData<IIImul , [InstrStage<17, [IMULDIV]>]>, + InstrItinData<IIIdiv , [InstrStage<38, [IMULDIV]>]>, + InstrItinData<IIFcvt , [InstrStage<1, [ALU]>]>, + InstrItinData<IIFmove , [InstrStage<2, [ALU]>]>, + InstrItinData<IIFcmp , [InstrStage<3, [ALU]>]>, + InstrItinData<IIFadd , [InstrStage<4, [ALU]>]>, + InstrItinData<IIFmulSingle , [InstrStage<7, [ALU]>]>, + InstrItinData<IIFmulDouble , [InstrStage<8, [ALU]>]>, + InstrItinData<IIFdivSingle , [InstrStage<23, [ALU]>]>, + InstrItinData<IIFdivDouble , [InstrStage<36, [ALU]>]>, + InstrItinData<IIFsqrtSingle , [InstrStage<54, [ALU]>]>, + InstrItinData<IIFsqrtDouble , [InstrStage<12, [ALU]>]>, + InstrItinData<IIFrecipFsqrtStep , [InstrStage<5, [ALU]>]>, + InstrItinData<IIFLoad , [InstrStage<3, [ALU]>]>, + InstrItinData<IIFStore , [InstrStage<1, [ALU]>]>, + InstrItinData<IIFmoveC1 , [InstrStage<2, [ALU]>]> +]>; diff --git a/contrib/llvm/lib/Target/Mips/MipsSelectionDAGInfo.cpp b/contrib/llvm/lib/Target/Mips/MipsSelectionDAGInfo.cpp new file mode 100644 index 000000000000..e4d70fcec591 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSelectionDAGInfo.cpp @@ -0,0 +1,23 @@ +//===-- MipsSelectionDAGInfo.cpp - Mips 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 MipsSelectionDAGInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-selectiondag-info" +#include "MipsTargetMachine.h" +using namespace llvm; + +MipsSelectionDAGInfo::MipsSelectionDAGInfo(const MipsTargetMachine &TM) + : TargetSelectionDAGInfo(TM) { +} + +MipsSelectionDAGInfo::~MipsSelectionDAGInfo() { +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSelectionDAGInfo.h b/contrib/llvm/lib/Target/Mips/MipsSelectionDAGInfo.h new file mode 100644 index 000000000000..6cafb558b35a --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSelectionDAGInfo.h @@ -0,0 +1,31 @@ +//===-- MipsSelectionDAGInfo.h - Mips 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 Mips subclass for TargetSelectionDAGInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSSELECTIONDAGINFO_H +#define MIPSSELECTIONDAGINFO_H + +#include "llvm/Target/TargetSelectionDAGInfo.h" + +namespace llvm { + +class MipsTargetMachine; + +class MipsSelectionDAGInfo : public TargetSelectionDAGInfo { +public: + explicit MipsSelectionDAGInfo(const MipsTargetMachine &TM); + ~MipsSelectionDAGInfo(); +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsSubtarget.cpp b/contrib/llvm/lib/Target/Mips/MipsSubtarget.cpp new file mode 100644 index 000000000000..0a81072b0858 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSubtarget.cpp @@ -0,0 +1,176 @@ +//===-- MipsSubtarget.cpp - Mips 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 Mips specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mips-subtarget" + +#include "MipsMachineFunction.h" +#include "MipsSubtarget.h" +#include "MipsTargetMachine.h" +#include "Mips.h" +#include "MipsRegisterInfo.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" + +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "MipsGenSubtargetInfo.inc" + + +using namespace llvm; + +// FIXME: Maybe this should be on by default when Mips16 is specified +// +static cl::opt<bool> Mixed16_32( + "mips-mixed-16-32", + cl::init(false), + cl::desc("Allow for a mixture of Mips16 " + "and Mips32 code in a single source file"), + cl::Hidden); + +static cl::opt<bool> Mips_Os16( + "mips-os16", + cl::init(false), + cl::desc("Compile all functions that don' use " + "floating point as Mips 16"), + cl::Hidden); + +static cl::opt<bool> +Mips16HardFloat("mips16-hard-float", cl::NotHidden, + cl::desc("MIPS: mips16 hard float enable."), + cl::init(false)); + +static cl::opt<bool> +Mips16ConstantIslands( + "mips16-constant-islands", cl::Hidden, + cl::desc("MIPS: mips16 constant islands enable. experimental feature"), + cl::init(false)); + +void MipsSubtarget::anchor() { } + +MipsSubtarget::MipsSubtarget(const std::string &TT, const std::string &CPU, + const std::string &FS, bool little, + Reloc::Model _RM, MipsTargetMachine *_TM) : + MipsGenSubtargetInfo(TT, CPU, FS), + MipsArchVersion(Mips32), MipsABI(UnknownABI), IsLittle(little), + IsSingleFloat(false), IsFP64bit(false), IsGP64bit(false), HasVFPU(false), + IsLinux(true), HasSEInReg(false), HasCondMov(false), HasSwap(false), + HasBitCount(false), HasFPIdx(false), + InMips16Mode(false), InMips16HardFloat(Mips16HardFloat), + InMicroMipsMode(false), HasDSP(false), HasDSPR2(false), + AllowMixed16_32(Mixed16_32 | Mips_Os16), Os16(Mips_Os16), HasMSA(false), + RM(_RM), OverrideMode(NoOverride), TM(_TM) +{ + std::string CPUName = CPU; + if (CPUName.empty()) + CPUName = "mips32"; + + // Parse features string. + ParseSubtargetFeatures(CPUName, FS); + + PreviousInMips16Mode = InMips16Mode; + + // Initialize scheduling itinerary for the specified CPU. + InstrItins = getInstrItineraryForCPU(CPUName); + + // Set MipsABI if it hasn't been set yet. + if (MipsABI == UnknownABI) + MipsABI = hasMips64() ? N64 : O32; + + // Check if Architecture and ABI are compatible. + assert(((!hasMips64() && (isABI_O32() || isABI_EABI())) || + (hasMips64() && (isABI_N32() || isABI_N64()))) && + "Invalid Arch & ABI pair."); + + if (hasMSA() && !isFP64bit()) + report_fatal_error("MSA requires a 64-bit FPU register file (FR=1 mode). " + "See -mattr=+fp64.", + false); + + // Is the target system Linux ? + if (TT.find("linux") == std::string::npos) + IsLinux = false; + + // Set UseSmallSection. + UseSmallSection = !IsLinux && (RM == Reloc::Static); + // set some subtarget specific features + if (inMips16Mode()) + HasBitCount=false; +} + +bool +MipsSubtarget::enablePostRAScheduler(CodeGenOpt::Level OptLevel, + TargetSubtargetInfo::AntiDepBreakMode &Mode, + RegClassVector &CriticalPathRCs) const { + Mode = TargetSubtargetInfo::ANTIDEP_NONE; + CriticalPathRCs.clear(); + CriticalPathRCs.push_back(hasMips64() ? + &Mips::GPR64RegClass : &Mips::GPR32RegClass); + return OptLevel >= CodeGenOpt::Aggressive; +} + +//FIXME: This logic for reseting the subtarget along with +// the helper classes can probably be simplified but there are a lot of +// cases so we will defer rewriting this to later. +// +void MipsSubtarget::resetSubtarget(MachineFunction *MF) { + bool ChangeToMips16 = false, ChangeToNoMips16 = false; + DEBUG(dbgs() << "resetSubtargetFeatures" << "\n"); + AttributeSet FnAttrs = MF->getFunction()->getAttributes(); + ChangeToMips16 = FnAttrs.hasAttribute(AttributeSet::FunctionIndex, + "mips16"); + ChangeToNoMips16 = FnAttrs.hasAttribute(AttributeSet::FunctionIndex, + "nomips16"); + assert (!(ChangeToMips16 & ChangeToNoMips16) && + "mips16 and nomips16 specified on the same function"); + if (ChangeToMips16) { + if (PreviousInMips16Mode) + return; + OverrideMode = Mips16Override; + PreviousInMips16Mode = true; + TM->setHelperClassesMips16(); + return; + } else if (ChangeToNoMips16) { + if (!PreviousInMips16Mode) + return; + OverrideMode = NoMips16Override; + PreviousInMips16Mode = false; + TM->setHelperClassesMipsSE(); + return; + } else { + if (OverrideMode == NoOverride) + return; + OverrideMode = NoOverride; + DEBUG(dbgs() << "back to default" << "\n"); + if (inMips16Mode() && !PreviousInMips16Mode) { + TM->setHelperClassesMips16(); + PreviousInMips16Mode = true; + } else if (!inMips16Mode() && PreviousInMips16Mode) { + TM->setHelperClassesMipsSE(); + PreviousInMips16Mode = false; + } + return; + } +} + +bool MipsSubtarget::mipsSEUsesSoftFloat() const { + return TM->Options.UseSoftFloat && !InMips16HardFloat; +} + +bool MipsSubtarget::useConstantIslands() { + DEBUG(dbgs() << "use constant islands " << Mips16ConstantIslands << "\n"); + return Mips16ConstantIslands; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsSubtarget.h b/contrib/llvm/lib/Target/Mips/MipsSubtarget.h new file mode 100644 index 000000000000..6b2ab1238b87 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsSubtarget.h @@ -0,0 +1,235 @@ +//===-- MipsSubtarget.h - Define Subtarget for the Mips ---------*- 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 Mips specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSSUBTARGET_H +#define MIPSSUBTARGET_H + +#include "MCTargetDesc/MipsReginfo.h" +#include "llvm/MC/MCInstrItineraries.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +#include <string> + +#define GET_SUBTARGETINFO_HEADER +#include "MipsGenSubtargetInfo.inc" + +namespace llvm { +class StringRef; + +class MipsTargetMachine; + +class MipsSubtarget : public MipsGenSubtargetInfo { + virtual void anchor(); + +public: + // NOTE: O64 will not be supported. + enum MipsABIEnum { + UnknownABI, O32, N32, N64, EABI + }; + +protected: + + enum MipsArchEnum { + Mips32, Mips32r2, Mips64, Mips64r2 + }; + + // Mips architecture version + MipsArchEnum MipsArchVersion; + + // Mips supported ABIs + MipsABIEnum MipsABI; + + // IsLittle - The target is Little Endian + bool IsLittle; + + // IsSingleFloat - The target only supports single precision float + // point operations. This enable the target to use all 32 32-bit + // floating point registers instead of only using even ones. + bool IsSingleFloat; + + // IsFP64bit - The target processor has 64-bit floating point registers. + bool IsFP64bit; + + // IsFP64bit - General-purpose registers are 64 bits wide + bool IsGP64bit; + + // HasVFPU - Processor has a vector floating point unit. + bool HasVFPU; + + // isLinux - Target system is Linux. Is false we consider ELFOS for now. + bool IsLinux; + + // UseSmallSection - Small section is used. + bool UseSmallSection; + + /// Features related to the presence of specific instructions. + + // HasSEInReg - SEB and SEH (signext in register) instructions. + bool HasSEInReg; + + // HasCondMov - Conditional mov (MOVZ, MOVN) instructions. + bool HasCondMov; + + // HasSwap - Byte and half swap instructions. + bool HasSwap; + + // HasBitCount - Count leading '1' and '0' bits. + bool HasBitCount; + + // HasFPIdx -- Floating point indexed load/store instructions. + bool HasFPIdx; + + // InMips16 -- can process Mips16 instructions + bool InMips16Mode; + + // Mips16 hard float + bool InMips16HardFloat; + + // PreviousInMips16 -- the function we just processed was in Mips 16 Mode + bool PreviousInMips16Mode; + + // InMicroMips -- can process MicroMips instructions + bool InMicroMipsMode; + + // HasDSP, HasDSPR2 -- supports DSP ASE. + bool HasDSP, HasDSPR2; + + // Allow mixed Mips16 and Mips32 in one source file + bool AllowMixed16_32; + + // Optimize for space by compiling all functions as Mips 16 unless + // it needs floating point. Functions needing floating point are + // compiled as Mips32 + bool Os16; + + // HasMSA -- supports MSA ASE. + bool HasMSA; + + InstrItineraryData InstrItins; + + // The instance to the register info section object + MipsReginfo MRI; + + // Relocation Model + Reloc::Model RM; + + // We can override the determination of whether we are in mips16 mode + // as from the command line + enum {NoOverride, Mips16Override, NoMips16Override} OverrideMode; + + MipsTargetMachine *TM; + +public: + virtual bool enablePostRAScheduler(CodeGenOpt::Level OptLevel, + AntiDepBreakMode& Mode, + RegClassVector& CriticalPathRCs) const; + + /// Only O32 and EABI supported right now. + bool isABI_EABI() const { return MipsABI == EABI; } + bool isABI_N64() const { return MipsABI == N64; } + bool isABI_N32() const { return MipsABI == N32; } + bool isABI_O32() const { return MipsABI == O32; } + unsigned getTargetABI() const { return MipsABI; } + + /// This constructor initializes the data members to match that + /// of the specified triple. + MipsSubtarget(const std::string &TT, const std::string &CPU, + const std::string &FS, bool little, Reloc::Model RM, + MipsTargetMachine *TM); + + /// ParseSubtargetFeatures - Parses features string setting specified + /// subtarget options. Definition of function is auto generated by tblgen. + void ParseSubtargetFeatures(StringRef CPU, StringRef FS); + + bool hasMips32() const { return MipsArchVersion >= Mips32; } + bool hasMips32r2() const { return MipsArchVersion == Mips32r2 || + MipsArchVersion == Mips64r2; } + bool hasMips64() const { return MipsArchVersion >= Mips64; } + bool hasMips64r2() const { return MipsArchVersion == Mips64r2; } + + bool isLittle() const { return IsLittle; } + bool isFP64bit() const { return IsFP64bit; } + bool isNotFP64bit() const { return !IsFP64bit; } + bool isGP64bit() const { return IsGP64bit; } + bool isGP32bit() const { return !IsGP64bit; } + bool isSingleFloat() const { return IsSingleFloat; } + bool isNotSingleFloat() const { return !IsSingleFloat; } + bool hasVFPU() const { return HasVFPU; } + bool inMips16Mode() const { + switch (OverrideMode) { + case NoOverride: + return InMips16Mode; + case Mips16Override: + return true; + case NoMips16Override: + return false; + } + llvm_unreachable("Unexpected mode"); + } + bool inMips16ModeDefault() const { + return InMips16Mode; + } + bool inMips16HardFloat() const { + return inMips16Mode() && InMips16HardFloat; + } + bool inMicroMipsMode() const { return InMicroMipsMode; } + bool hasDSP() const { return HasDSP; } + bool hasDSPR2() const { return HasDSPR2; } + bool hasMSA() const { return HasMSA; } + bool isLinux() const { return IsLinux; } + bool useSmallSection() const { return UseSmallSection; } + + bool hasStandardEncoding() const { return !inMips16Mode(); } + + bool mipsSEUsesSoftFloat() const; + + bool enableLongBranchPass() const { + return hasStandardEncoding() || allowMixed16_32(); + } + + /// Features related to the presence of specific instructions. + bool hasSEInReg() const { return HasSEInReg; } + bool hasCondMov() const { return HasCondMov; } + bool hasSwap() const { return HasSwap; } + bool hasBitCount() const { return HasBitCount; } + bool hasFPIdx() const { return HasFPIdx; } + bool hasExtractInsert() const { return !inMips16Mode() && hasMips32r2(); } + + const InstrItineraryData &getInstrItineraryData() const { return InstrItins; } + bool allowMixed16_32() const { return inMips16ModeDefault() | + AllowMixed16_32;} + + bool os16() const { return Os16;}; + +// for now constant islands are on for the whole compilation unit but we only +// really use them if in addition we are in mips16 mode +// +static bool useConstantIslands(); + + unsigned stackAlignment() const { return hasMips64() ? 16 : 8; } + + // Grab MipsRegInfo object + const MipsReginfo &getMReginfo() const { return MRI; } + + // Grab relocation model + Reloc::Model getRelocationModel() const {return RM;} + + /// \brief Reset the subtarget for the Mips target. + void resetSubtarget(MachineFunction *MF); + + +}; +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp new file mode 100644 index 000000000000..5046c1b782f6 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.cpp @@ -0,0 +1,220 @@ +//===-- MipsTargetMachine.cpp - Define TargetMachine for Mips -------------===// +// +// 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 Mips target spec. +// +//===----------------------------------------------------------------------===// + +#include "MipsTargetMachine.h" +#include "Mips.h" +#include "MipsFrameLowering.h" +#include "MipsInstrInfo.h" +#include "MipsModuleISelDAGToDAG.h" +#include "MipsOs16.h" +#include "MipsSEFrameLowering.h" +#include "MipsSEInstrInfo.h" +#include "MipsSEISelLowering.h" +#include "MipsSEISelDAGToDAG.h" +#include "Mips16FrameLowering.h" +#include "Mips16HardFloat.h" +#include "Mips16InstrInfo.h" +#include "Mips16ISelDAGToDAG.h" +#include "Mips16ISelLowering.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/PassManager.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Transforms/Scalar.h" +using namespace llvm; + + + +extern "C" void LLVMInitializeMipsTarget() { + // Register the target. + RegisterTargetMachine<MipsebTargetMachine> X(TheMipsTarget); + RegisterTargetMachine<MipselTargetMachine> Y(TheMipselTarget); + RegisterTargetMachine<MipsebTargetMachine> A(TheMips64Target); + RegisterTargetMachine<MipselTargetMachine> B(TheMips64elTarget); +} + +// 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. +// Using CodeModel::Large enables different CALL behavior. +MipsTargetMachine:: +MipsTargetMachine(const Target &T, StringRef TT, + StringRef CPU, StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL, + bool isLittle) + : LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL), + Subtarget(TT, CPU, FS, isLittle, RM, this), + DL(isLittle ? + (Subtarget.isABI_N64() ? + "e-p:64:64:64-i8:8:32-i16:16:32-i64:64:64-f128:128:128-" + "n32:64-S128" : + "e-p:32:32:32-i8:8:32-i16:16:32-i64:64:64-n32-S64") : + (Subtarget.isABI_N64() ? + "E-p:64:64:64-i8:8:32-i16:16:32-i64:64:64-f128:128:128-" + "n32:64-S128" : + "E-p:32:32:32-i8:8:32-i16:16:32-i64:64:64-n32-S64")), + InstrInfo(MipsInstrInfo::create(*this)), + FrameLowering(MipsFrameLowering::create(*this, Subtarget)), + TLInfo(MipsTargetLowering::create(*this)), TSInfo(*this), + InstrItins(Subtarget.getInstrItineraryData()), JITInfo() { + initAsmInfo(); +} + + +void MipsTargetMachine::setHelperClassesMips16() { + InstrInfoSE.swap(InstrInfo); + FrameLoweringSE.swap(FrameLowering); + TLInfoSE.swap(TLInfo); + if (!InstrInfo16) { + InstrInfo.reset(MipsInstrInfo::create(*this)); + FrameLowering.reset(MipsFrameLowering::create(*this, Subtarget)); + TLInfo.reset(MipsTargetLowering::create(*this)); + } else { + InstrInfo16.swap(InstrInfo); + FrameLowering16.swap(FrameLowering); + TLInfo16.swap(TLInfo); + } + assert(TLInfo && "null target lowering 16"); + assert(InstrInfo && "null instr info 16"); + assert(FrameLowering && "null frame lowering 16"); +} + +void MipsTargetMachine::setHelperClassesMipsSE() { + InstrInfo16.swap(InstrInfo); + FrameLowering16.swap(FrameLowering); + TLInfo16.swap(TLInfo); + if (!InstrInfoSE) { + InstrInfo.reset(MipsInstrInfo::create(*this)); + FrameLowering.reset(MipsFrameLowering::create(*this, Subtarget)); + TLInfo.reset(MipsTargetLowering::create(*this)); + } else { + InstrInfoSE.swap(InstrInfo); + FrameLoweringSE.swap(FrameLowering); + TLInfoSE.swap(TLInfo); + } + assert(TLInfo && "null target lowering in SE"); + assert(InstrInfo && "null instr info SE"); + assert(FrameLowering && "null frame lowering SE"); +} +void MipsebTargetMachine::anchor() { } + +MipsebTargetMachine:: +MipsebTargetMachine(const Target &T, StringRef TT, + StringRef CPU, StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL) + : MipsTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {} + +void MipselTargetMachine::anchor() { } + +MipselTargetMachine:: +MipselTargetMachine(const Target &T, StringRef TT, + StringRef CPU, StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL) + : MipsTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {} + +namespace { +/// Mips Code Generator Pass Configuration Options. +class MipsPassConfig : public TargetPassConfig { +public: + MipsPassConfig(MipsTargetMachine *TM, PassManagerBase &PM) + : TargetPassConfig(TM, PM) { + // The current implementation of long branch pass requires a scratch + // register ($at) to be available before branch instructions. Tail merging + // can break this requirement, so disable it when long branch pass is + // enabled. + EnableTailMerge = !getMipsSubtarget().enableLongBranchPass(); + } + + MipsTargetMachine &getMipsTargetMachine() const { + return getTM<MipsTargetMachine>(); + } + + const MipsSubtarget &getMipsSubtarget() const { + return *getMipsTargetMachine().getSubtargetImpl(); + } + + virtual void addIRPasses(); + virtual bool addInstSelector(); + virtual bool addPreEmitPass(); +}; +} // namespace + +TargetPassConfig *MipsTargetMachine::createPassConfig(PassManagerBase &PM) { + return new MipsPassConfig(this, PM); +} + +void MipsPassConfig::addIRPasses() { + TargetPassConfig::addIRPasses(); + if (getMipsSubtarget().os16()) + addPass(createMipsOs16(getMipsTargetMachine())); + if (getMipsSubtarget().inMips16HardFloat()) + addPass(createMips16HardFloat(getMipsTargetMachine())); + addPass(createPartiallyInlineLibCallsPass()); +} +// Install an instruction selector pass using +// the ISelDag to gen Mips code. +bool MipsPassConfig::addInstSelector() { + if (getMipsSubtarget().allowMixed16_32()) { + addPass(createMipsModuleISelDag(getMipsTargetMachine())); + addPass(createMips16ISelDag(getMipsTargetMachine())); + addPass(createMipsSEISelDag(getMipsTargetMachine())); + } else { + addPass(createMipsISelDag(getMipsTargetMachine())); + } + return false; +} + +void MipsTargetMachine::addAnalysisPasses(PassManagerBase &PM) { + if (Subtarget.allowMixed16_32()) { + DEBUG(errs() << "No "); + //FIXME: The Basic Target Transform Info + // pass needs to become a function pass instead of + // being an immutable pass and then this method as it exists now + // would be unnecessary. + PM.add(createNoTargetTransformInfoPass()); + } else + LLVMTargetMachine::addAnalysisPasses(PM); + DEBUG(errs() << "Target Transform Info Pass Added\n"); +} + +// 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 MipsPassConfig::addPreEmitPass() { + MipsTargetMachine &TM = getMipsTargetMachine(); + const MipsSubtarget &Subtarget = TM.getSubtarget<MipsSubtarget>(); + addPass(createMipsDelaySlotFillerPass(TM)); + + if (Subtarget.enableLongBranchPass()) + addPass(createMipsLongBranchPass(TM)); + if (Subtarget.inMips16Mode() || + Subtarget.allowMixed16_32()) + addPass(createMipsConstantIslandPass(TM)); + + return true; +} + +bool MipsTargetMachine::addCodeEmitter(PassManagerBase &PM, + JITCodeEmitter &JCE) { + // Machine code emitter pass for Mips. + PM.add(createMipsJITCodeEmitterPass(*this, JCE)); + return false; +} diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetMachine.h b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.h new file mode 100644 index 000000000000..5a9a11d861c0 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetMachine.h @@ -0,0 +1,125 @@ +//===-- MipsTargetMachine.h - Define TargetMachine for Mips -----*- 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 Mips specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSTARGETMACHINE_H +#define MIPSTARGETMACHINE_H + +#include "MipsFrameLowering.h" +#include "MipsISelLowering.h" +#include "MipsInstrInfo.h" +#include "MipsJITInfo.h" +#include "MipsSelectionDAGInfo.h" +#include "MipsSubtarget.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +class formatted_raw_ostream; +class MipsRegisterInfo; + +class MipsTargetMachine : public LLVMTargetMachine { + MipsSubtarget Subtarget; + const DataLayout DL; // Calculates type size & alignment + OwningPtr<const MipsInstrInfo> InstrInfo; + OwningPtr<const MipsFrameLowering> FrameLowering; + OwningPtr<const MipsTargetLowering> TLInfo; + OwningPtr<const MipsInstrInfo> InstrInfo16; + OwningPtr<const MipsFrameLowering> FrameLowering16; + OwningPtr<const MipsTargetLowering> TLInfo16; + OwningPtr<const MipsInstrInfo> InstrInfoSE; + OwningPtr<const MipsFrameLowering> FrameLoweringSE; + OwningPtr<const MipsTargetLowering> TLInfoSE; + MipsSelectionDAGInfo TSInfo; + const InstrItineraryData &InstrItins; + MipsJITInfo JITInfo; + +public: + MipsTargetMachine(const Target &T, StringRef TT, + StringRef CPU, StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL, + bool isLittle); + + virtual ~MipsTargetMachine() {} + + virtual void addAnalysisPasses(PassManagerBase &PM); + + virtual const MipsInstrInfo *getInstrInfo() const + { return InstrInfo.get(); } + virtual const TargetFrameLowering *getFrameLowering() const + { return FrameLowering.get(); } + virtual const MipsSubtarget *getSubtargetImpl() const + { return &Subtarget; } + virtual const DataLayout *getDataLayout() const + { return &DL;} + + virtual const InstrItineraryData *getInstrItineraryData() const { + return Subtarget.inMips16Mode() ? 0 : &InstrItins; + } + + virtual MipsJITInfo *getJITInfo() + { return &JITInfo; } + + virtual const MipsRegisterInfo *getRegisterInfo() const { + return &InstrInfo->getRegisterInfo(); + } + + virtual const MipsTargetLowering *getTargetLowering() const { + return TLInfo.get(); + } + + virtual const MipsSelectionDAGInfo* getSelectionDAGInfo() const { + return &TSInfo; + } + + // Pass Pipeline Configuration + virtual TargetPassConfig *createPassConfig(PassManagerBase &PM); + virtual bool addCodeEmitter(PassManagerBase &PM, JITCodeEmitter &JCE); + + // Set helper classes + void setHelperClassesMips16(); + + void setHelperClassesMipsSE(); + + +}; + +/// MipsebTargetMachine - Mips32/64 big endian target machine. +/// +class MipsebTargetMachine : public MipsTargetMachine { + virtual void anchor(); +public: + MipsebTargetMachine(const Target &T, StringRef TT, + StringRef CPU, StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL); +}; + +/// MipselTargetMachine - Mips32/64 little endian target machine. +/// +class MipselTargetMachine : public MipsTargetMachine { + virtual void anchor(); +public: + MipselTargetMachine(const Target &T, StringRef TT, + StringRef CPU, StringRef FS, const TargetOptions &Options, + Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL); +}; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp new file mode 100644 index 000000000000..4c748c5b57cd --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.cpp @@ -0,0 +1,118 @@ +//===-- MipsTargetObjectFile.cpp - Mips Object Files ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsTargetObjectFile.h" +#include "MipsSubtarget.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ELF.h" +#include "llvm/Target/TargetMachine.h" +using namespace llvm; + +static cl::opt<unsigned> +SSThreshold("mips-ssection-threshold", cl::Hidden, + cl::desc("Small data and bss section threshold size (default=8)"), + cl::init(8)); + +void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){ + TargetLoweringObjectFileELF::Initialize(Ctx, TM); + InitializeELF(TM.Options.UseInitArray); + + 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()); + + // Register info information + const MipsSubtarget &Subtarget = TM.getSubtarget<MipsSubtarget>(); + if (Subtarget.isABI_N64() || Subtarget.isABI_N32()) + ReginfoSection = + getContext().getELFSection(".MIPS.options", + ELF::SHT_MIPS_OPTIONS, + ELF::SHF_ALLOC |ELF::SHF_MIPS_NOSTRIP, + SectionKind::getMetadata()); + else + ReginfoSection = + getContext().getELFSection(".reginfo", + ELF::SHT_MIPS_REGINFO, + ELF::SHF_ALLOC, + SectionKind::getMetadata()); +} + +// 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 <= SSThreshold; +} + +bool MipsTargetObjectFile::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 MipsTargetObjectFile:: +IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM, + SectionKind Kind) const { + + const MipsSubtarget &Subtarget = TM.getSubtarget<MipsSubtarget>(); + + // Return if small section is not available. + if (!Subtarget.useSmallSection()) + return false; + + // 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.getDataLayout()->getTypeAllocSize(Ty)); +} + + + +const MCSection *MipsTargetObjectFile:: +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/Mips/MipsTargetObjectFile.h b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.h new file mode 100644 index 000000000000..c0e9140c829c --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetObjectFile.h @@ -0,0 +1,43 @@ +//===-- llvm/Target/MipsTargetObjectFile.h - Mips Object 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_MIPS_TARGETOBJECTFILE_H +#define LLVM_TARGET_MIPS_TARGETOBJECTFILE_H + +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" + +namespace llvm { + + class MipsTargetObjectFile : public TargetLoweringObjectFileELF { + const MCSection *SmallDataSection; + const MCSection *SmallBSSSection; + const MCSection *ReginfoSection; + 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; + + // TODO: Classify globals as mips wishes. + const MCSection *getReginfoSection() const { return ReginfoSection; } + }; +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Mips/MipsTargetStreamer.h b/contrib/llvm/lib/Target/Mips/MipsTargetStreamer.h new file mode 100644 index 000000000000..96966fd7cbc0 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/MipsTargetStreamer.h @@ -0,0 +1,44 @@ +//===-- MipsTargetStreamer.h - Mips Target Streamer ------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSTARGETSTREAMER_H +#define MIPSTARGETSTREAMER_H + +#include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCStreamer.h" + +namespace llvm { +class MipsTargetStreamer : public MCTargetStreamer { + virtual void anchor(); + +public: + virtual void emitMipsHackELFFlags(unsigned Flags) = 0; + virtual void emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val) = 0; +}; + +// This part is for ascii assembly output +class MipsTargetAsmStreamer : public MipsTargetStreamer { + formatted_raw_ostream &OS; + +public: + MipsTargetAsmStreamer(formatted_raw_ostream &OS); + virtual void emitMipsHackELFFlags(unsigned Flags); + virtual void emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val); +}; + +// This part is for ELF object output +class MipsTargetELFStreamer : public MipsTargetStreamer { +public: + MCELFStreamer &getStreamer(); + virtual void emitMipsHackELFFlags(unsigned Flags); + virtual void emitMipsHackSTOCG(MCSymbol *Sym, unsigned Val); +}; +} + +#endif diff --git a/contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp b/contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp new file mode 100644 index 000000000000..3615c146a527 --- /dev/null +++ b/contrib/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp @@ -0,0 +1,31 @@ +//===-- MipsTargetInfo.cpp - Mips Target Implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/TargetRegistry.h" +using namespace llvm; + +Target llvm::TheMipsTarget, llvm::TheMipselTarget; +Target llvm::TheMips64Target, llvm::TheMips64elTarget; + +extern "C" void LLVMInitializeMipsTargetInfo() { + RegisterTarget<Triple::mips, + /*HasJIT=*/true> X(TheMipsTarget, "mips", "Mips"); + + RegisterTarget<Triple::mipsel, + /*HasJIT=*/true> Y(TheMipselTarget, "mipsel", "Mipsel"); + + RegisterTarget<Triple::mips64, + /*HasJIT=*/false> A(TheMips64Target, "mips64", "Mips64 [experimental]"); + + RegisterTarget<Triple::mips64el, + /*HasJIT=*/false> B(TheMips64elTarget, + "mips64el", "Mips64el [experimental]"); +} |